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 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 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 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: 81 TempOutFile() { file_ = GetTempOutFile(&file_name_); } 82 ~TempOutFile() { 83 CloseFile(); 84 if (!file_name_.empty()) { 85 EXPECT_EQ(0, remove(file_name_.c_str())); 86 } 87 } 88 FILE *file() { return file_; } 89 const std::string &file_name() { return file_name_; } 90 91 protected: 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: 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: 135 DummyVideoSource() 136 : img_(NULL), limit_(100), width_(80), height_(64), 137 format_(VPX_IMG_FMT_I420) { 138 ReallocImage(); 139 } 140 141 virtual ~DummyVideoSource() { vpx_img_free(img_); } 142 143 virtual void Begin() { 144 frame_ = 0; 145 FillFrame(); 146 } 147 148 virtual void Next() { 149 ++frame_; 150 FillFrame(); 151 } 152 153 virtual vpx_image_t *img() const { return (frame_ < limit_) ? img_ : NULL; } 154 155 // Models a stream where Timebase = 1/FPS, so pts == frame. 156 virtual vpx_codec_pts_t pts() const { return frame_; } 157 158 virtual unsigned long duration() const { return 1; } 159 160 virtual vpx_rational_t timebase() const { 161 const vpx_rational_t t = { 1, 30 }; 162 return t; 163 } 164 165 virtual unsigned int frame() const { return frame_; } 166 167 virtual unsigned int limit() const { return limit_; } 168 169 void set_limit(unsigned int limit) { limit_ = limit; } 170 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 179 void SetImageFormat(vpx_img_fmt_t format) { 180 if (format_ != format) { 181 format_ = format; 182 ReallocImage(); 183 } 184 } 185 186 protected: 187 virtual void FillFrame() { 188 if (img_) memset(img_->img_data, 0, raw_sz_); 189 } 190 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()) 209 : rnd_(seed), seed_(seed) {} 210 211 protected: 212 // Reset the RNG to get a matching stream for the second pass 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. 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: 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