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 27namespace 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 37static 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 56inline 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 61static 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 79class 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. 104class 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 133class 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 206class 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. 237class 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