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