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