video_source.h 6.41 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
2
3
4
5
6
7
8
9
10
11
/*
 *  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_VIDEO_SOURCE_H_
#define TEST_VIDEO_SOURCE_H_
Johann's avatar
Johann committed
12

13
#if defined(_WIN32)
14
#undef NOMINMAX
15
16
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
17
18
#include <windows.h>
#endif
19
20
21
#include <cstdio>
#include <cstdlib>
#include <string>
Johann's avatar
Johann committed
22
#include "test/acm_random.h"
John Koleszar's avatar
John Koleszar committed
23
24
25
26
#include "vpx/vpx_encoder.h"

namespace libvpx_test {

Adrian Grange's avatar
Adrian Grange committed
27
// Helper macros to ensure LIBAOM_TEST_DATA_PATH is a quoted string.
28
// These are undefined right below GetDataPath
Adrian Grange's avatar
Adrian Grange committed
29
// NOTE: LIBAOM_TEST_DATA_PATH MUST NOT be a quoted string before
30
31
32
// Stringification or the GetDataPath will fail at runtime
#define TO_STRING(S) #S
#define STRINGIFY(S) TO_STRING(S)
33

34
35
// A simple function to encapsulate cross platform retrieval of test data path
static std::string GetDataPath() {
Adrian Grange's avatar
Adrian Grange committed
36
  const char *const data_path = getenv("LIBAOM_TEST_DATA_PATH");
37
  if (data_path == NULL) {
Adrian Grange's avatar
Adrian Grange committed
38
#ifdef LIBAOM_TEST_DATA_PATH
39
40
41
    // In some environments, we cannot set environment variables
    // Instead, we set the data path by using a preprocessor symbol
    // which can be set from make files
Adrian Grange's avatar
Adrian Grange committed
42
    return STRINGIFY(LIBAOM_TEST_DATA_PATH);
43
44
45
#else
    return ".";
#endif
46
  }
47
48
  return data_path;
}
49

50
51
52
53
// Undefining stringification macros because they are not used elsewhere
#undef TO_STRING
#undef STRINGIFY

clang-format's avatar
clang-format committed
54
inline FILE *OpenTestDataFile(const std::string &file_name) {
55
  const std::string path_to_source = GetDataPath() + "/" + file_name;
56
57
58
  return fopen(path_to_source.c_str(), "rb");
}

59
60
static FILE *GetTempOutFile(std::string *file_name) {
  file_name->clear();
61
62
#if defined(_WIN32)
  char fname[MAX_PATH];
63
64
65
66
67
68
69
  char tmppath[MAX_PATH];
  if (GetTempPathA(MAX_PATH, tmppath)) {
    // Assume for now that the filename generated is unique per process
    if (GetTempFileNameA(tmppath, "lvx", 0, fname)) {
      file_name->assign(fname);
      return fopen(fname, "wb+");
    }
70
  }
71
  return NULL;
72
#else
73
  return tmpfile();
74
#endif
75
76
}

77
78
class TempOutFile {
 public:
clang-format's avatar
clang-format committed
79
  TempOutFile() { file_ = GetTempOutFile(&file_name_); }
80
81
82
  ~TempOutFile() {
    CloseFile();
    if (!file_name_.empty()) {
83
      EXPECT_EQ(0, remove(file_name_.c_str()));
84
85
    }
  }
clang-format's avatar
clang-format committed
86
87
  FILE *file() { return file_; }
  const std::string &file_name() { return file_name_; }
88
89

 protected:
90
91
  void CloseFile() {
    if (file_) {
92
      fclose(file_);
93
94
95
96
97
98
99
      file_ = NULL;
    }
  }
  FILE *file_;
  std::string file_name_;
};

John Koleszar's avatar
John Koleszar committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Abstract base class for test video sources, which provide a stream of
// vpx_image_t images with associated timestamps and duration.
class VideoSource {
 public:
  virtual ~VideoSource() {}

  // Prepare the stream for reading, rewind/open as necessary.
  virtual void Begin() = 0;

  // Advance the cursor to the next frame
  virtual void Next() = 0;

  // Get the current video frame, or NULL on End-Of-Stream.
  virtual vpx_image_t *img() const = 0;

  // Get the presentation timestamp of the current frame.
  virtual vpx_codec_pts_t pts() const = 0;

  // Get the current frame's duration
  virtual unsigned long duration() const = 0;

  // Get the timebase for the stream
  virtual vpx_rational_t timebase() const = 0;

  // Get the current frame counter, starting at 0.
  virtual unsigned int frame() const = 0;
126
127
128

  // Get the current file limit.
  virtual unsigned int limit() const = 0;
John Koleszar's avatar
John Koleszar committed
129
130
131
132
};

class DummyVideoSource : public VideoSource {
 public:
133
  DummyVideoSource()
clang-format's avatar
clang-format committed
134
      : img_(NULL), limit_(100), width_(80), height_(64),
135
136
        format_(VPX_IMG_FMT_I420) {
    ReallocImage();
John Koleszar's avatar
John Koleszar committed
137
  }
John Koleszar's avatar
John Koleszar committed
138
139
140
141
142
143
144
145
146
147
148
149
150

  virtual ~DummyVideoSource() { vpx_img_free(img_); }

  virtual void Begin() {
    frame_ = 0;
    FillFrame();
  }

  virtual void Next() {
    ++frame_;
    FillFrame();
  }

clang-format's avatar
clang-format committed
151
  virtual vpx_image_t *img() const { return (frame_ < limit_) ? img_ : NULL; }
John Koleszar's avatar
John Koleszar committed
152
153
154
155
156
157
158

  // Models a stream where Timebase = 1/FPS, so pts == frame.
  virtual vpx_codec_pts_t pts() const { return frame_; }

  virtual unsigned long duration() const { return 1; }

  virtual vpx_rational_t timebase() const {
clang-format's avatar
clang-format committed
159
    const vpx_rational_t t = { 1, 30 };
John Koleszar's avatar
John Koleszar committed
160
161
162
163
164
    return t;
  }

  virtual unsigned int frame() const { return frame_; }

165
166
  virtual unsigned int limit() const { return limit_; }

clang-format's avatar
clang-format committed
167
  void set_limit(unsigned int limit) { limit_ = limit; }
168

John Koleszar's avatar
John Koleszar committed
169
  void SetSize(unsigned int width, unsigned int height) {
John Koleszar's avatar
John Koleszar committed
170
171
172
    if (width != width_ || height != height_) {
      width_ = width;
      height_ = height;
173
174
175
176
177
178
179
180
      ReallocImage();
    }
  }

  void SetImageFormat(vpx_img_fmt_t format) {
    if (format_ != format) {
      format_ = format;
      ReallocImage();
John Koleszar's avatar
John Koleszar committed
181
    }
John Koleszar's avatar
John Koleszar committed
182
183
184
  }

 protected:
clang-format's avatar
clang-format committed
185
186
187
  virtual void FillFrame() {
    if (img_) memset(img_->img_data, 0, raw_sz_);
  }
John Koleszar's avatar
John Koleszar committed
188

189
190
191
192
193
194
  void ReallocImage() {
    vpx_img_free(img_);
    img_ = vpx_img_alloc(NULL, format_, width_, height_, 32);
    raw_sz_ = ((img_->w + 31) & ~31) * img_->h * img_->bps / 8;
  }

John Koleszar's avatar
John Koleszar committed
195
  vpx_image_t *img_;
clang-format's avatar
clang-format committed
196
  size_t raw_sz_;
John Koleszar's avatar
John Koleszar committed
197
198
  unsigned int limit_;
  unsigned int frame_;
John Koleszar's avatar
John Koleszar committed
199
200
  unsigned int width_;
  unsigned int height_;
201
  vpx_img_fmt_t format_;
John Koleszar's avatar
John Koleszar committed
202
203
204
};

class RandomVideoSource : public DummyVideoSource {
Johann's avatar
Johann committed
205
 public:
Johann's avatar
Johann committed
206
  RandomVideoSource(int seed = ACMRandom::DeterministicSeed())
clang-format's avatar
clang-format committed
207
      : rnd_(seed), seed_(seed) {}
Johann's avatar
Johann committed
208

John Koleszar's avatar
John Koleszar committed
209
 protected:
Johann's avatar
Johann committed
210
211
212
  // Reset the RNG to get a matching stream for the second pass
  virtual void Begin() {
    frame_ = 0;
Johann's avatar
Johann committed
213
    rnd_.Reset(seed_);
Johann's avatar
Johann committed
214
215
216
    FillFrame();
  }

John Koleszar's avatar
John Koleszar committed
217
218
219
  // 15 frames of noise, followed by 15 static frames. Reset to 0 rather
  // than holding previous frames to encourage keyframes to be thrown.
  virtual void FillFrame() {
220
221
    if (img_) {
      if (frame_ % 30 < 15)
clang-format's avatar
clang-format committed
222
        for (size_t i = 0; i < raw_sz_; ++i) img_->img_data[i] = rnd_.Rand8();
223
224
225
      else
        memset(img_->img_data, 0, raw_sz_);
    }
John Koleszar's avatar
John Koleszar committed
226
  }
Johann's avatar
Johann committed
227
228

  ACMRandom rnd_;
Johann's avatar
Johann committed
229
  int seed_;
John Koleszar's avatar
John Koleszar committed
230
231
};

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
// Abstract base class for test video sources, which provide a stream of
// decompressed images to the decoder.
class CompressedVideoSource {
 public:
  virtual ~CompressedVideoSource() {}

  virtual void Init() = 0;

  // Prepare the stream for reading, rewind/open as necessary.
  virtual void Begin() = 0;

  // Advance the cursor to the next frame
  virtual void Next() = 0;

  virtual const uint8_t *cxdata() const = 0;

Tom Finegan's avatar
Tom Finegan committed
248
  virtual size_t frame_size() const = 0;
249

Tom Finegan's avatar
Tom Finegan committed
250
  virtual unsigned int frame_number() const = 0;
251
252
};

John Koleszar's avatar
John Koleszar committed
253
254
255
}  // namespace libvpx_test

#endif  // TEST_VIDEO_SOURCE_H_