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