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
20namespace libvpx_test {
21
22static int
23nestegg_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
36static int
37nestegg_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
54static int64_t
55nestegg_tell_cb(void *userdata) {
56  FILE *f = reinterpret_cast<FILE *>(userdata);
57  return ftell(f);
58}
59
60
61static void
62nestegg_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.
74class WebMVideoSource : public CompressedVideoSource {
75 public:
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
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
101  virtual void Init() {
102  }
103
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
131  virtual void Next() {
132    ++frame_;
133    FillFrame();
134  }
135
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
169  virtual const uint8_t *cxdata() const {
170    return end_of_file_ ? NULL : buf_;
171  }
172  virtual size_t frame_size() const { return buf_sz_; }
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