1 /*
2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10 #include <stdio.h>
11
12 #include <climits>
13 #include <vector>
14 #include "third_party/googletest/src/include/gtest/gtest.h"
15 #include "test/codec_factory.h"
16 #include "test/encode_test_driver.h"
17 #include "test/i420_video_source.h"
18 #include "test/video_source.h"
19 #include "test/util.h"
20
21 // Enable(1) or Disable(0) writing of the compressed bitstream.
22 #define WRITE_COMPRESSED_STREAM 0
23
24 namespace {
25
26 #if WRITE_COMPRESSED_STREAM
mem_put_le16(char * const mem,const unsigned int val)27 static void mem_put_le16(char *const mem, const unsigned int val) {
28 mem[0] = val;
29 mem[1] = val >> 8;
30 }
31
mem_put_le32(char * const mem,const unsigned int val)32 static void mem_put_le32(char *const mem, const unsigned int val) {
33 mem[0] = val;
34 mem[1] = val >> 8;
35 mem[2] = val >> 16;
36 mem[3] = val >> 24;
37 }
38
write_ivf_file_header(const vpx_codec_enc_cfg_t * const cfg,int frame_cnt,FILE * const outfile)39 static void write_ivf_file_header(const vpx_codec_enc_cfg_t *const cfg,
40 int frame_cnt, FILE *const outfile) {
41 char header[32];
42
43 header[0] = 'D';
44 header[1] = 'K';
45 header[2] = 'I';
46 header[3] = 'F';
47 mem_put_le16(header + 4, 0); /* version */
48 mem_put_le16(header + 6, 32); /* headersize */
49 mem_put_le32(header + 8, 0x30395056); /* fourcc (vp9) */
50 mem_put_le16(header + 12, cfg->g_w); /* width */
51 mem_put_le16(header + 14, cfg->g_h); /* height */
52 mem_put_le32(header + 16, cfg->g_timebase.den); /* rate */
53 mem_put_le32(header + 20, cfg->g_timebase.num); /* scale */
54 mem_put_le32(header + 24, frame_cnt); /* length */
55 mem_put_le32(header + 28, 0); /* unused */
56
57 (void)fwrite(header, 1, 32, outfile);
58 }
59
write_ivf_frame_size(FILE * const outfile,const size_t size)60 static void write_ivf_frame_size(FILE *const outfile, const size_t size) {
61 char header[4];
62 mem_put_le32(header, static_cast<unsigned int>(size));
63 (void)fwrite(header, 1, 4, outfile);
64 }
65
write_ivf_frame_header(const vpx_codec_cx_pkt_t * const pkt,FILE * const outfile)66 static void write_ivf_frame_header(const vpx_codec_cx_pkt_t *const pkt,
67 FILE *const outfile) {
68 char header[12];
69 vpx_codec_pts_t pts;
70
71 if (pkt->kind != VPX_CODEC_CX_FRAME_PKT) return;
72
73 pts = pkt->data.frame.pts;
74 mem_put_le32(header, static_cast<unsigned int>(pkt->data.frame.sz));
75 mem_put_le32(header + 4, pts & 0xFFFFFFFF);
76 mem_put_le32(header + 8, pts >> 32);
77
78 (void)fwrite(header, 1, 12, outfile);
79 }
80 #endif // WRITE_COMPRESSED_STREAM
81
82 const unsigned int kInitialWidth = 320;
83 const unsigned int kInitialHeight = 240;
84
85 struct FrameInfo {
FrameInfo__anon90f106ec0111::FrameInfo86 FrameInfo(vpx_codec_pts_t _pts, unsigned int _w, unsigned int _h)
87 : pts(_pts), w(_w), h(_h) {}
88
89 vpx_codec_pts_t pts;
90 unsigned int w;
91 unsigned int h;
92 };
93
ScaleForFrameNumber(unsigned int frame,unsigned int initial_w,unsigned int initial_h,unsigned int * w,unsigned int * h,int flag_codec)94 void ScaleForFrameNumber(unsigned int frame, unsigned int initial_w,
95 unsigned int initial_h, unsigned int *w,
96 unsigned int *h, int flag_codec) {
97 if (frame < 10) {
98 *w = initial_w;
99 *h = initial_h;
100 return;
101 }
102 if (frame < 20) {
103 *w = initial_w * 3 / 4;
104 *h = initial_h * 3 / 4;
105 return;
106 }
107 if (frame < 30) {
108 *w = initial_w / 2;
109 *h = initial_h / 2;
110 return;
111 }
112 if (frame < 40) {
113 *w = initial_w;
114 *h = initial_h;
115 return;
116 }
117 if (frame < 50) {
118 *w = initial_w * 3 / 4;
119 *h = initial_h * 3 / 4;
120 return;
121 }
122 if (frame < 60) {
123 *w = initial_w / 2;
124 *h = initial_h / 2;
125 return;
126 }
127 if (frame < 70) {
128 *w = initial_w;
129 *h = initial_h;
130 return;
131 }
132 if (frame < 80) {
133 *w = initial_w * 3 / 4;
134 *h = initial_h * 3 / 4;
135 return;
136 }
137 if (frame < 90) {
138 *w = initial_w / 2;
139 *h = initial_h / 2;
140 return;
141 }
142 if (frame < 100) {
143 *w = initial_w * 3 / 4;
144 *h = initial_h * 3 / 4;
145 return;
146 }
147 if (frame < 110) {
148 *w = initial_w;
149 *h = initial_h;
150 return;
151 }
152 if (frame < 120) {
153 *w = initial_w * 3 / 4;
154 *h = initial_h * 3 / 4;
155 return;
156 }
157 if (frame < 130) {
158 *w = initial_w / 2;
159 *h = initial_h / 2;
160 return;
161 }
162 if (frame < 140) {
163 *w = initial_w * 3 / 4;
164 *h = initial_h * 3 / 4;
165 return;
166 }
167 if (frame < 150) {
168 *w = initial_w;
169 *h = initial_h;
170 return;
171 }
172 if (frame < 160) {
173 *w = initial_w * 3 / 4;
174 *h = initial_h * 3 / 4;
175 return;
176 }
177 if (frame < 170) {
178 *w = initial_w / 2;
179 *h = initial_h / 2;
180 return;
181 }
182 if (frame < 180) {
183 *w = initial_w * 3 / 4;
184 *h = initial_h * 3 / 4;
185 return;
186 }
187 if (frame < 190) {
188 *w = initial_w;
189 *h = initial_h;
190 return;
191 }
192 if (frame < 200) {
193 *w = initial_w * 3 / 4;
194 *h = initial_h * 3 / 4;
195 return;
196 }
197 if (frame < 210) {
198 *w = initial_w / 2;
199 *h = initial_h / 2;
200 return;
201 }
202 if (frame < 220) {
203 *w = initial_w * 3 / 4;
204 *h = initial_h * 3 / 4;
205 return;
206 }
207 if (frame < 230) {
208 *w = initial_w;
209 *h = initial_h;
210 return;
211 }
212 if (frame < 240) {
213 *w = initial_w * 3 / 4;
214 *h = initial_h * 3 / 4;
215 return;
216 }
217 if (frame < 250) {
218 *w = initial_w / 2;
219 *h = initial_h / 2;
220 return;
221 }
222 if (frame < 260) {
223 *w = initial_w;
224 *h = initial_h;
225 return;
226 }
227 // Go down very low.
228 if (frame < 270) {
229 *w = initial_w / 4;
230 *h = initial_h / 4;
231 return;
232 }
233 if (flag_codec == 1) {
234 // Cases that only works for VP9.
235 // For VP9: Swap width and height of original.
236 if (frame < 320) {
237 *w = initial_h;
238 *h = initial_w;
239 return;
240 }
241 }
242 *w = initial_w;
243 *h = initial_h;
244 }
245
246 class ResizingVideoSource : public ::libvpx_test::DummyVideoSource {
247 public:
ResizingVideoSource()248 ResizingVideoSource() {
249 SetSize(kInitialWidth, kInitialHeight);
250 limit_ = 350;
251 }
252 int flag_codec_;
~ResizingVideoSource()253 virtual ~ResizingVideoSource() {}
254
255 protected:
Next()256 virtual void Next() {
257 ++frame_;
258 unsigned int width;
259 unsigned int height;
260 ScaleForFrameNumber(frame_, kInitialWidth, kInitialHeight, &width, &height,
261 flag_codec_);
262 SetSize(width, height);
263 FillFrame();
264 }
265 };
266
267 class ResizeTest
268 : public ::libvpx_test::EncoderTest,
269 public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
270 protected:
ResizeTest()271 ResizeTest() : EncoderTest(GET_PARAM(0)) {}
272
~ResizeTest()273 virtual ~ResizeTest() {}
274
SetUp()275 virtual void SetUp() {
276 InitializeConfig();
277 SetMode(GET_PARAM(1));
278 }
279
DecompressedFrameHook(const vpx_image_t & img,vpx_codec_pts_t pts)280 virtual void DecompressedFrameHook(const vpx_image_t &img,
281 vpx_codec_pts_t pts) {
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
TEST_P(ResizeTest,TestExternalResizeWorks)288 TEST_P(ResizeTest, TestExternalResizeWorks) {
289 ResizingVideoSource video;
290 video.flag_codec_ = 0;
291 cfg_.g_lag_in_frames = 0;
292 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
293
294 for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
295 info != frame_info_list_.end(); ++info) {
296 const unsigned int frame = static_cast<unsigned>(info->pts);
297 unsigned int expected_w;
298 unsigned int expected_h;
299 ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w,
300 &expected_h, 0);
301 EXPECT_EQ(expected_w, info->w) << "Frame " << frame
302 << " had unexpected width";
303 EXPECT_EQ(expected_h, info->h) << "Frame " << frame
304 << " had unexpected height";
305 }
306 }
307
308 const unsigned int kStepDownFrame = 3;
309 const unsigned int kStepUpFrame = 6;
310
311 class ResizeInternalTest : public ResizeTest {
312 protected:
313 #if WRITE_COMPRESSED_STREAM
ResizeInternalTest()314 ResizeInternalTest()
315 : ResizeTest(), frame0_psnr_(0.0), outfile_(NULL), out_frames_(0) {}
316 #else
317 ResizeInternalTest() : ResizeTest(), frame0_psnr_(0.0) {}
318 #endif
319
~ResizeInternalTest()320 virtual ~ResizeInternalTest() {}
321
BeginPassHook(unsigned int)322 virtual void BeginPassHook(unsigned int /*pass*/) {
323 #if WRITE_COMPRESSED_STREAM
324 outfile_ = fopen("vp90-2-05-resize.ivf", "wb");
325 #endif
326 }
327
EndPassHook()328 virtual void EndPassHook() {
329 #if WRITE_COMPRESSED_STREAM
330 if (outfile_) {
331 if (!fseek(outfile_, 0, SEEK_SET))
332 write_ivf_file_header(&cfg_, out_frames_, outfile_);
333 fclose(outfile_);
334 outfile_ = NULL;
335 }
336 #endif
337 }
338
PreEncodeFrameHook(libvpx_test::VideoSource * video,libvpx_test::Encoder * encoder)339 virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
340 libvpx_test::Encoder *encoder) {
341 if (change_config_) {
342 int new_q = 60;
343 if (video->frame() == 0) {
344 struct vpx_scaling_mode mode = { VP8E_ONETWO, VP8E_ONETWO };
345 encoder->Control(VP8E_SET_SCALEMODE, &mode);
346 }
347 if (video->frame() == 1) {
348 struct vpx_scaling_mode mode = { VP8E_NORMAL, VP8E_NORMAL };
349 encoder->Control(VP8E_SET_SCALEMODE, &mode);
350 cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = new_q;
351 encoder->Config(&cfg_);
352 }
353 } else {
354 if (video->frame() == kStepDownFrame) {
355 struct vpx_scaling_mode mode = { VP8E_FOURFIVE, VP8E_THREEFIVE };
356 encoder->Control(VP8E_SET_SCALEMODE, &mode);
357 }
358 if (video->frame() == kStepUpFrame) {
359 struct vpx_scaling_mode mode = { VP8E_NORMAL, VP8E_NORMAL };
360 encoder->Control(VP8E_SET_SCALEMODE, &mode);
361 }
362 }
363 }
364
PSNRPktHook(const vpx_codec_cx_pkt_t * pkt)365 virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
366 if (frame0_psnr_ == 0.) frame0_psnr_ = pkt->data.psnr.psnr[0];
367 EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0);
368 }
369
370 #if WRITE_COMPRESSED_STREAM
FramePktHook(const vpx_codec_cx_pkt_t * pkt)371 virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
372 ++out_frames_;
373
374 // Write initial file header if first frame.
375 if (pkt->data.frame.pts == 0) write_ivf_file_header(&cfg_, 0, outfile_);
376
377 // Write frame header and data.
378 write_ivf_frame_header(pkt, outfile_);
379 (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_);
380 }
381 #endif
382
383 double frame0_psnr_;
384 bool change_config_;
385 #if WRITE_COMPRESSED_STREAM
386 FILE *outfile_;
387 unsigned int out_frames_;
388 #endif
389 };
390
TEST_P(ResizeInternalTest,TestInternalResizeWorks)391 TEST_P(ResizeInternalTest, TestInternalResizeWorks) {
392 ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
393 30, 1, 0, 10);
394 init_flags_ = VPX_CODEC_USE_PSNR;
395 change_config_ = false;
396
397 // q picked such that initial keyframe on this clip is ~30dB PSNR
398 cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48;
399
400 // If the number of frames being encoded is smaller than g_lag_in_frames
401 // the encoded frame is unavailable using the current API. Comparing
402 // frames to detect mismatch would then not be possible. Set
403 // g_lag_in_frames = 0 to get around this.
404 cfg_.g_lag_in_frames = 0;
405 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
406
407 for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
408 info != frame_info_list_.end(); ++info) {
409 const vpx_codec_pts_t pts = info->pts;
410 if (pts >= kStepDownFrame && pts < kStepUpFrame) {
411 ASSERT_EQ(282U, info->w) << "Frame " << pts << " had unexpected width";
412 ASSERT_EQ(173U, info->h) << "Frame " << pts << " had unexpected height";
413 } else {
414 EXPECT_EQ(352U, info->w) << "Frame " << pts << " had unexpected width";
415 EXPECT_EQ(288U, info->h) << "Frame " << pts << " had unexpected height";
416 }
417 }
418 }
419
TEST_P(ResizeInternalTest,TestInternalResizeChangeConfig)420 TEST_P(ResizeInternalTest, TestInternalResizeChangeConfig) {
421 ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
422 30, 1, 0, 10);
423 cfg_.g_w = 352;
424 cfg_.g_h = 288;
425 change_config_ = true;
426 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
427 }
428
429 class ResizeRealtimeTest
430 : public ::libvpx_test::EncoderTest,
431 public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
432 protected:
ResizeRealtimeTest()433 ResizeRealtimeTest() : EncoderTest(GET_PARAM(0)) {}
~ResizeRealtimeTest()434 virtual ~ResizeRealtimeTest() {}
435
PreEncodeFrameHook(libvpx_test::VideoSource * video,libvpx_test::Encoder * encoder)436 virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
437 libvpx_test::Encoder *encoder) {
438 if (video->frame() == 0) {
439 encoder->Control(VP9E_SET_AQ_MODE, 3);
440 encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
441 }
442
443 if (change_bitrate_ && video->frame() == 120) {
444 change_bitrate_ = false;
445 cfg_.rc_target_bitrate = 500;
446 encoder->Config(&cfg_);
447 }
448 }
449
SetUp()450 virtual void SetUp() {
451 InitializeConfig();
452 SetMode(GET_PARAM(1));
453 set_cpu_used_ = GET_PARAM(2);
454 }
455
DecompressedFrameHook(const vpx_image_t & img,vpx_codec_pts_t pts)456 virtual void DecompressedFrameHook(const vpx_image_t &img,
457 vpx_codec_pts_t pts) {
458 frame_info_list_.push_back(FrameInfo(pts, img.d_w, img.d_h));
459 }
460
MismatchHook(const vpx_image_t * img1,const vpx_image_t * img2)461 virtual void MismatchHook(const vpx_image_t *img1, const vpx_image_t *img2) {
462 double mismatch_psnr = compute_psnr(img1, img2);
463 mismatch_psnr_ += mismatch_psnr;
464 ++mismatch_nframes_;
465 }
466
GetMismatchFrames()467 unsigned int GetMismatchFrames() { return mismatch_nframes_; }
468
DefaultConfig()469 void DefaultConfig() {
470 cfg_.rc_buf_initial_sz = 500;
471 cfg_.rc_buf_optimal_sz = 600;
472 cfg_.rc_buf_sz = 1000;
473 cfg_.rc_min_quantizer = 2;
474 cfg_.rc_max_quantizer = 56;
475 cfg_.rc_undershoot_pct = 50;
476 cfg_.rc_overshoot_pct = 50;
477 cfg_.rc_end_usage = VPX_CBR;
478 cfg_.kf_mode = VPX_KF_AUTO;
479 cfg_.g_lag_in_frames = 0;
480 cfg_.kf_min_dist = cfg_.kf_max_dist = 3000;
481 // Enable dropped frames.
482 cfg_.rc_dropframe_thresh = 1;
483 // Enable error_resilience mode.
484 cfg_.g_error_resilient = 1;
485 // Enable dynamic resizing.
486 cfg_.rc_resize_allowed = 1;
487 // Run at low bitrate.
488 cfg_.rc_target_bitrate = 200;
489 }
490
491 std::vector<FrameInfo> frame_info_list_;
492 int set_cpu_used_;
493 bool change_bitrate_;
494 double mismatch_psnr_;
495 int mismatch_nframes_;
496 };
497
TEST_P(ResizeRealtimeTest,TestExternalResizeWorks)498 TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) {
499 ResizingVideoSource video;
500 video.flag_codec_ = 1;
501 DefaultConfig();
502 // Disable internal resize for this test.
503 cfg_.rc_resize_allowed = 0;
504 change_bitrate_ = false;
505 mismatch_psnr_ = 0.0;
506 mismatch_nframes_ = 0;
507 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
508
509 for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
510 info != frame_info_list_.end(); ++info) {
511 const unsigned int frame = static_cast<unsigned>(info->pts);
512 unsigned int expected_w;
513 unsigned int expected_h;
514 ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w,
515 &expected_h, 1);
516 EXPECT_EQ(expected_w, info->w) << "Frame " << frame
517 << " had unexpected width";
518 EXPECT_EQ(expected_h, info->h) << "Frame " << frame
519 << " had unexpected height";
520 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
521 }
522 }
523
524 // Verify the dynamic resizer behavior for real time, 1 pass CBR mode.
525 // Run at low bitrate, with resize_allowed = 1, and verify that we get
526 // one resize down event.
TEST_P(ResizeRealtimeTest,TestInternalResizeDown)527 TEST_P(ResizeRealtimeTest, TestInternalResizeDown) {
528 ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
529 30, 1, 0, 299);
530 DefaultConfig();
531 cfg_.g_w = 352;
532 cfg_.g_h = 288;
533 change_bitrate_ = false;
534 mismatch_psnr_ = 0.0;
535 mismatch_nframes_ = 0;
536 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
537
538 unsigned int last_w = cfg_.g_w;
539 unsigned int last_h = cfg_.g_h;
540 int resize_count = 0;
541 for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
542 info != frame_info_list_.end(); ++info) {
543 if (info->w != last_w || info->h != last_h) {
544 // Verify that resize down occurs.
545 ASSERT_LT(info->w, last_w);
546 ASSERT_LT(info->h, last_h);
547 last_w = info->w;
548 last_h = info->h;
549 resize_count++;
550 }
551 }
552
553 #if CONFIG_VP9_DECODER
554 // Verify that we get 1 resize down event in this test.
555 ASSERT_EQ(1, resize_count) << "Resizing should occur.";
556 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
557 #else
558 printf("Warning: VP9 decoder unavailable, unable to check resize count!\n");
559 #endif
560 }
561
562 // Verify the dynamic resizer behavior for real time, 1 pass CBR mode.
563 // Start at low target bitrate, raise the bitrate in the middle of the clip,
564 // scaling-up should occur after bitrate changed.
TEST_P(ResizeRealtimeTest,TestInternalResizeDownUpChangeBitRate)565 TEST_P(ResizeRealtimeTest, TestInternalResizeDownUpChangeBitRate) {
566 ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
567 30, 1, 0, 359);
568 DefaultConfig();
569 cfg_.g_w = 352;
570 cfg_.g_h = 288;
571 change_bitrate_ = true;
572 mismatch_psnr_ = 0.0;
573 mismatch_nframes_ = 0;
574 // Disable dropped frames.
575 cfg_.rc_dropframe_thresh = 0;
576 // Starting bitrate low.
577 cfg_.rc_target_bitrate = 80;
578 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
579
580 unsigned int last_w = cfg_.g_w;
581 unsigned int last_h = cfg_.g_h;
582 int resize_count = 0;
583 for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
584 info != frame_info_list_.end(); ++info) {
585 if (info->w != last_w || info->h != last_h) {
586 resize_count++;
587 if (resize_count == 1) {
588 // Verify that resize down occurs.
589 ASSERT_LT(info->w, last_w);
590 ASSERT_LT(info->h, last_h);
591 } else if (resize_count == 2) {
592 // Verify that resize up occurs.
593 ASSERT_GT(info->w, last_w);
594 ASSERT_GT(info->h, last_h);
595 }
596 last_w = info->w;
597 last_h = info->h;
598 }
599 }
600
601 #if CONFIG_VP9_DECODER
602 // Verify that we get 2 resize events in this test.
603 ASSERT_EQ(resize_count, 2) << "Resizing should occur twice.";
604 EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
605 #else
606 printf("Warning: VP9 decoder unavailable, unable to check resize count!\n");
607 #endif
608 }
609
CspForFrameNumber(int frame)610 vpx_img_fmt_t CspForFrameNumber(int frame) {
611 if (frame < 10) return VPX_IMG_FMT_I420;
612 if (frame < 20) return VPX_IMG_FMT_I444;
613 return VPX_IMG_FMT_I420;
614 }
615
616 class ResizeCspTest : public ResizeTest {
617 protected:
618 #if WRITE_COMPRESSED_STREAM
ResizeCspTest()619 ResizeCspTest()
620 : ResizeTest(), frame0_psnr_(0.0), outfile_(NULL), out_frames_(0) {}
621 #else
622 ResizeCspTest() : ResizeTest(), frame0_psnr_(0.0) {}
623 #endif
624
~ResizeCspTest()625 virtual ~ResizeCspTest() {}
626
BeginPassHook(unsigned int)627 virtual void BeginPassHook(unsigned int /*pass*/) {
628 #if WRITE_COMPRESSED_STREAM
629 outfile_ = fopen("vp91-2-05-cspchape.ivf", "wb");
630 #endif
631 }
632
EndPassHook()633 virtual void EndPassHook() {
634 #if WRITE_COMPRESSED_STREAM
635 if (outfile_) {
636 if (!fseek(outfile_, 0, SEEK_SET))
637 write_ivf_file_header(&cfg_, out_frames_, outfile_);
638 fclose(outfile_);
639 outfile_ = NULL;
640 }
641 #endif
642 }
643
PreEncodeFrameHook(libvpx_test::VideoSource * video,libvpx_test::Encoder * encoder)644 virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
645 libvpx_test::Encoder *encoder) {
646 if (CspForFrameNumber(video->frame()) != VPX_IMG_FMT_I420 &&
647 cfg_.g_profile != 1) {
648 cfg_.g_profile = 1;
649 encoder->Config(&cfg_);
650 }
651 if (CspForFrameNumber(video->frame()) == VPX_IMG_FMT_I420 &&
652 cfg_.g_profile != 0) {
653 cfg_.g_profile = 0;
654 encoder->Config(&cfg_);
655 }
656 }
657
PSNRPktHook(const vpx_codec_cx_pkt_t * pkt)658 virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
659 if (frame0_psnr_ == 0.) frame0_psnr_ = pkt->data.psnr.psnr[0];
660 EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0);
661 }
662
663 #if WRITE_COMPRESSED_STREAM
FramePktHook(const vpx_codec_cx_pkt_t * pkt)664 virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
665 ++out_frames_;
666
667 // Write initial file header if first frame.
668 if (pkt->data.frame.pts == 0) write_ivf_file_header(&cfg_, 0, outfile_);
669
670 // Write frame header and data.
671 write_ivf_frame_header(pkt, outfile_);
672 (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_);
673 }
674 #endif
675
676 double frame0_psnr_;
677 #if WRITE_COMPRESSED_STREAM
678 FILE *outfile_;
679 unsigned int out_frames_;
680 #endif
681 };
682
683 class ResizingCspVideoSource : public ::libvpx_test::DummyVideoSource {
684 public:
ResizingCspVideoSource()685 ResizingCspVideoSource() {
686 SetSize(kInitialWidth, kInitialHeight);
687 limit_ = 30;
688 }
689
~ResizingCspVideoSource()690 virtual ~ResizingCspVideoSource() {}
691
692 protected:
Next()693 virtual void Next() {
694 ++frame_;
695 SetImageFormat(CspForFrameNumber(frame_));
696 FillFrame();
697 }
698 };
699
TEST_P(ResizeCspTest,TestResizeCspWorks)700 TEST_P(ResizeCspTest, TestResizeCspWorks) {
701 ResizingCspVideoSource video;
702 init_flags_ = VPX_CODEC_USE_PSNR;
703 cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48;
704 cfg_.g_lag_in_frames = 0;
705 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
706 }
707
708 VP8_INSTANTIATE_TEST_CASE(ResizeTest, ONE_PASS_TEST_MODES);
709 VP9_INSTANTIATE_TEST_CASE(ResizeTest,
710 ::testing::Values(::libvpx_test::kRealTime));
711 VP9_INSTANTIATE_TEST_CASE(ResizeInternalTest,
712 ::testing::Values(::libvpx_test::kOnePassBest));
713 VP9_INSTANTIATE_TEST_CASE(ResizeRealtimeTest,
714 ::testing::Values(::libvpx_test::kRealTime),
715 ::testing::Range(5, 9));
716 VP9_INSTANTIATE_TEST_CASE(ResizeCspTest,
717 ::testing::Values(::libvpx_test::kRealTime));
718 } // namespace
719