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 "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_)
94      nestegg_destroy(nestegg_ctx_);
95  }
96
97  virtual void Init() {
98  }
99
100  virtual void Begin() {
101    input_file_ = OpenTestDataFile(file_name_);
102    ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
103        << file_name_;
104
105    nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb,
106                     input_file_};
107    ASSERT_FALSE(nestegg_init(&nestegg_ctx_, io, NULL))
108        << "nestegg_init failed";
109
110    unsigned int n;
111    ASSERT_FALSE(nestegg_track_count(nestegg_ctx_, &n))
112        << "failed to get track count";
113
114    for (unsigned int i = 0; i < n; i++) {
115      int track_type = nestegg_track_type(nestegg_ctx_, i);
116      ASSERT_GE(track_type, 0) << "failed to get track type";
117
118      if (track_type == NESTEGG_TRACK_VIDEO) {
119        video_track_ = i;
120        break;
121      }
122    }
123
124    FillFrame();
125  }
126
127  virtual void Next() {
128    ++frame_;
129    FillFrame();
130  }
131
132  void FillFrame() {
133    ASSERT_TRUE(input_file_ != NULL);
134    if (chunk_ >= chunks_) {
135      unsigned int track;
136
137      do {
138        /* End of this packet, get another. */
139        if (pkt_)
140          nestegg_free_packet(pkt_);
141
142        int again = nestegg_read_packet(nestegg_ctx_, &pkt_);
143        ASSERT_GE(again, 0) << "nestegg_read_packet failed";
144        if (!again) {
145          end_of_file_ = true;
146          return;
147        }
148
149        ASSERT_FALSE(nestegg_packet_track(pkt_, &track))
150            << "nestegg_packet_track failed";
151      } while (track != video_track_);
152
153      ASSERT_FALSE(nestegg_packet_count(pkt_, &chunks_))
154          << "nestegg_packet_count failed";
155      chunk_ = 0;
156    }
157
158    ASSERT_FALSE(nestegg_packet_data(pkt_, chunk_, &buf_, &buf_sz_))
159        << "nestegg_packet_data failed";
160    chunk_++;
161  }
162
163  virtual const uint8_t *cxdata() const {
164    return end_of_file_ ? NULL : buf_;
165  }
166  virtual const unsigned int frame_size() const { return buf_sz_; }
167  virtual const unsigned int frame_number() const { return frame_; }
168
169 protected:
170  std::string file_name_;
171  FILE *input_file_;
172  nestegg *nestegg_ctx_;
173  nestegg_packet *pkt_;
174  unsigned int video_track_;
175  unsigned int chunk_;
176  unsigned int chunks_;
177  uint8_t *buf_;
178  size_t buf_sz_;
179  unsigned int frame_;
180  bool end_of_file_;
181};
182
183}  // namespace libvpx_test
184
185#endif  // TEST_WEBM_VIDEO_SOURCE_H_
186