1 /*
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10 #ifndef TEST_WEBM_VIDEO_SOURCE_H_
11 #define TEST_WEBM_VIDEO_SOURCE_H_
12 #include <cstdarg>
13 #include <cstdio>
14 #include <cstdlib>
15 #include <new>
16 #include <string>
17 #include "third_party/nestegg/include/nestegg/nestegg.h"
18 #include "test/video_source.h"
19
20 namespace libvpx_test {
21
22 static int
nestegg_read_cb(void * buffer,size_t length,void * userdata)23 nestegg_read_cb(void *buffer, size_t length, void *userdata) {
24 FILE *f = reinterpret_cast<FILE *>(userdata);
25
26 if (fread(buffer, 1, length, f) < length) {
27 if (ferror(f))
28 return -1;
29 if (feof(f))
30 return 0;
31 }
32 return 1;
33 }
34
35
36 static int
nestegg_seek_cb(int64_t offset,int whence,void * userdata)37 nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
38 FILE *f = reinterpret_cast<FILE *>(userdata);
39 switch (whence) {
40 case NESTEGG_SEEK_SET:
41 whence = SEEK_SET;
42 break;
43 case NESTEGG_SEEK_CUR:
44 whence = SEEK_CUR;
45 break;
46 case NESTEGG_SEEK_END:
47 whence = SEEK_END;
48 break;
49 };
50 return fseek(f, (long)offset, whence) ? -1 : 0;
51 }
52
53
54 static int64_t
nestegg_tell_cb(void * userdata)55 nestegg_tell_cb(void *userdata) {
56 FILE *f = reinterpret_cast<FILE *>(userdata);
57 return ftell(f);
58 }
59
60
61 static void
nestegg_log_cb(nestegg * context,unsigned int severity,char const * format,...)62 nestegg_log_cb(nestegg *context, unsigned int severity, char const *format,
63 ...) {
64 va_list ap;
65
66 va_start(ap, format);
67 vfprintf(stderr, format, ap);
68 fprintf(stderr, "\n");
69 va_end(ap);
70 }
71
72 // This class extends VideoSource to allow parsing of WebM files,
73 // so that we can do actual file decodes.
74 class WebMVideoSource : public CompressedVideoSource {
75 public:
WebMVideoSource(const std::string & file_name)76 explicit WebMVideoSource(const std::string &file_name)
77 : file_name_(file_name),
78 input_file_(NULL),
79 nestegg_ctx_(NULL),
80 pkt_(NULL),
81 video_track_(0),
82 chunk_(0),
83 chunks_(0),
84 buf_(NULL),
85 buf_sz_(0),
86 frame_(0),
87 end_of_file_(false) {
88 }
89
~WebMVideoSource()90 virtual ~WebMVideoSource() {
91 if (input_file_)
92 fclose(input_file_);
93 if (nestegg_ctx_ != NULL) {
94 if (pkt_ != NULL) {
95 nestegg_free_packet(pkt_);
96 }
97 nestegg_destroy(nestegg_ctx_);
98 }
99 }
100
Init()101 virtual void Init() {
102 }
103
Begin()104 virtual void Begin() {
105 input_file_ = OpenTestDataFile(file_name_);
106 ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
107 << file_name_;
108
109 nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb,
110 input_file_};
111 ASSERT_FALSE(nestegg_init(&nestegg_ctx_, io, NULL, -1))
112 << "nestegg_init failed";
113
114 unsigned int n;
115 ASSERT_FALSE(nestegg_track_count(nestegg_ctx_, &n))
116 << "failed to get track count";
117
118 for (unsigned int i = 0; i < n; i++) {
119 int track_type = nestegg_track_type(nestegg_ctx_, i);
120 ASSERT_GE(track_type, 0) << "failed to get track type";
121
122 if (track_type == NESTEGG_TRACK_VIDEO) {
123 video_track_ = i;
124 break;
125 }
126 }
127
128 FillFrame();
129 }
130
Next()131 virtual void Next() {
132 ++frame_;
133 FillFrame();
134 }
135
FillFrame()136 void FillFrame() {
137 ASSERT_TRUE(input_file_ != NULL);
138 if (chunk_ >= chunks_) {
139 unsigned int track;
140
141 do {
142 /* End of this packet, get another. */
143 if (pkt_ != NULL) {
144 nestegg_free_packet(pkt_);
145 pkt_ = NULL;
146 }
147
148 int again = nestegg_read_packet(nestegg_ctx_, &pkt_);
149 ASSERT_GE(again, 0) << "nestegg_read_packet failed";
150 if (!again) {
151 end_of_file_ = true;
152 return;
153 }
154
155 ASSERT_FALSE(nestegg_packet_track(pkt_, &track))
156 << "nestegg_packet_track failed";
157 } while (track != video_track_);
158
159 ASSERT_FALSE(nestegg_packet_count(pkt_, &chunks_))
160 << "nestegg_packet_count failed";
161 chunk_ = 0;
162 }
163
164 ASSERT_FALSE(nestegg_packet_data(pkt_, chunk_, &buf_, &buf_sz_))
165 << "nestegg_packet_data failed";
166 chunk_++;
167 }
168
cxdata()169 virtual const uint8_t *cxdata() const {
170 return end_of_file_ ? NULL : buf_;
171 }
frame_size()172 virtual size_t frame_size() const { return buf_sz_; }
frame_number()173 virtual unsigned int frame_number() const { return frame_; }
174
175 protected:
176 std::string file_name_;
177 FILE *input_file_;
178 nestegg *nestegg_ctx_;
179 nestegg_packet *pkt_;
180 unsigned int video_track_;
181 unsigned int chunk_;
182 unsigned int chunks_;
183 uint8_t *buf_;
184 size_t buf_sz_;
185 unsigned int frame_;
186 bool end_of_file_;
187 };
188
189 } // namespace libvpx_test
190
191 #endif // TEST_WEBM_VIDEO_SOURCE_H_
192