resize_test.cc (46534B)
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 12 #include <climits> 13 #include <vector> 14 15 #include "aom/aomcx.h" 16 #include "aom_dsp/aom_dsp_common.h" 17 #include "av1/encoder/encoder.h" 18 #include "gtest/gtest.h" 19 #include "test/codec_factory.h" 20 #include "test/encode_test_driver.h" 21 #include "test/i420_video_source.h" 22 #include "test/util.h" 23 #include "test/video_source.h" 24 #include "test/y4m_video_source.h" 25 26 // Enable(1) or Disable(0) writing of the compressed bitstream. 27 #define WRITE_COMPRESSED_STREAM 0 28 29 namespace { 30 31 #if WRITE_COMPRESSED_STREAM 32 static void mem_put_le16(char *const mem, unsigned int val) { 33 mem[0] = val; 34 mem[1] = val >> 8; 35 } 36 37 static void mem_put_le32(char *const mem, unsigned int val) { 38 mem[0] = val; 39 mem[1] = val >> 8; 40 mem[2] = val >> 16; 41 mem[3] = val >> 24; 42 } 43 44 static void write_ivf_file_header(const aom_codec_enc_cfg_t *const cfg, 45 int frame_cnt, FILE *const outfile) { 46 char header[32]; 47 48 header[0] = 'D'; 49 header[1] = 'K'; 50 header[2] = 'I'; 51 header[3] = 'F'; 52 mem_put_le16(header + 4, 0); /* version */ 53 mem_put_le16(header + 6, 32); /* headersize */ 54 mem_put_le32(header + 8, AV1_FOURCC); /* fourcc (av1) */ 55 mem_put_le16(header + 12, cfg->g_w); /* width */ 56 mem_put_le16(header + 14, cfg->g_h); /* height */ 57 mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */ 58 mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */ 59 mem_put_le32(header + 24, frame_cnt); /* length */ 60 mem_put_le32(header + 28, 0); /* unused */ 61 62 (void)fwrite(header, 1, 32, outfile); 63 } 64 65 static void write_ivf_frame_size(FILE *const outfile, const size_t size) { 66 char header[4]; 67 mem_put_le32(header, static_cast<unsigned int>(size)); 68 (void)fwrite(header, 1, 4, outfile); 69 } 70 71 static void write_ivf_frame_header(const aom_codec_cx_pkt_t *const pkt, 72 FILE *const outfile) { 73 char header[12]; 74 aom_codec_pts_t pts; 75 76 if (pkt->kind != AOM_CODEC_CX_FRAME_PKT) return; 77 78 pts = pkt->data.frame.pts; 79 mem_put_le32(header, static_cast<unsigned int>(pkt->data.frame.sz)); 80 mem_put_le32(header + 4, pts & 0xFFFFFFFF); 81 mem_put_le32(header + 8, pts >> 32); 82 83 (void)fwrite(header, 1, 12, outfile); 84 } 85 #endif // WRITE_COMPRESSED_STREAM 86 87 const unsigned int kInitialWidth = 320; 88 const unsigned int kInitialHeight = 240; 89 90 struct FrameInfo { 91 FrameInfo(aom_codec_pts_t _pts, unsigned int _w, unsigned int _h) 92 : pts(_pts), w(_w), h(_h) {} 93 94 aom_codec_pts_t pts; 95 unsigned int w; 96 unsigned int h; 97 }; 98 99 void ScaleForFrameNumber(unsigned int frame, unsigned int initial_w, 100 unsigned int initial_h, int flag_codec, 101 bool change_start_resln, 102 bool random_input_one_half_only_, unsigned int *w, 103 unsigned int *h) { 104 if (random_input_one_half_only_) { 105 if (frame < 50) { 106 *w = initial_w; 107 *h = initial_h; 108 return; 109 } 110 *w = initial_w / 2; 111 *h = initial_h / 2; 112 return; 113 } 114 if (frame < 10) { 115 if (change_start_resln) { 116 *w = initial_w / 4; 117 *h = initial_h / 4; 118 } else { 119 *w = initial_w; 120 *h = initial_h; 121 } 122 return; 123 } 124 if (frame < 20) { 125 *w = initial_w * 3 / 4; 126 *h = initial_h * 3 / 4; 127 return; 128 } 129 if (frame < 30) { 130 *w = initial_w / 2; 131 *h = initial_h / 2; 132 return; 133 } 134 if (frame < 40) { 135 *w = initial_w; 136 *h = initial_h; 137 return; 138 } 139 if (frame < 50) { 140 *w = initial_w * 3 / 4; 141 *h = initial_h * 3 / 4; 142 return; 143 } 144 if (frame < 60) { 145 *w = initial_w / 2; 146 *h = initial_h / 2; 147 return; 148 } 149 if (frame < 70) { 150 *w = initial_w; 151 *h = initial_h; 152 return; 153 } 154 if (frame < 80) { 155 *w = initial_w * 3 / 4; 156 *h = initial_h * 3 / 4; 157 return; 158 } 159 if (frame < 90) { 160 *w = initial_w / 2; 161 *h = initial_h / 2; 162 return; 163 } 164 if (frame < 100) { 165 *w = initial_w * 3 / 4; 166 *h = initial_h * 3 / 4; 167 return; 168 } 169 if (frame < 110) { 170 *w = initial_w; 171 *h = initial_h; 172 return; 173 } 174 // Go down very low 175 if (frame < 120) { 176 *w = initial_w / 4; 177 *h = initial_h / 4; 178 return; 179 } 180 if (flag_codec == 1) { 181 // Cases that only works for AV1. 182 // For AV1: Swap width and height of original. 183 if (frame < 140) { 184 *w = initial_h; 185 *h = initial_w; 186 return; 187 } 188 } 189 *w = initial_w; 190 *h = initial_h; 191 } 192 193 class ResizingVideoSource : public ::libaom_test::DummyVideoSource { 194 public: 195 ResizingVideoSource(int width, int height) 196 : change_start_resln_(false), random_input_one_half_only_(false), 197 top_width_(width), top_height_(height) { 198 SetSize(top_width_, top_height_); 199 limit_ = 150; 200 } 201 int flag_codec_; 202 bool change_start_resln_; 203 bool random_input_one_half_only_; 204 // top_width_/height_ is the configured resolution when codec is created. 205 int top_width_; 206 int top_height_; 207 208 ~ResizingVideoSource() override = default; 209 210 protected: 211 void Begin() override { 212 frame_ = 0; 213 unsigned int width; 214 unsigned int height; 215 ScaleForFrameNumber(frame_, top_width_, top_height_, flag_codec_, 216 change_start_resln_, random_input_one_half_only_, 217 &width, &height); 218 SetSize(width, height); 219 FillFrame(); 220 } 221 222 void Next() override { 223 ++frame_; 224 unsigned int width; 225 unsigned int height; 226 ScaleForFrameNumber(frame_, top_width_, top_height_, flag_codec_, 227 change_start_resln_, random_input_one_half_only_, 228 &width, &height); 229 SetSize(width, height); 230 FillFrame(); 231 } 232 233 void FillFrame() override { 234 if (img_) { 235 memset(img_->img_data, 0, raw_sz_); 236 if (random_input_one_half_only_) { 237 libaom_test::ACMRandom rnd(libaom_test::ACMRandom::DeterministicSeed()); 238 unsigned char *image = img_->planes[0]; 239 for (size_t i = 0; i < raw_sz_; ++i) { 240 image[i] = rnd.Rand8(); 241 } 242 } 243 } 244 } 245 }; 246 247 class ResizeTest 248 : public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>, 249 public ::libaom_test::EncoderTest { 250 protected: 251 ResizeTest() : EncoderTest(GET_PARAM(0)) {} 252 253 ~ResizeTest() override = default; 254 255 void SetUp() override { InitializeConfig(GET_PARAM(1)); } 256 257 void PreEncodeFrameHook(libaom_test::VideoSource *video, 258 libaom_test::Encoder *encoder) override { 259 if (video->frame() == 0) { 260 if (GET_PARAM(1) == ::libaom_test::kRealTime) { 261 encoder->Control(AV1E_SET_AQ_MODE, 3); 262 encoder->Control(AOME_SET_CPUUSED, 5); 263 encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1); 264 } else if (GET_PARAM(1) == ::libaom_test::kOnePassGood) { 265 encoder->Control(AV1E_SET_AQ_MODE, 3); 266 encoder->Control(AOME_SET_CPUUSED, 4); 267 encoder->Control(AV1E_SET_ENABLE_GLOBAL_MOTION, 0); 268 encoder->Control(AV1E_SET_ENABLE_WARPED_MOTION, 0); 269 encoder->Control(AV1E_SET_ENABLE_RESTORATION, 0); 270 encoder->Control(AV1E_SET_ENABLE_OBMC, 0); 271 } 272 if (cfg_.g_threads > 0) { 273 encoder->Control(AV1E_SET_ROW_MT, 1); 274 encoder->Control(AV1E_SET_TILE_COLUMNS, cfg_.g_threads >> 1); 275 encoder->Control(AV1E_SET_TILE_ROWS, 0); 276 } 277 } 278 } 279 280 void DecompressedFrameHook(const aom_image_t &img, 281 aom_codec_pts_t pts) override { 282 frame_info_list_.push_back(FrameInfo(pts, img.d_w, img.d_h)); 283 } 284 285 std::vector<FrameInfo> frame_info_list_; 286 }; 287 288 TEST_P(ResizeTest, TestExternalResizeWorks) { 289 ResizingVideoSource video(kInitialWidth, kInitialHeight); 290 video.flag_codec_ = 0; 291 video.change_start_resln_ = false; 292 cfg_.g_lag_in_frames = 0; 293 // We use max(kInitialWidth, kInitialHeight) because during the test 294 // the width and height of the frame are swapped 295 cfg_.g_forced_max_frame_width = cfg_.g_forced_max_frame_height = 296 AOMMAX(kInitialWidth, kInitialHeight); 297 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 298 299 #if CONFIG_AV1_DECODER 300 // Check we decoded the same number of frames as we attempted to encode 301 ASSERT_EQ(frame_info_list_.size(), video.limit()); 302 303 for (const auto &info : frame_info_list_) { 304 const unsigned int frame = static_cast<unsigned>(info.pts); 305 unsigned int expected_w; 306 unsigned int expected_h; 307 ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, video.flag_codec_, 308 video.change_start_resln_, false, &expected_w, 309 &expected_h); 310 EXPECT_EQ(expected_w, info.w) 311 << "Frame " << frame << " had unexpected width"; 312 EXPECT_EQ(expected_h, info.h) 313 << "Frame " << frame << " had unexpected height"; 314 } 315 #endif 316 } 317 318 TEST_P(ResizeTest, TestExternalResizeWorks4Threads) { 319 ResizingVideoSource video(640, 480); 320 video.flag_codec_ = 0; 321 video.random_input_one_half_only_ = true; 322 cfg_.g_lag_in_frames = 0; 323 cfg_.g_forced_max_frame_width = 640; 324 cfg_.g_forced_max_frame_height = 480; 325 cfg_.g_threads = 4; 326 cfg_.kf_max_dist = 40; 327 cfg_.kf_min_dist = 40; 328 cfg_.rc_dropframe_thresh = 0; 329 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 330 331 #if CONFIG_AV1_DECODER 332 // Check we decoded the same number of frames as we attempted to encode 333 ASSERT_EQ(frame_info_list_.size(), video.limit()); 334 335 for (const auto &info : frame_info_list_) { 336 const unsigned int frame = static_cast<unsigned>(info.pts); 337 unsigned int expected_w; 338 unsigned int expected_h; 339 ScaleForFrameNumber(frame, 640, 480, video.flag_codec_, false, 340 video.random_input_one_half_only_, &expected_w, 341 &expected_h); 342 EXPECT_EQ(expected_w, info.w) 343 << "Frame " << frame << " had unexpected width"; 344 EXPECT_EQ(expected_h, info.h) 345 << "Frame " << frame << " had unexpected height"; 346 } 347 #endif 348 } 349 350 #if !CONFIG_REALTIME_ONLY 351 const unsigned int kStepDownFrame = 3; 352 const unsigned int kStepUpFrame = 6; 353 354 class ResizeInternalTestLarge : public ResizeTest { 355 protected: 356 #if WRITE_COMPRESSED_STREAM 357 ResizeInternalTestLarge() 358 : ResizeTest(), frame0_psnr_(0.0), outfile_(nullptr), out_frames_(0) {} 359 #else 360 ResizeInternalTestLarge() : ResizeTest(), frame0_psnr_(0.0) {} 361 #endif 362 363 ~ResizeInternalTestLarge() override = default; 364 365 void BeginPassHook(unsigned int /*pass*/) override { 366 #if WRITE_COMPRESSED_STREAM 367 outfile_ = fopen("av10-2-05-resize.ivf", "wb"); 368 #endif 369 } 370 371 void EndPassHook() override { 372 #if WRITE_COMPRESSED_STREAM 373 if (outfile_) { 374 if (!fseek(outfile_, 0, SEEK_SET)) 375 write_ivf_file_header(&cfg_, out_frames_, outfile_); 376 fclose(outfile_); 377 outfile_ = nullptr; 378 } 379 #endif 380 } 381 382 void PreEncodeFrameHook(libaom_test::VideoSource *video, 383 libaom_test::Encoder *encoder) override { 384 if (change_config_) { 385 int new_q = 60; 386 if (video->frame() == 0) { 387 struct aom_scaling_mode mode = { AOME_ONETWO, AOME_ONETWO }; 388 encoder->Control(AOME_SET_SCALEMODE, &mode); 389 } else if (video->frame() == 1) { 390 struct aom_scaling_mode mode = { AOME_NORMAL, AOME_NORMAL }; 391 encoder->Control(AOME_SET_SCALEMODE, &mode); 392 cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = new_q; 393 encoder->Config(&cfg_); 394 } 395 } else { 396 if (video->frame() >= kStepDownFrame && video->frame() < kStepUpFrame) { 397 struct aom_scaling_mode mode = { AOME_FOURFIVE, AOME_THREEFIVE }; 398 encoder->Control(AOME_SET_SCALEMODE, &mode); 399 } 400 if (video->frame() >= kStepUpFrame) { 401 struct aom_scaling_mode mode = { AOME_NORMAL, AOME_NORMAL }; 402 encoder->Control(AOME_SET_SCALEMODE, &mode); 403 } 404 } 405 } 406 407 void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) override { 408 if (frame0_psnr_ == 0.) frame0_psnr_ = pkt->data.psnr.psnr[0]; 409 EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 4.1); 410 } 411 412 #if WRITE_COMPRESSED_STREAM 413 void FramePktHook(const aom_codec_cx_pkt_t *pkt) override { 414 ++out_frames_; 415 416 // Write initial file header if first frame. 417 if (pkt->data.frame.pts == 0) write_ivf_file_header(&cfg_, 0, outfile_); 418 419 // Write frame header and data. 420 write_ivf_frame_header(pkt, outfile_); 421 (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_); 422 } 423 #endif 424 425 double frame0_psnr_; 426 bool change_config_; 427 #if WRITE_COMPRESSED_STREAM 428 FILE *outfile_; 429 unsigned int out_frames_; 430 #endif 431 }; 432 433 TEST_P(ResizeInternalTestLarge, TestInternalResizeWorks) { 434 ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, 435 30, 1, 0, 10); 436 init_flags_ = AOM_CODEC_USE_PSNR; 437 change_config_ = false; 438 439 // q picked such that initial keyframe on this clip is ~30dB PSNR 440 cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48; 441 442 // If the number of frames being encoded is smaller than g_lag_in_frames 443 // the encoded frame is unavailable using the current API. Comparing 444 // frames to detect mismatch would then not be possible. Set 445 // g_lag_in_frames = 0 to get around this. 446 cfg_.g_lag_in_frames = 0; 447 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 448 449 for (const auto &info : frame_info_list_) { 450 const aom_codec_pts_t pts = info.pts; 451 if (pts >= kStepDownFrame && pts < kStepUpFrame) { 452 ASSERT_EQ(282U, info.w) << "Frame " << pts << " had unexpected width"; 453 ASSERT_EQ(173U, info.h) << "Frame " << pts << " had unexpected height"; 454 } else { 455 EXPECT_EQ(352U, info.w) << "Frame " << pts << " had unexpected width"; 456 EXPECT_EQ(288U, info.h) << "Frame " << pts << " had unexpected height"; 457 } 458 } 459 } 460 461 TEST_P(ResizeInternalTestLarge, TestInternalResizeChangeConfig) { 462 ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, 463 30, 1, 0, 10); 464 cfg_.g_w = 352; 465 cfg_.g_h = 288; 466 change_config_ = true; 467 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 468 } 469 470 AV1_INSTANTIATE_TEST_SUITE(ResizeInternalTestLarge, 471 ::testing::Values(::libaom_test::kOnePassGood)); 472 #endif 473 474 // Parameters: test mode, speed, threads 475 class ResizeRealtimeTest 476 : public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode, int, 477 int>, 478 public ::libaom_test::EncoderTest { 479 protected: 480 ResizeRealtimeTest() 481 : EncoderTest(GET_PARAM(0)), num_threads_(GET_PARAM(3)), 482 set_scale_mode_(false), set_scale_mode2_(false), 483 set_scale_mode3_(false), is_screen_(false) {} 484 ~ResizeRealtimeTest() override = default; 485 486 void PreEncodeFrameHook(libaom_test::VideoSource *video, 487 libaom_test::Encoder *encoder) override { 488 if (video->frame() == 0) { 489 encoder->Control(AV1E_SET_AQ_MODE, 3); 490 encoder->Control(AV1E_SET_ALLOW_WARPED_MOTION, 0); 491 encoder->Control(AV1E_SET_ENABLE_GLOBAL_MOTION, 0); 492 encoder->Control(AV1E_SET_ENABLE_OBMC, 0); 493 encoder->Control(AOME_SET_CPUUSED, set_cpu_used_); 494 encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1); 495 if (cfg_.g_threads > 0) { 496 encoder->Control(AV1E_SET_ROW_MT, 1); 497 encoder->Control(AV1E_SET_TILE_COLUMNS, cfg_.g_threads >> 1); 498 encoder->Control(AV1E_SET_TILE_ROWS, 0); 499 } 500 if (is_screen_) 501 encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN); 502 } 503 if (set_scale_mode_) { 504 struct aom_scaling_mode mode; 505 if (video->frame() <= 20) 506 mode = { AOME_ONETWO, AOME_ONETWO }; 507 else if (video->frame() <= 40) 508 mode = { AOME_ONEFOUR, AOME_ONEFOUR }; 509 else if (video->frame() > 40) 510 mode = { AOME_NORMAL, AOME_NORMAL }; 511 encoder->Control(AOME_SET_SCALEMODE, &mode); 512 } else if (set_scale_mode2_) { 513 struct aom_scaling_mode mode; 514 if (video->frame() <= 20) 515 mode = { AOME_ONEFOUR, AOME_ONEFOUR }; 516 else if (video->frame() <= 40) 517 mode = { AOME_ONETWO, AOME_ONETWO }; 518 else if (video->frame() > 40) 519 mode = { AOME_THREEFOUR, AOME_THREEFOUR }; 520 encoder->Control(AOME_SET_SCALEMODE, &mode); 521 } else if (set_scale_mode3_) { 522 struct aom_scaling_mode mode; 523 if (video->frame() <= 30) 524 mode = { AOME_ONETWO, AOME_NORMAL }; 525 else 526 mode = { AOME_NORMAL, AOME_NORMAL }; 527 encoder->Control(AOME_SET_SCALEMODE, &mode); 528 } 529 530 if (change_bitrate_ && video->frame() == frame_change_bitrate_) { 531 change_bitrate_ = false; 532 cfg_.rc_target_bitrate = 500; 533 encoder->Config(&cfg_); 534 } 535 } 536 537 void SetUp() override { 538 InitializeConfig(GET_PARAM(1)); 539 set_cpu_used_ = GET_PARAM(2); 540 } 541 542 void DecompressedFrameHook(const aom_image_t &img, 543 aom_codec_pts_t pts) override { 544 frame_info_list_.push_back(FrameInfo(pts, img.d_w, img.d_h)); 545 } 546 547 void MismatchHook(const aom_image_t *img1, const aom_image_t *img2) override { 548 double mismatch_psnr = compute_psnr(img1, img2); 549 mismatch_psnr_ += mismatch_psnr; 550 ++mismatch_nframes_; 551 } 552 553 unsigned int GetMismatchFrames() { return mismatch_nframes_; } 554 555 void DefaultConfig() { 556 cfg_.rc_buf_initial_sz = 500; 557 cfg_.rc_buf_optimal_sz = 600; 558 cfg_.rc_buf_sz = 1000; 559 cfg_.rc_min_quantizer = 2; 560 cfg_.rc_max_quantizer = 56; 561 cfg_.rc_undershoot_pct = 50; 562 cfg_.rc_overshoot_pct = 50; 563 cfg_.rc_end_usage = AOM_CBR; 564 cfg_.kf_mode = AOM_KF_AUTO; 565 cfg_.g_lag_in_frames = 0; 566 cfg_.kf_min_dist = cfg_.kf_max_dist = 3000; 567 // Enable dropped frames. 568 cfg_.rc_dropframe_thresh = 1; 569 // Disable error_resilience mode. 570 cfg_.g_error_resilient = 0; 571 cfg_.g_threads = num_threads_; 572 // Run at low bitrate. 573 cfg_.rc_target_bitrate = 200; 574 // We use max(kInitialWidth, kInitialHeight) because during the test 575 // the width and height of the frame are swapped 576 cfg_.g_forced_max_frame_width = cfg_.g_forced_max_frame_height = 577 AOMMAX(kInitialWidth, kInitialHeight); 578 if (set_scale_mode_ || set_scale_mode2_ || set_scale_mode3_) { 579 cfg_.rc_dropframe_thresh = 0; 580 cfg_.g_forced_max_frame_width = 1280; 581 cfg_.g_forced_max_frame_height = 1280; 582 } 583 } 584 585 std::vector<FrameInfo> frame_info_list_; 586 int set_cpu_used_; 587 int num_threads_; 588 bool change_bitrate_; 589 unsigned int frame_change_bitrate_; 590 double mismatch_psnr_; 591 int mismatch_nframes_; 592 bool set_scale_mode_; 593 bool set_scale_mode2_; 594 bool set_scale_mode3_; 595 bool is_screen_; 596 }; 597 598 // Check the AOME_SET_SCALEMODE control by downsizing to 599 // 1/2, then 1/4, and then back up to originsal. 600 TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode1) { 601 ::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); 602 cfg_.g_w = 1280; 603 cfg_.g_h = 720; 604 set_scale_mode_ = true; 605 set_scale_mode2_ = false; 606 set_scale_mode3_ = false; 607 DefaultConfig(); 608 change_bitrate_ = false; 609 mismatch_nframes_ = 0; 610 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 611 #if CONFIG_AV1_DECODER 612 // Check we decoded the same number of frames as we attempted to encode 613 ASSERT_EQ(frame_info_list_.size(), video.limit()); 614 for (const auto &info : frame_info_list_) { 615 const auto frame = static_cast<unsigned>(info.pts); 616 unsigned int expected_w = 1280 >> 1; 617 unsigned int expected_h = 720 >> 1; 618 if (frame > 40) { 619 expected_w = 1280; 620 expected_h = 720; 621 } else if (frame > 20 && frame <= 40) { 622 expected_w = 1280 >> 2; 623 expected_h = 720 >> 2; 624 } 625 EXPECT_EQ(expected_w, info.w) 626 << "Frame " << frame << " had unexpected width"; 627 EXPECT_EQ(expected_h, info.h) 628 << "Frame " << frame << " had unexpected height"; 629 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 630 } 631 #else 632 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 633 #endif 634 } 635 636 // Check the AOME_SET_SCALEMODE control by downsizing to 637 // 1/2, then 1/4, and then back up to originsal. 638 TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode1QVGA) { 639 ::libaom_test::I420VideoSource video("desktop1.320_180.yuv", 320, 180, 30, 1, 640 0, 80); 641 cfg_.g_w = 320; 642 cfg_.g_h = 180; 643 set_scale_mode_ = true; 644 set_scale_mode2_ = false; 645 set_scale_mode3_ = false; 646 DefaultConfig(); 647 change_bitrate_ = false; 648 mismatch_nframes_ = 0; 649 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 650 #if CONFIG_AV1_DECODER 651 // Check we decoded the same number of frames as we attempted to encode 652 ASSERT_EQ(frame_info_list_.size(), video.limit()); 653 for (const auto &info : frame_info_list_) { 654 const auto frame = static_cast<unsigned>(info.pts); 655 unsigned int expected_w = 320 >> 1; 656 unsigned int expected_h = 180 >> 1; 657 if (frame > 40) { 658 expected_w = 320; 659 expected_h = 180; 660 } else if (frame > 20 && frame <= 40) { 661 expected_w = 320 >> 2; 662 expected_h = 180 >> 2; 663 } 664 EXPECT_EQ(expected_w, info.w) 665 << "Frame " << frame << " had unexpected width"; 666 EXPECT_EQ(expected_h, info.h) 667 << "Frame " << frame << " had unexpected height"; 668 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 669 } 670 #else 671 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 672 #endif 673 } 674 675 // Check the AOME_SET_SCALEMODE control by downsizing to 676 // 1/4, then 1/2, and then up to 3/4. 677 TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode2) { 678 ::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); 679 cfg_.g_w = 1280; 680 cfg_.g_h = 720; 681 set_scale_mode_ = false; 682 set_scale_mode2_ = true; 683 set_scale_mode3_ = false; 684 DefaultConfig(); 685 change_bitrate_ = false; 686 mismatch_nframes_ = 0; 687 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 688 #if CONFIG_AV1_DECODER 689 // Check we decoded the same number of frames as we attempted to encode 690 ASSERT_EQ(frame_info_list_.size(), video.limit()); 691 for (const auto &info : frame_info_list_) { 692 const auto frame = static_cast<unsigned>(info.pts); 693 unsigned int expected_w = 1280 >> 2; 694 unsigned int expected_h = 720 >> 2; 695 if (frame > 40) { 696 expected_w = (3 * 1280) >> 2; 697 expected_h = (3 * 720) >> 2; 698 } else if (frame > 20 && frame <= 40) { 699 expected_w = 1280 >> 1; 700 expected_h = 720 >> 1; 701 } 702 EXPECT_EQ(expected_w, info.w) 703 << "Frame " << frame << " had unexpected width"; 704 EXPECT_EQ(expected_h, info.h) 705 << "Frame " << frame << " had unexpected height"; 706 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 707 } 708 #else 709 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 710 #endif 711 } 712 713 // Check the AOME_SET_SCALEMODE control by downsizing to 714 // 1/2 horizontally only and then back up to original. 715 TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode3) { 716 ::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60); 717 cfg_.g_w = 1280; 718 cfg_.g_h = 720; 719 set_scale_mode_ = false; 720 set_scale_mode2_ = false; 721 set_scale_mode3_ = true; 722 DefaultConfig(); 723 change_bitrate_ = false; 724 mismatch_nframes_ = 0; 725 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 726 #if CONFIG_AV1_DECODER 727 // Check we decoded the same number of frames as we attempted to encode 728 ASSERT_EQ(frame_info_list_.size(), video.limit()); 729 for (const auto &info : frame_info_list_) { 730 const auto frame = static_cast<unsigned>(info.pts); 731 unsigned int expected_w = 640; 732 unsigned int expected_h = 720; 733 if (frame > 30) { 734 expected_w = 1280; 735 expected_h = 720; 736 } 737 EXPECT_EQ(expected_w, info.w) 738 << "Frame " << frame << " had unexpected width"; 739 EXPECT_EQ(expected_h, info.h) 740 << "Frame " << frame << " had unexpected height"; 741 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 742 } 743 #else 744 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 745 #endif 746 } 747 748 TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) { 749 ResizingVideoSource video(kInitialWidth, kInitialHeight); 750 video.flag_codec_ = 1; 751 change_bitrate_ = false; 752 set_scale_mode_ = false; 753 set_scale_mode2_ = false; 754 set_scale_mode3_ = false; 755 mismatch_psnr_ = 0.0; 756 mismatch_nframes_ = 0; 757 DefaultConfig(); 758 // Test external resizing with start resolution equal to 759 // 1. kInitialWidth and kInitialHeight 760 // 2. down-scaled kInitialWidth and kInitialHeight 761 for (int i = 0; i < 2; i++) { 762 video.change_start_resln_ = static_cast<bool>(i); 763 764 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 765 #if CONFIG_AV1_DECODER 766 // Check we decoded the same number of frames as we attempted to encode 767 ASSERT_EQ(frame_info_list_.size(), video.limit()); 768 for (const auto &info : frame_info_list_) { 769 const unsigned int frame = static_cast<unsigned>(info.pts); 770 unsigned int expected_w; 771 unsigned int expected_h; 772 ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, 773 video.flag_codec_, video.change_start_resln_, false, 774 &expected_w, &expected_h); 775 EXPECT_EQ(expected_w, info.w) 776 << "Frame " << frame << " had unexpected width"; 777 EXPECT_EQ(expected_h, info.h) 778 << "Frame " << frame << " had unexpected height"; 779 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 780 } 781 #else 782 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 783 #endif 784 frame_info_list_.clear(); 785 } 786 } 787 788 // This tests uses 4 threads with small keyframe spacing, random input, 789 // and uses 640x480 as initial resolution. 790 TEST_P(ResizeRealtimeTest, TestExternalResizeWorks4Threads) { 791 ResizingVideoSource video(640, 480); 792 video.flag_codec_ = true; 793 video.random_input_one_half_only_ = true; 794 change_bitrate_ = false; 795 set_scale_mode_ = false; 796 set_scale_mode2_ = false; 797 set_scale_mode3_ = false; 798 mismatch_psnr_ = 0.0; 799 mismatch_nframes_ = 0; 800 DefaultConfig(); 801 cfg_.g_forced_max_frame_width = 640; 802 cfg_.g_forced_max_frame_height = 480; 803 cfg_.g_threads = 4; 804 cfg_.kf_max_dist = 40; 805 cfg_.kf_min_dist = 40; 806 cfg_.rc_dropframe_thresh = 0; 807 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 808 809 for (const auto &info : frame_info_list_) { 810 const unsigned int frame = static_cast<unsigned>(info.pts); 811 unsigned int expected_w; 812 unsigned int expected_h; 813 ScaleForFrameNumber(frame, 640, 480, video.flag_codec_, false, 814 video.random_input_one_half_only_, &expected_w, 815 &expected_h); 816 EXPECT_EQ(expected_w, info.w) 817 << "Frame " << frame << " had unexpected width"; 818 EXPECT_EQ(expected_h, info.h) 819 << "Frame " << frame << " had unexpected height"; 820 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 821 } 822 } 823 824 TEST_P(ResizeRealtimeTest, TestExternalResizeWorksUsePSNR) { 825 ResizingVideoSource video(kInitialWidth, kInitialHeight); 826 video.flag_codec_ = 1; 827 change_bitrate_ = false; 828 set_scale_mode_ = false; 829 set_scale_mode2_ = false; 830 set_scale_mode3_ = false; 831 mismatch_psnr_ = 0.0; 832 mismatch_nframes_ = 0; 833 init_flags_ = AOM_CODEC_USE_PSNR; 834 cfg_.rc_dropframe_thresh = 30; 835 DefaultConfig(); 836 // Test external resizing with start resolution equal to 837 // 1. kInitialWidth and kInitialHeight 838 // 2. down-scaled kInitialWidth and kInitialHeight 839 for (int i = 0; i < 2; i++) { 840 video.change_start_resln_ = static_cast<bool>(i); 841 842 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 843 #if CONFIG_AV1_DECODER 844 // Check we decoded the same number of frames as we attempted to encode 845 ASSERT_EQ(frame_info_list_.size(), video.limit()); 846 for (const auto &info : frame_info_list_) { 847 const unsigned int frame = static_cast<unsigned>(info.pts); 848 unsigned int expected_w; 849 unsigned int expected_h; 850 ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, 851 video.flag_codec_, video.change_start_resln_, false, 852 &expected_w, &expected_h); 853 EXPECT_EQ(expected_w, info.w) 854 << "Frame " << frame << " had unexpected width"; 855 EXPECT_EQ(expected_h, info.h) 856 << "Frame " << frame << " had unexpected height"; 857 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 858 } 859 #else 860 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 861 #endif 862 frame_info_list_.clear(); 863 } 864 } 865 866 // Verify the dynamic resizer behavior for real time, 1 pass CBR mode. 867 // Run at low bitrate, with resize_allowed = 1, and verify that we get 868 // one resize down event. 869 TEST_P(ResizeRealtimeTest, TestInternalResizeDown) { 870 ::libaom_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, 871 0, 400); 872 cfg_.g_w = 640; 873 cfg_.g_h = 480; 874 change_bitrate_ = false; 875 set_scale_mode_ = false; 876 set_scale_mode2_ = false; 877 set_scale_mode3_ = false; 878 mismatch_psnr_ = 0.0; 879 mismatch_nframes_ = 0; 880 DefaultConfig(); 881 // Disable dropped frames. 882 cfg_.rc_dropframe_thresh = 0; 883 // Starting bitrate low. 884 cfg_.rc_target_bitrate = 150; 885 cfg_.rc_resize_mode = RESIZE_DYNAMIC; 886 cfg_.g_forced_max_frame_width = 1280; 887 cfg_.g_forced_max_frame_height = 1280; 888 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 889 890 #if CONFIG_AV1_DECODER 891 unsigned int last_w = cfg_.g_w; 892 unsigned int last_h = cfg_.g_h; 893 int resize_down_count = 0; 894 for (const auto &info : frame_info_list_) { 895 if (info.w != last_w || info.h != last_h) { 896 // Verify that resize down occurs. 897 if (info.w < last_w && info.h < last_h) { 898 resize_down_count++; 899 } 900 last_w = info.w; 901 last_h = info.h; 902 } 903 } 904 905 // Verify that we get at lease 1 resize down event in this test. 906 ASSERT_GE(resize_down_count, 1) << "Resizing should occur."; 907 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 908 #else 909 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 910 #endif 911 } 912 913 // Verify the dynamic resizer behavior for real time, 1 pass CBR mode. 914 // Start at low target bitrate, raise the bitrate in the middle of the clip 915 // (at frame# = frame_change_bitrate_), scaling-up should occur after bitrate 916 // is increased. 917 TEST_P(ResizeRealtimeTest, TestInternalResizeDownUpChangeBitRate) { 918 ::libaom_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, 919 0, 400); 920 init_flags_ = AOM_CODEC_USE_PSNR; 921 cfg_.g_w = 640; 922 cfg_.g_h = 480; 923 change_bitrate_ = true; 924 frame_change_bitrate_ = 120; 925 set_scale_mode_ = false; 926 set_scale_mode2_ = false; 927 set_scale_mode3_ = false; 928 mismatch_psnr_ = 0.0; 929 mismatch_nframes_ = 0; 930 DefaultConfig(); 931 // Disable dropped frames. 932 cfg_.rc_dropframe_thresh = 0; 933 // Starting bitrate low. 934 cfg_.rc_target_bitrate = 150; 935 cfg_.rc_resize_mode = RESIZE_DYNAMIC; 936 cfg_.g_forced_max_frame_width = 1280; 937 cfg_.g_forced_max_frame_height = 1280; 938 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 939 940 #if CONFIG_AV1_DECODER 941 unsigned int last_w = cfg_.g_w; 942 unsigned int last_h = cfg_.g_h; 943 unsigned int frame_number = 0; 944 int resize_down_count = 0; 945 int resize_up_count = 0; 946 for (const auto &info : frame_info_list_) { 947 if (info.w != last_w || info.h != last_h) { 948 if (frame_number < frame_change_bitrate_) { 949 // Verify that resize down occurs, before bitrate is increased. 950 ASSERT_LT(info.w, last_w); 951 ASSERT_LT(info.h, last_h); 952 resize_down_count++; 953 } else { 954 // Verify that resize up occurs, after bitrate is increased. 955 ASSERT_GT(info.w, last_w); 956 ASSERT_GT(info.h, last_h); 957 resize_up_count++; 958 } 959 last_w = info.w; 960 last_h = info.h; 961 } 962 frame_number++; 963 } 964 965 // Verify that we get at least 2 resize events in this test. 966 ASSERT_GE(resize_up_count, 1) << "Resizing up should occur at lease once."; 967 ASSERT_GE(resize_down_count, 1) 968 << "Resizing down should occur at lease once."; 969 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 970 #else 971 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 972 #endif 973 } 974 975 // Verify the dynamic resizer behavior for real time, 1 pass CBR mode for 976 // screen content mode. Start at low target bitrate, raise the bitrate in the 977 // middle of the clip (at frame# = frame_change_bitrate_), scaling-up should 978 // occur after bitrate is increased. 979 TEST_P(ResizeRealtimeTest, TestInternalResizeDownUpChangeBitRateScreen) { 980 ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, 981 30, 1, 0, 300); 982 init_flags_ = AOM_CODEC_USE_PSNR; 983 cfg_.g_w = 352; 984 cfg_.g_h = 288; 985 change_bitrate_ = true; 986 frame_change_bitrate_ = 200; 987 set_scale_mode_ = false; 988 set_scale_mode2_ = false; 989 set_scale_mode3_ = false; 990 mismatch_psnr_ = 0.0; 991 mismatch_nframes_ = 0; 992 is_screen_ = true; 993 DefaultConfig(); 994 // Disable dropped frames. 995 cfg_.rc_dropframe_thresh = 0; 996 // Starting bitrate low. 997 cfg_.rc_target_bitrate = 30; 998 cfg_.rc_resize_mode = RESIZE_DYNAMIC; 999 cfg_.g_forced_max_frame_width = 1280; 1000 cfg_.g_forced_max_frame_height = 1280; 1001 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 1002 1003 #if CONFIG_AV1_DECODER 1004 unsigned int last_w = cfg_.g_w; 1005 unsigned int last_h = cfg_.g_h; 1006 unsigned int frame_number = 0; 1007 int resize_down_count = 0; 1008 for (const auto &info : frame_info_list_) { 1009 if (info.w != last_w || info.h != last_h) { 1010 if (frame_number < frame_change_bitrate_) { 1011 // Verify that resize down occurs, before bitrate is increased. 1012 ASSERT_LT(info.w, last_w); 1013 ASSERT_LT(info.h, last_h); 1014 resize_down_count++; 1015 } 1016 last_w = info.w; 1017 last_h = info.h; 1018 } 1019 frame_number++; 1020 } 1021 1022 // Verify that we get at least 1 resize event in this test. 1023 ASSERT_GE(resize_down_count, 1) 1024 << "Resizing down should occur at lease once."; 1025 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames()); 1026 #else 1027 printf("Warning: AV1 decoder unavailable, unable to check resize count!\n"); 1028 #endif 1029 } 1030 1031 class ResizeCspTest : public ResizeTest { 1032 protected: 1033 #if WRITE_COMPRESSED_STREAM 1034 ResizeCspTest() 1035 : ResizeTest(), frame0_psnr_(0.0), outfile_(nullptr), out_frames_(0) {} 1036 #else 1037 ResizeCspTest() : ResizeTest(), frame0_psnr_(0.0) {} 1038 #endif 1039 1040 ~ResizeCspTest() override = default; 1041 1042 void BeginPassHook(unsigned int /*pass*/) override { 1043 #if WRITE_COMPRESSED_STREAM 1044 outfile_ = fopen("av11-2-05-cspchape.ivf", "wb"); 1045 #endif 1046 } 1047 1048 void EndPassHook() override { 1049 #if WRITE_COMPRESSED_STREAM 1050 if (outfile_) { 1051 if (!fseek(outfile_, 0, SEEK_SET)) 1052 write_ivf_file_header(&cfg_, out_frames_, outfile_); 1053 fclose(outfile_); 1054 outfile_ = nullptr; 1055 } 1056 #endif 1057 } 1058 1059 void PSNRPktHook(const aom_codec_cx_pkt_t *pkt) override { 1060 if (frame0_psnr_ == 0.) frame0_psnr_ = pkt->data.psnr.psnr[0]; 1061 EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0); 1062 } 1063 1064 #if WRITE_COMPRESSED_STREAM 1065 void FramePktHook(const aom_codec_cx_pkt_t *pkt) override { 1066 ++out_frames_; 1067 1068 // Write initial file header if first frame. 1069 if (pkt->data.frame.pts == 0) write_ivf_file_header(&cfg_, 0, outfile_); 1070 1071 // Write frame header and data. 1072 write_ivf_frame_header(pkt, outfile_); 1073 (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_); 1074 } 1075 #endif 1076 1077 double frame0_psnr_; 1078 #if WRITE_COMPRESSED_STREAM 1079 FILE *outfile_; 1080 unsigned int out_frames_; 1081 #endif 1082 }; 1083 1084 class ResizingCspVideoSource : public ::libaom_test::DummyVideoSource { 1085 public: 1086 explicit ResizingCspVideoSource(aom_img_fmt_t image_format) { 1087 SetSize(kInitialWidth, kInitialHeight); 1088 SetImageFormat(image_format); 1089 limit_ = 30; 1090 } 1091 1092 ~ResizingCspVideoSource() override = default; 1093 }; 1094 1095 #if (defined(DISABLE_TRELLISQ_SEARCH) && DISABLE_TRELLISQ_SEARCH) || \ 1096 (defined(CONFIG_MAX_DECODE_PROFILE) && CONFIG_MAX_DECODE_PROFILE < 1) 1097 TEST_P(ResizeCspTest, DISABLED_TestResizeCspWorks) { 1098 #else 1099 TEST_P(ResizeCspTest, TestResizeCspWorks) { 1100 #endif 1101 const aom_img_fmt_t image_formats[] = { AOM_IMG_FMT_I420, AOM_IMG_FMT_I444 }; 1102 for (const aom_img_fmt_t &img_format : image_formats) { 1103 ResizingCspVideoSource video(img_format); 1104 init_flags_ = AOM_CODEC_USE_PSNR; 1105 cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48; 1106 cfg_.g_lag_in_frames = 0; 1107 cfg_.g_profile = (img_format == AOM_IMG_FMT_I420) ? 0 : 1; 1108 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 1109 1110 #if CONFIG_AV1_DECODER 1111 // Check we decoded the same number of frames as we attempted to encode 1112 ASSERT_EQ(frame_info_list_.size(), video.limit()); 1113 frame_info_list_.clear(); 1114 #endif 1115 } 1116 } 1117 1118 #if !CONFIG_REALTIME_ONLY 1119 // This class is used to check if there are any fatal 1120 // failures while encoding with resize-mode > 0 1121 class ResizeModeTestLarge 1122 : public ::libaom_test::CodecTestWith5Params<libaom_test::TestMode, int, 1123 int, int, int>, 1124 public ::libaom_test::EncoderTest { 1125 protected: 1126 ResizeModeTestLarge() 1127 : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)), 1128 resize_mode_(GET_PARAM(2)), resize_denominator_(GET_PARAM(3)), 1129 resize_kf_denominator_(GET_PARAM(4)), cpu_used_(GET_PARAM(5)) {} 1130 ~ResizeModeTestLarge() override = default; 1131 1132 void SetUp() override { 1133 InitializeConfig(encoding_mode_); 1134 const aom_rational timebase = { 1, 30 }; 1135 cfg_.g_timebase = timebase; 1136 cfg_.rc_end_usage = AOM_VBR; 1137 cfg_.g_threads = 1; 1138 cfg_.g_lag_in_frames = 35; 1139 cfg_.rc_target_bitrate = 1000; 1140 cfg_.rc_resize_mode = resize_mode_; 1141 cfg_.rc_resize_denominator = resize_denominator_; 1142 cfg_.rc_resize_kf_denominator = resize_kf_denominator_; 1143 init_flags_ = AOM_CODEC_USE_PSNR; 1144 } 1145 1146 void PreEncodeFrameHook(::libaom_test::VideoSource *video, 1147 ::libaom_test::Encoder *encoder) override { 1148 if (video->frame() == 0) { 1149 encoder->Control(AOME_SET_CPUUSED, cpu_used_); 1150 encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1); 1151 } 1152 } 1153 1154 ::libaom_test::TestMode encoding_mode_; 1155 int resize_mode_; 1156 int resize_denominator_; 1157 int resize_kf_denominator_; 1158 int cpu_used_; 1159 }; 1160 1161 TEST_P(ResizeModeTestLarge, ResizeModeTest) { 1162 ::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 30); 1163 ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); 1164 } 1165 1166 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ResizeModeTestLarge); 1167 AV1_INSTANTIATE_TEST_SUITE(ResizeModeTestLarge, 1168 ::testing::Values(::libaom_test::kOnePassGood, 1169 ::libaom_test::kTwoPassGood), 1170 ::testing::Values(1, 2), ::testing::Values(8, 12), 1171 ::testing::Values(10, 14), ::testing::Values(3, 6)); 1172 #endif // !CONFIG_REALTIME_ONLY 1173 1174 #if CONFIG_REALTIME_ONLY 1175 AV1_INSTANTIATE_TEST_SUITE(ResizeTest, 1176 ::testing::Values(::libaom_test::kRealTime)); 1177 #else 1178 AV1_INSTANTIATE_TEST_SUITE(ResizeTest, 1179 ::testing::Values(::libaom_test::kRealTime, 1180 ::libaom_test::kOnePassGood)); 1181 #endif 1182 1183 AV1_INSTANTIATE_TEST_SUITE(ResizeRealtimeTest, 1184 ::testing::Values(::libaom_test::kRealTime), 1185 ::testing::Range(6, 10), ::testing::Values(1, 2, 4)); 1186 AV1_INSTANTIATE_TEST_SUITE(ResizeCspTest, 1187 ::testing::Values(::libaom_test::kRealTime)); 1188 1189 // A test that reproduces crbug.com/1393384. In realtime usage mode, encode 1190 // frames of sizes 202x202, 1x202, and 202x202. ASan should report no memory 1191 // errors. 1192 TEST(ResizeSimpleTest, TemporarySmallerFrameSize) { 1193 constexpr int kWidth = 202; 1194 constexpr int kHeight = 202; 1195 // Dummy buffer of zero samples. 1196 constexpr size_t kBufferSize = 1197 kWidth * kHeight + 2 * (kWidth + 1) / 2 * (kHeight + 1) / 2; 1198 std::vector<unsigned char> buffer(kBufferSize); 1199 1200 aom_image_t img; 1201 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1, 1202 buffer.data())); 1203 aom_image_t img2; 1204 EXPECT_EQ(&img2, aom_img_wrap(&img2, AOM_IMG_FMT_I420, 1, kHeight, 1, 1205 buffer.data())); 1206 1207 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1208 aom_codec_enc_cfg_t cfg; 1209 EXPECT_EQ(AOM_CODEC_OK, 1210 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME)); 1211 cfg.g_w = kWidth; 1212 cfg.g_h = kHeight; 1213 aom_codec_ctx_t enc; 1214 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 1215 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 5)); 1216 1217 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); 1218 1219 cfg.g_w = 1; 1220 cfg.g_h = kHeight; 1221 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg)); 1222 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img2, 1, 1, 0)); 1223 1224 cfg.g_w = kWidth; 1225 cfg.g_h = kHeight; 1226 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg)); 1227 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 2, 1, 0)); 1228 1229 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0)); 1230 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 1231 } 1232 1233 // A test that reproduces crbug.com/1410766. In realtime usage mode 1234 // for SVC with temporal layers, encode frames of sizes 600x600, 1235 // 600x600, and 100x480. ASan should report no memory errors. 1236 TEST(ResizeSimpleTest, SmallerFrameSizeSVC) { 1237 constexpr int kWidth = 600; 1238 constexpr int kHeight = 600; 1239 // Dummy buffer of zero samples. 1240 constexpr size_t kBufferSize = 1241 kWidth * kHeight + 2 * (kWidth + 1) / 2 * (kHeight + 1) / 2; 1242 std::vector<unsigned char> buffer(kBufferSize); 1243 1244 aom_image_t img; 1245 EXPECT_EQ(&img, aom_img_wrap(&img, AOM_IMG_FMT_I420, kWidth, kHeight, 1, 1246 buffer.data())); 1247 aom_image_t img2; 1248 EXPECT_EQ(&img2, 1249 aom_img_wrap(&img2, AOM_IMG_FMT_I420, 100, 480, 1, buffer.data())); 1250 1251 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1252 aom_codec_enc_cfg_t cfg; 1253 EXPECT_EQ(AOM_CODEC_OK, 1254 aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME)); 1255 cfg.g_w = kWidth; 1256 cfg.g_h = kHeight; 1257 aom_codec_ctx_t enc; 1258 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 1259 EXPECT_EQ(AOM_CODEC_OK, aom_codec_control(&enc, AOME_SET_CPUUSED, 5)); 1260 1261 aom_svc_params_t svc_params = {}; 1262 aom_svc_layer_id_t layer_id; 1263 svc_params.number_spatial_layers = 1; 1264 svc_params.framerate_factor[0] = 2; 1265 svc_params.framerate_factor[1] = 1; 1266 svc_params.number_temporal_layers = 2; 1267 // Bitrate allocation L0: 60% L1: 40% 1268 svc_params.layer_target_bitrate[0] = 60 * cfg.rc_target_bitrate / 100; 1269 svc_params.layer_target_bitrate[1] = cfg.rc_target_bitrate; 1270 EXPECT_EQ(AOM_CODEC_OK, 1271 aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params)); 1272 1273 layer_id.spatial_layer_id = 0; 1274 layer_id.temporal_layer_id = 0; 1275 EXPECT_EQ(AOM_CODEC_OK, 1276 aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id)); 1277 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 0, 1, 0)); 1278 1279 cfg.g_w = kWidth; 1280 cfg.g_h = kHeight; 1281 layer_id.temporal_layer_id = 1; 1282 EXPECT_EQ(AOM_CODEC_OK, 1283 aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id)); 1284 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg)); 1285 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img, 1, 1, 0)); 1286 1287 cfg.g_w = 100; 1288 cfg.g_h = 480; 1289 layer_id.temporal_layer_id = 0; 1290 EXPECT_EQ(AOM_CODEC_OK, 1291 aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id)); 1292 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg)); 1293 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img2, 2, 1, 0)); 1294 1295 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0)); 1296 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 1297 } 1298 1299 const int kUsages[] = 1300 #if CONFIG_REALTIME_ONLY 1301 { AOM_USAGE_REALTIME }; 1302 #else 1303 { AOM_USAGE_GOOD_QUALITY, AOM_USAGE_REALTIME, AOM_USAGE_ALL_INTRA }; 1304 #endif 1305 1306 const int kNumThreads[] = { 2, 4, 8 }; 1307 1308 class FrameSizeChangeTest 1309 : public ::libaom_test::CodecTestWith3Params<int, int, int> { 1310 protected: 1311 FrameSizeChangeTest() {} 1312 ~FrameSizeChangeTest() override = default; 1313 1314 void DoTest(int change_thread) { 1315 usage_ = GET_PARAM(1); 1316 cpu_used_ = GET_PARAM(2); 1317 threads_ = GET_PARAM(3); 1318 constexpr int kWidth = 512; 1319 constexpr int kHeight = 512; 1320 constexpr int kFirstWidth = 256; 1321 constexpr int kFirstHeight = 256; 1322 // Buffer of zero samples. 1323 constexpr size_t kBufferSize = 3 * kWidth * kHeight; 1324 std::vector<unsigned char> buffer(kBufferSize, 1325 static_cast<unsigned char>(0)); 1326 1327 aom_image_t img1; 1328 EXPECT_EQ(&img1, aom_img_wrap(&img1, AOM_IMG_FMT_I420, kFirstWidth, 1329 kFirstHeight, 1, buffer.data())); 1330 1331 aom_image_t img2; 1332 EXPECT_EQ(&img2, aom_img_wrap(&img2, AOM_IMG_FMT_I420, kWidth, kHeight, 1, 1333 buffer.data())); 1334 1335 aom_codec_iface_t *iface = aom_codec_av1_cx(); 1336 aom_codec_enc_cfg_t cfg; 1337 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_default(iface, &cfg, usage_)); 1338 cfg.g_threads = threads_; 1339 cfg.g_lag_in_frames = usage_ == AOM_USAGE_ALL_INTRA ? 0 : 1; 1340 cfg.g_w = kFirstWidth; 1341 cfg.g_h = kFirstHeight; 1342 cfg.g_forced_max_frame_width = kWidth; 1343 cfg.g_forced_max_frame_height = kHeight; 1344 aom_codec_ctx_t enc; 1345 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_init(&enc, iface, &cfg, 0)); 1346 EXPECT_EQ(AOM_CODEC_OK, 1347 aom_codec_control(&enc, AOME_SET_CPUUSED, cpu_used_)); 1348 1349 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img1, 0, 1, 0)); 1350 1351 if (change_thread == 1) { 1352 cfg.g_threads = AOMMAX(1, threads_ / 2); 1353 } else if (change_thread == 2) { 1354 cfg.g_threads = threads_ * 2; 1355 } 1356 cfg.g_w = kWidth; 1357 cfg.g_h = kHeight; 1358 EXPECT_EQ(AOM_CODEC_OK, aom_codec_enc_config_set(&enc, &cfg)); 1359 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, &img2, 1, 1, 0)); 1360 1361 EXPECT_EQ(AOM_CODEC_OK, aom_codec_encode(&enc, nullptr, 0, 0, 0)); 1362 EXPECT_EQ(AOM_CODEC_OK, aom_codec_destroy(&enc)); 1363 } 1364 1365 int cpu_used_; 1366 int threads_; 1367 int usage_; 1368 }; 1369 1370 TEST_P(FrameSizeChangeTest, FixedThreads) { DoTest(0); } 1371 TEST_P(FrameSizeChangeTest, DecreasingThreads) { DoTest(1); } 1372 TEST_P(FrameSizeChangeTest, IncreasingThreads) { DoTest(2); } 1373 1374 AV1_INSTANTIATE_TEST_SUITE(FrameSizeChangeTest, ::testing::ValuesIn(kUsages), 1375 ::testing::Range(6, 7), 1376 ::testing::ValuesIn(kNumThreads)); 1377 1378 } // namespace