webm_video_source.h 4.58 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *  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>
James Zern's avatar
James Zern committed
17
#include "third_party/nestegg/include/nestegg/nestegg.h"
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#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_);
93 94 95 96
    if (nestegg_ctx_ != NULL) {
      if (pkt_ != NULL) {
        nestegg_free_packet(pkt_);
      }
97
      nestegg_destroy(nestegg_ctx_);
98
    }
99 100 101 102 103 104 105
  }

  virtual void Init() {
  }

  virtual void Begin() {
    input_file_ = OpenTestDataFile(file_name_);
106
    ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
107 108 109 110
        << file_name_;

    nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb,
                     input_file_};
James Zern's avatar
James Zern committed
111
    ASSERT_FALSE(nestegg_init(&nestegg_ctx_, io, NULL, -1))
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
        << "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() {
137
    ASSERT_TRUE(input_file_ != NULL);
138 139 140 141 142
    if (chunk_ >= chunks_) {
      unsigned int track;

      do {
        /* End of this packet, get another. */
143
        if (pkt_ != NULL) {
144
          nestegg_free_packet(pkt_);
145 146
          pkt_ = NULL;
        }
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171

        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_;
  }
172 173
  virtual size_t frame_size() const { return buf_sz_; }
  virtual unsigned int frame_number() const { return frame_; }
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

 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_