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_VIDEO_SOURCE_H_
11 #define TEST_VIDEO_SOURCE_H_
12
13 #if defined(_WIN32)
14 #undef NOMINMAX
15 #define NOMINMAX
16 #ifndef WIN32_LEAN_AND_MEAN
17 #define WIN32_LEAN_AND_MEAN
18 #endif
19 #include <windows.h>
20 #endif
21 #include <cstdio>
22 #include <cstdlib>
23 #include <string>
24 #include "test/acm_random.h"
25 #include "vpx/vpx_encoder.h"
26
27 namespace libvpx_test {
28
29 // Helper macros to ensure LIBVPX_TEST_DATA_PATH is a quoted string.
30 // These are undefined right below GetDataPath
31 // NOTE: LIBVPX_TEST_DATA_PATH MUST NOT be a quoted string before
32 // Stringification or the GetDataPath will fail at runtime
33 #define TO_STRING(S) #S
34 #define STRINGIFY(S) TO_STRING(S)
35
36 // A simple function to encapsulate cross platform retrieval of test data path
GetDataPath()37 static std::string GetDataPath() {
38 const char *const data_path = getenv("LIBVPX_TEST_DATA_PATH");
39 if (data_path == NULL) {
40 #ifdef LIBVPX_TEST_DATA_PATH
41 // In some environments, we cannot set environment variables
42 // Instead, we set the data path by using a preprocessor symbol
43 // which can be set from make files
44 return STRINGIFY(LIBVPX_TEST_DATA_PATH);
45 #else
46 return ".";
47 #endif
48 }
49 return data_path;
50 }
51
52 // Undefining stringification macros because they are not used elsewhere
53 #undef TO_STRING
54 #undef STRINGIFY
55
OpenTestDataFile(const std::string & file_name)56 inline FILE *OpenTestDataFile(const std::string &file_name) {
57 const std::string path_to_source = GetDataPath() + "/" + file_name;
58 return fopen(path_to_source.c_str(), "rb");
59 }
60
GetTempOutFile(std::string * file_name)61 static FILE *GetTempOutFile(std::string *file_name) {
62 file_name->clear();
63 #if defined(_WIN32)
64 char fname[MAX_PATH];
65 char tmppath[MAX_PATH];
66 if (GetTempPathA(MAX_PATH, tmppath)) {
67 // Assume for now that the filename generated is unique per process
68 if (GetTempFileNameA(tmppath, "lvx", 0, fname)) {
69 file_name->assign(fname);
70 return fopen(fname, "wb+");
71 }
72 }
73 return NULL;
74 #else
75 return tmpfile();
76 #endif
77 }
78
79 class TempOutFile {
80 public:
TempOutFile()81 TempOutFile() { file_ = GetTempOutFile(&file_name_); }
~TempOutFile()82 ~TempOutFile() {
83 CloseFile();
84 if (!file_name_.empty()) {
85 EXPECT_EQ(0, remove(file_name_.c_str()));
86 }
87 }
file()88 FILE *file() { return file_; }
file_name()89 const std::string &file_name() { return file_name_; }
90
91 protected:
CloseFile()92 void CloseFile() {
93 if (file_) {
94 fclose(file_);
95 file_ = NULL;
96 }
97 }
98 FILE *file_;
99 std::string file_name_;
100 };
101
102 // Abstract base class for test video sources, which provide a stream of
103 // vpx_image_t images with associated timestamps and duration.
104 class VideoSource {
105 public:
~VideoSource()106 virtual ~VideoSource() {}
107
108 // Prepare the stream for reading, rewind/open as necessary.
109 virtual void Begin() = 0;
110
111 // Advance the cursor to the next frame
112 virtual void Next() = 0;
113
114 // Get the current video frame, or NULL on End-Of-Stream.
115 virtual vpx_image_t *img() const = 0;
116
117 // Get the presentation timestamp of the current frame.
118 virtual vpx_codec_pts_t pts() const = 0;
119
120 // Get the current frame's duration
121 virtual unsigned long duration() const = 0;
122
123 // Get the timebase for the stream
124 virtual vpx_rational_t timebase() const = 0;
125
126 // Get the current frame counter, starting at 0.
127 virtual unsigned int frame() const = 0;
128
129 // Get the current file limit.
130 virtual unsigned int limit() const = 0;
131 };
132
133 class DummyVideoSource : public VideoSource {
134 public:
DummyVideoSource()135 DummyVideoSource()
136 : img_(NULL), limit_(100), width_(80), height_(64),
137 format_(VPX_IMG_FMT_I420) {
138 ReallocImage();
139 }
140
~DummyVideoSource()141 virtual ~DummyVideoSource() { vpx_img_free(img_); }
142
Begin()143 virtual void Begin() {
144 frame_ = 0;
145 FillFrame();
146 }
147
Next()148 virtual void Next() {
149 ++frame_;
150 FillFrame();
151 }
152
img()153 virtual vpx_image_t *img() const { return (frame_ < limit_) ? img_ : NULL; }
154
155 // Models a stream where Timebase = 1/FPS, so pts == frame.
pts()156 virtual vpx_codec_pts_t pts() const { return frame_; }
157
duration()158 virtual unsigned long duration() const { return 1; }
159
timebase()160 virtual vpx_rational_t timebase() const {
161 const vpx_rational_t t = { 1, 30 };
162 return t;
163 }
164
frame()165 virtual unsigned int frame() const { return frame_; }
166
limit()167 virtual unsigned int limit() const { return limit_; }
168
set_limit(unsigned int limit)169 void set_limit(unsigned int limit) { limit_ = limit; }
170
SetSize(unsigned int width,unsigned int height)171 void SetSize(unsigned int width, unsigned int height) {
172 if (width != width_ || height != height_) {
173 width_ = width;
174 height_ = height;
175 ReallocImage();
176 }
177 }
178
SetImageFormat(vpx_img_fmt_t format)179 void SetImageFormat(vpx_img_fmt_t format) {
180 if (format_ != format) {
181 format_ = format;
182 ReallocImage();
183 }
184 }
185
186 protected:
FillFrame()187 virtual void FillFrame() {
188 if (img_) memset(img_->img_data, 0, raw_sz_);
189 }
190
ReallocImage()191 void ReallocImage() {
192 vpx_img_free(img_);
193 img_ = vpx_img_alloc(NULL, format_, width_, height_, 32);
194 raw_sz_ = ((img_->w + 31) & ~31) * img_->h * img_->bps / 8;
195 }
196
197 vpx_image_t *img_;
198 size_t raw_sz_;
199 unsigned int limit_;
200 unsigned int frame_;
201 unsigned int width_;
202 unsigned int height_;
203 vpx_img_fmt_t format_;
204 };
205
206 class RandomVideoSource : public DummyVideoSource {
207 public:
208 RandomVideoSource(int seed = ACMRandom::DeterministicSeed())
rnd_(seed)209 : rnd_(seed), seed_(seed) {}
210
211 protected:
212 // Reset the RNG to get a matching stream for the second pass
Begin()213 virtual void Begin() {
214 frame_ = 0;
215 rnd_.Reset(seed_);
216 FillFrame();
217 }
218
219 // 15 frames of noise, followed by 15 static frames. Reset to 0 rather
220 // than holding previous frames to encourage keyframes to be thrown.
FillFrame()221 virtual void FillFrame() {
222 if (img_) {
223 if (frame_ % 30 < 15) {
224 for (size_t i = 0; i < raw_sz_; ++i) img_->img_data[i] = rnd_.Rand8();
225 } else {
226 memset(img_->img_data, 0, raw_sz_);
227 }
228 }
229 }
230
231 ACMRandom rnd_;
232 int seed_;
233 };
234
235 // Abstract base class for test video sources, which provide a stream of
236 // decompressed images to the decoder.
237 class CompressedVideoSource {
238 public:
~CompressedVideoSource()239 virtual ~CompressedVideoSource() {}
240
241 virtual void Init() = 0;
242
243 // Prepare the stream for reading, rewind/open as necessary.
244 virtual void Begin() = 0;
245
246 // Advance the cursor to the next frame
247 virtual void Next() = 0;
248
249 virtual const uint8_t *cxdata() const = 0;
250
251 virtual size_t frame_size() const = 0;
252
253 virtual unsigned int frame_number() const = 0;
254 };
255
256 } // namespace libvpx_test
257
258 #endif // TEST_VIDEO_SOURCE_H_
259