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