blob: f21cf98f907c319edad2fde10e297f9ed995b07e [file] [log] [blame]
/*
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef TEST_WEBM_VIDEO_SOURCE_H_
#define TEST_WEBM_VIDEO_SOURCE_H_
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <new>
#include <string>
#include "nestegg/include/nestegg/nestegg.h"
#include "test/video_source.h"
namespace libvpx_test {
static int
nestegg_read_cb(void *buffer, size_t length, void *userdata) {
FILE *f = reinterpret_cast<FILE *>(userdata);
if (fread(buffer, 1, length, f) < length) {
if (ferror(f))
return -1;
if (feof(f))
return 0;
}
return 1;
}
static int
nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
FILE *f = reinterpret_cast<FILE *>(userdata);
switch (whence) {
case NESTEGG_SEEK_SET:
whence = SEEK_SET;
break;
case NESTEGG_SEEK_CUR:
whence = SEEK_CUR;
break;
case NESTEGG_SEEK_END:
whence = SEEK_END;
break;
};
return fseek(f, (long)offset, whence) ? -1 : 0;
}
static int64_t
nestegg_tell_cb(void *userdata) {
FILE *f = reinterpret_cast<FILE *>(userdata);
return ftell(f);
}
static void
nestegg_log_cb(nestegg *context, unsigned int severity, char const *format,
...) {
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
}
// This class extends VideoSource to allow parsing of WebM files,
// so that we can do actual file decodes.
class WebMVideoSource : public CompressedVideoSource {
public:
explicit WebMVideoSource(const std::string &file_name)
: file_name_(file_name),
input_file_(NULL),
nestegg_ctx_(NULL),
pkt_(NULL),
video_track_(0),
chunk_(0),
chunks_(0),
buf_(NULL),
buf_sz_(0),
frame_(0),
end_of_file_(false) {
}
virtual ~WebMVideoSource() {
if (input_file_)
fclose(input_file_);
if (nestegg_ctx_ != NULL) {
if (pkt_ != NULL) {
nestegg_free_packet(pkt_);
}
nestegg_destroy(nestegg_ctx_);
}
}
virtual void Init() {
}
virtual void Begin() {
input_file_ = OpenTestDataFile(file_name_);
ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
<< file_name_;
nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb,
input_file_};
ASSERT_FALSE(nestegg_init(&nestegg_ctx_, io, NULL))
<< "nestegg_init failed";
unsigned int n;
ASSERT_FALSE(nestegg_track_count(nestegg_ctx_, &n))
<< "failed to get track count";
for (unsigned int i = 0; i < n; i++) {
int track_type = nestegg_track_type(nestegg_ctx_, i);
ASSERT_GE(track_type, 0) << "failed to get track type";
if (track_type == NESTEGG_TRACK_VIDEO) {
video_track_ = i;
break;
}
}
FillFrame();
}
virtual void Next() {
++frame_;
FillFrame();
}
void FillFrame() {
ASSERT_TRUE(input_file_ != NULL);
if (chunk_ >= chunks_) {
unsigned int track;
do {
/* End of this packet, get another. */
if (pkt_ != NULL) {
nestegg_free_packet(pkt_);
pkt_ = NULL;
}
int again = nestegg_read_packet(nestegg_ctx_, &pkt_);
ASSERT_GE(again, 0) << "nestegg_read_packet failed";
if (!again) {
end_of_file_ = true;
return;
}
ASSERT_FALSE(nestegg_packet_track(pkt_, &track))
<< "nestegg_packet_track failed";
} while (track != video_track_);
ASSERT_FALSE(nestegg_packet_count(pkt_, &chunks_))
<< "nestegg_packet_count failed";
chunk_ = 0;
}
ASSERT_FALSE(nestegg_packet_data(pkt_, chunk_, &buf_, &buf_sz_))
<< "nestegg_packet_data failed";
chunk_++;
}
virtual const uint8_t *cxdata() const {
return end_of_file_ ? NULL : buf_;
}
virtual size_t frame_size() const { return buf_sz_; }
virtual unsigned int frame_number() const { return frame_; }
protected:
std::string file_name_;
FILE *input_file_;
nestegg *nestegg_ctx_;
nestegg_packet *pkt_;
unsigned int video_track_;
unsigned int chunk_;
unsigned int chunks_;
uint8_t *buf_;
size_t buf_sz_;
unsigned int frame_;
bool end_of_file_;
};
} // namespace libvpx_test
#endif // TEST_WEBM_VIDEO_SOURCE_H_