vp9[loongarch]: Optimize fdct4x4/8x8_lsx
[platform/upstream/libvpx.git] / test / resize_test.cc
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
27 static void mem_put_le16(char *const mem, const unsigned int val) {
28   mem[0] = val;
29   mem[1] = val >> 8;
30 }
31
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
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
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
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 {
86   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
94 void ScaleForFrameNumber(unsigned int frame, unsigned int initial_w,
95                          unsigned int initial_h, unsigned int *w,
96                          unsigned int *h, bool flag_codec,
97                          bool smaller_width_larger_size_) {
98   if (smaller_width_larger_size_) {
99     if (frame < 30) {
100       *w = initial_w;
101       *h = initial_h;
102       return;
103     }
104     if (frame < 100) {
105       *w = initial_w * 7 / 10;
106       *h = initial_h * 16 / 10;
107       return;
108     }
109     return;
110   }
111   if (frame < 10) {
112     *w = initial_w;
113     *h = initial_h;
114     return;
115   }
116   if (frame < 20) {
117     *w = initial_w * 3 / 4;
118     *h = initial_h * 3 / 4;
119     return;
120   }
121   if (frame < 30) {
122     *w = initial_w / 2;
123     *h = initial_h / 2;
124     return;
125   }
126   if (frame < 40) {
127     *w = initial_w;
128     *h = initial_h;
129     return;
130   }
131   if (frame < 50) {
132     *w = initial_w * 3 / 4;
133     *h = initial_h * 3 / 4;
134     return;
135   }
136   if (frame < 60) {
137     *w = initial_w / 2;
138     *h = initial_h / 2;
139     return;
140   }
141   if (frame < 70) {
142     *w = initial_w;
143     *h = initial_h;
144     return;
145   }
146   if (frame < 80) {
147     *w = initial_w * 3 / 4;
148     *h = initial_h * 3 / 4;
149     return;
150   }
151   if (frame < 90) {
152     *w = initial_w / 2;
153     *h = initial_h / 2;
154     return;
155   }
156   if (frame < 100) {
157     *w = initial_w * 3 / 4;
158     *h = initial_h * 3 / 4;
159     return;
160   }
161   if (frame < 110) {
162     *w = initial_w;
163     *h = initial_h;
164     return;
165   }
166   if (frame < 120) {
167     *w = initial_w * 3 / 4;
168     *h = initial_h * 3 / 4;
169     return;
170   }
171   if (frame < 130) {
172     *w = initial_w / 2;
173     *h = initial_h / 2;
174     return;
175   }
176   if (frame < 140) {
177     *w = initial_w * 3 / 4;
178     *h = initial_h * 3 / 4;
179     return;
180   }
181   if (frame < 150) {
182     *w = initial_w;
183     *h = initial_h;
184     return;
185   }
186   if (frame < 160) {
187     *w = initial_w * 3 / 4;
188     *h = initial_h * 3 / 4;
189     return;
190   }
191   if (frame < 170) {
192     *w = initial_w / 2;
193     *h = initial_h / 2;
194     return;
195   }
196   if (frame < 180) {
197     *w = initial_w * 3 / 4;
198     *h = initial_h * 3 / 4;
199     return;
200   }
201   if (frame < 190) {
202     *w = initial_w;
203     *h = initial_h;
204     return;
205   }
206   if (frame < 200) {
207     *w = initial_w * 3 / 4;
208     *h = initial_h * 3 / 4;
209     return;
210   }
211   if (frame < 210) {
212     *w = initial_w / 2;
213     *h = initial_h / 2;
214     return;
215   }
216   if (frame < 220) {
217     *w = initial_w * 3 / 4;
218     *h = initial_h * 3 / 4;
219     return;
220   }
221   if (frame < 230) {
222     *w = initial_w;
223     *h = initial_h;
224     return;
225   }
226   if (frame < 240) {
227     *w = initial_w * 3 / 4;
228     *h = initial_h * 3 / 4;
229     return;
230   }
231   if (frame < 250) {
232     *w = initial_w / 2;
233     *h = initial_h / 2;
234     return;
235   }
236   if (frame < 260) {
237     *w = initial_w;
238     *h = initial_h;
239     return;
240   }
241   // Go down very low.
242   if (frame < 270) {
243     *w = initial_w / 4;
244     *h = initial_h / 4;
245     return;
246   }
247   if (flag_codec == 1) {
248     // Cases that only works for VP9.
249     // For VP9: Swap width and height of original.
250     if (frame < 320) {
251       *w = initial_h;
252       *h = initial_w;
253       return;
254     }
255   }
256   *w = initial_w;
257   *h = initial_h;
258 }
259
260 class ResizingVideoSource : public ::libvpx_test::DummyVideoSource {
261  public:
262   ResizingVideoSource() {
263     SetSize(kInitialWidth, kInitialHeight);
264     limit_ = 350;
265     smaller_width_larger_size_ = false;
266   }
267   bool flag_codec_;
268   bool smaller_width_larger_size_;
269   virtual ~ResizingVideoSource() {}
270
271  protected:
272   virtual void Next() {
273     ++frame_;
274     unsigned int width = 0;
275     unsigned int height = 0;
276     ScaleForFrameNumber(frame_, kInitialWidth, kInitialHeight, &width, &height,
277                         flag_codec_, smaller_width_larger_size_);
278     SetSize(width, height);
279     FillFrame();
280   }
281 };
282
283 class ResizeTest
284     : public ::libvpx_test::EncoderTest,
285       public ::libvpx_test::CodecTestWithParam<libvpx_test::TestMode> {
286  protected:
287   ResizeTest() : EncoderTest(GET_PARAM(0)) {}
288
289   virtual ~ResizeTest() {}
290
291   virtual void SetUp() {
292     InitializeConfig();
293     SetMode(GET_PARAM(1));
294   }
295
296   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
297     ASSERT_NE(static_cast<int>(pkt->data.frame.width[0]), 0);
298     ASSERT_NE(static_cast<int>(pkt->data.frame.height[0]), 0);
299     encode_frame_width_.push_back(pkt->data.frame.width[0]);
300     encode_frame_height_.push_back(pkt->data.frame.height[0]);
301   }
302
303   unsigned int GetFrameWidth(size_t idx) const {
304     return encode_frame_width_[idx];
305   }
306
307   unsigned int GetFrameHeight(size_t idx) const {
308     return encode_frame_height_[idx];
309   }
310
311   virtual void DecompressedFrameHook(const vpx_image_t &img,
312                                      vpx_codec_pts_t pts) {
313     frame_info_list_.push_back(FrameInfo(pts, img.d_w, img.d_h));
314   }
315
316   std::vector<FrameInfo> frame_info_list_;
317   std::vector<unsigned int> encode_frame_width_;
318   std::vector<unsigned int> encode_frame_height_;
319 };
320
321 TEST_P(ResizeTest, TestExternalResizeWorks) {
322   ResizingVideoSource video;
323   video.flag_codec_ = false;
324   video.smaller_width_larger_size_ = false;
325   cfg_.g_lag_in_frames = 0;
326   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
327
328   for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
329        info != frame_info_list_.end(); ++info) {
330     const unsigned int frame = static_cast<unsigned>(info->pts);
331     unsigned int expected_w;
332     unsigned int expected_h;
333     const size_t idx = info - frame_info_list_.begin();
334     ASSERT_EQ(info->w, GetFrameWidth(idx));
335     ASSERT_EQ(info->h, GetFrameHeight(idx));
336     ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w,
337                         &expected_h, video.flag_codec_,
338                         video.smaller_width_larger_size_);
339     EXPECT_EQ(expected_w, info->w)
340         << "Frame " << frame << " had unexpected width";
341     EXPECT_EQ(expected_h, info->h)
342         << "Frame " << frame << " had unexpected height";
343   }
344 }
345
346 const unsigned int kStepDownFrame = 3;
347 const unsigned int kStepUpFrame = 6;
348
349 class ResizeInternalTest : public ResizeTest {
350  protected:
351 #if WRITE_COMPRESSED_STREAM
352   ResizeInternalTest()
353       : ResizeTest(), frame0_psnr_(0.0), outfile_(nullptr), out_frames_(0) {}
354 #else
355   ResizeInternalTest() : ResizeTest(), frame0_psnr_(0.0) {}
356 #endif
357
358   virtual ~ResizeInternalTest() {}
359
360   virtual void BeginPassHook(unsigned int /*pass*/) {
361 #if WRITE_COMPRESSED_STREAM
362     outfile_ = fopen("vp90-2-05-resize.ivf", "wb");
363 #endif
364   }
365
366   virtual void EndPassHook() {
367 #if WRITE_COMPRESSED_STREAM
368     if (outfile_) {
369       if (!fseek(outfile_, 0, SEEK_SET))
370         write_ivf_file_header(&cfg_, out_frames_, outfile_);
371       fclose(outfile_);
372       outfile_ = nullptr;
373     }
374 #endif
375   }
376
377   virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
378                                   libvpx_test::Encoder *encoder) {
379     if (change_config_) {
380       int new_q = 60;
381       if (video->frame() == 0) {
382         struct vpx_scaling_mode mode = { VP8E_ONETWO, VP8E_ONETWO };
383         encoder->Control(VP8E_SET_SCALEMODE, &mode);
384       }
385       if (video->frame() == 1) {
386         struct vpx_scaling_mode mode = { VP8E_NORMAL, VP8E_NORMAL };
387         encoder->Control(VP8E_SET_SCALEMODE, &mode);
388         cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = new_q;
389         encoder->Config(&cfg_);
390       }
391     } else {
392       if (video->frame() == kStepDownFrame) {
393         struct vpx_scaling_mode mode = { VP8E_FOURFIVE, VP8E_THREEFIVE };
394         encoder->Control(VP8E_SET_SCALEMODE, &mode);
395       }
396       if (video->frame() == kStepUpFrame) {
397         struct vpx_scaling_mode mode = { VP8E_NORMAL, VP8E_NORMAL };
398         encoder->Control(VP8E_SET_SCALEMODE, &mode);
399       }
400     }
401   }
402
403   virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
404     if (frame0_psnr_ == 0.) frame0_psnr_ = pkt->data.psnr.psnr[0];
405     EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0);
406   }
407
408 #if WRITE_COMPRESSED_STREAM
409   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
410     ++out_frames_;
411
412     // Write initial file header if first frame.
413     if (pkt->data.frame.pts == 0) write_ivf_file_header(&cfg_, 0, outfile_);
414
415     // Write frame header and data.
416     write_ivf_frame_header(pkt, outfile_);
417     (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_);
418   }
419 #endif
420
421   double frame0_psnr_;
422   bool change_config_;
423 #if WRITE_COMPRESSED_STREAM
424   FILE *outfile_;
425   unsigned int out_frames_;
426 #endif
427 };
428
429 TEST_P(ResizeInternalTest, TestInternalResizeWorks) {
430   ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
431                                        30, 1, 0, 10);
432   init_flags_ = VPX_CODEC_USE_PSNR;
433   change_config_ = false;
434
435   // q picked such that initial keyframe on this clip is ~30dB PSNR
436   cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48;
437
438   // If the number of frames being encoded is smaller than g_lag_in_frames
439   // the encoded frame is unavailable using the current API. Comparing
440   // frames to detect mismatch would then not be possible. Set
441   // g_lag_in_frames = 0 to get around this.
442   cfg_.g_lag_in_frames = 0;
443   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
444
445   for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
446        info != frame_info_list_.end(); ++info) {
447     const vpx_codec_pts_t pts = info->pts;
448     if (pts >= kStepDownFrame && pts < kStepUpFrame) {
449       ASSERT_EQ(282U, info->w) << "Frame " << pts << " had unexpected width";
450       ASSERT_EQ(173U, info->h) << "Frame " << pts << " had unexpected height";
451     } else {
452       EXPECT_EQ(352U, info->w) << "Frame " << pts << " had unexpected width";
453       EXPECT_EQ(288U, info->h) << "Frame " << pts << " had unexpected height";
454     }
455   }
456 }
457
458 TEST_P(ResizeInternalTest, TestInternalResizeChangeConfig) {
459   ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
460                                        30, 1, 0, 10);
461   cfg_.g_w = 352;
462   cfg_.g_h = 288;
463   change_config_ = true;
464   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
465 }
466
467 class ResizeRealtimeTest
468     : public ::libvpx_test::EncoderTest,
469       public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
470  protected:
471   ResizeRealtimeTest() : EncoderTest(GET_PARAM(0)) {}
472   virtual ~ResizeRealtimeTest() {}
473
474   virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
475                                   libvpx_test::Encoder *encoder) {
476     if (video->frame() == 0) {
477       encoder->Control(VP9E_SET_AQ_MODE, 3);
478       encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_);
479     }
480
481     if (change_bitrate_ && video->frame() == 120) {
482       change_bitrate_ = false;
483       cfg_.rc_target_bitrate = 500;
484       encoder->Config(&cfg_);
485     }
486   }
487
488   virtual void SetUp() {
489     InitializeConfig();
490     SetMode(GET_PARAM(1));
491     set_cpu_used_ = GET_PARAM(2);
492   }
493
494   virtual void DecompressedFrameHook(const vpx_image_t &img,
495                                      vpx_codec_pts_t pts) {
496     frame_info_list_.push_back(FrameInfo(pts, img.d_w, img.d_h));
497   }
498
499   virtual void MismatchHook(const vpx_image_t *img1, const vpx_image_t *img2) {
500     double mismatch_psnr = compute_psnr(img1, img2);
501     mismatch_psnr_ += mismatch_psnr;
502     ++mismatch_nframes_;
503   }
504
505   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
506     ASSERT_NE(static_cast<int>(pkt->data.frame.width[0]), 0);
507     ASSERT_NE(static_cast<int>(pkt->data.frame.height[0]), 0);
508     encode_frame_width_.push_back(pkt->data.frame.width[0]);
509     encode_frame_height_.push_back(pkt->data.frame.height[0]);
510   }
511
512   unsigned int GetMismatchFrames() { return mismatch_nframes_; }
513
514   unsigned int GetFrameWidth(size_t idx) const {
515     return encode_frame_width_[idx];
516   }
517
518   unsigned int GetFrameHeight(size_t idx) const {
519     return encode_frame_height_[idx];
520   }
521
522   void DefaultConfig() {
523     cfg_.rc_buf_initial_sz = 500;
524     cfg_.rc_buf_optimal_sz = 600;
525     cfg_.rc_buf_sz = 1000;
526     cfg_.rc_min_quantizer = 2;
527     cfg_.rc_max_quantizer = 56;
528     cfg_.rc_undershoot_pct = 50;
529     cfg_.rc_overshoot_pct = 50;
530     cfg_.rc_end_usage = VPX_CBR;
531     cfg_.kf_mode = VPX_KF_AUTO;
532     cfg_.g_lag_in_frames = 0;
533     cfg_.kf_min_dist = cfg_.kf_max_dist = 3000;
534     // Enable dropped frames.
535     cfg_.rc_dropframe_thresh = 1;
536     // Enable error_resilience mode.
537     cfg_.g_error_resilient = 1;
538     // Enable dynamic resizing.
539     cfg_.rc_resize_allowed = 1;
540     // Run at low bitrate.
541     cfg_.rc_target_bitrate = 200;
542   }
543
544   std::vector<FrameInfo> frame_info_list_;
545   int set_cpu_used_;
546   bool change_bitrate_;
547   double mismatch_psnr_;
548   int mismatch_nframes_;
549   std::vector<unsigned int> encode_frame_width_;
550   std::vector<unsigned int> encode_frame_height_;
551 };
552
553 TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) {
554   ResizingVideoSource video;
555   video.flag_codec_ = true;
556   video.smaller_width_larger_size_ = false;
557   DefaultConfig();
558   // Disable internal resize for this test.
559   cfg_.rc_resize_allowed = 0;
560   change_bitrate_ = false;
561   mismatch_psnr_ = 0.0;
562   mismatch_nframes_ = 0;
563   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
564
565   for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
566        info != frame_info_list_.end(); ++info) {
567     const unsigned int frame = static_cast<unsigned>(info->pts);
568     unsigned int expected_w;
569     unsigned int expected_h;
570     ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w,
571                         &expected_h, video.flag_codec_,
572                         video.smaller_width_larger_size_);
573     EXPECT_EQ(expected_w, info->w)
574         << "Frame " << frame << " had unexpected width";
575     EXPECT_EQ(expected_h, info->h)
576         << "Frame " << frame << " had unexpected height";
577     EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
578   }
579 }
580
581 TEST_P(ResizeRealtimeTest, DISABLED_TestExternalResizeSmallerWidthBiggerSize) {
582   ResizingVideoSource video;
583   video.flag_codec_ = true;
584   video.smaller_width_larger_size_ = true;
585   DefaultConfig();
586   // Disable internal resize for this test.
587   cfg_.rc_resize_allowed = 0;
588   change_bitrate_ = false;
589   mismatch_psnr_ = 0.0;
590   mismatch_nframes_ = 0;
591   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
592
593   for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
594        info != frame_info_list_.end(); ++info) {
595     const unsigned int frame = static_cast<unsigned>(info->pts);
596     unsigned int expected_w;
597     unsigned int expected_h;
598     ScaleForFrameNumber(frame, kInitialWidth, kInitialHeight, &expected_w,
599                         &expected_h, video.flag_codec_,
600                         video.smaller_width_larger_size_);
601     EXPECT_EQ(expected_w, info->w)
602         << "Frame " << frame << " had unexpected width";
603     EXPECT_EQ(expected_h, info->h)
604         << "Frame " << frame << " had unexpected height";
605     EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
606   }
607 }
608
609 // Verify the dynamic resizer behavior for real time, 1 pass CBR mode.
610 // Run at low bitrate, with resize_allowed = 1, and verify that we get
611 // one resize down event.
612 TEST_P(ResizeRealtimeTest, TestInternalResizeDown) {
613   ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
614                                        0, 299);
615   DefaultConfig();
616   cfg_.g_w = 640;
617   cfg_.g_h = 480;
618   change_bitrate_ = false;
619   mismatch_psnr_ = 0.0;
620   mismatch_nframes_ = 0;
621   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
622
623   unsigned int last_w = cfg_.g_w;
624   unsigned int last_h = cfg_.g_h;
625   int resize_count = 0;
626   for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
627        info != frame_info_list_.end(); ++info) {
628     if (info->w != last_w || info->h != last_h) {
629       // Verify that resize down occurs.
630       ASSERT_LT(info->w, last_w);
631       ASSERT_LT(info->h, last_h);
632       last_w = info->w;
633       last_h = info->h;
634       resize_count++;
635     }
636   }
637
638 #if CONFIG_VP9_DECODER
639   // Verify that we get 1 resize down event in this test.
640   ASSERT_EQ(1, resize_count) << "Resizing should occur.";
641   EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
642 #else
643   printf("Warning: VP9 decoder unavailable, unable to check resize count!\n");
644 #endif
645 }
646
647 // Verify the dynamic resizer behavior for real time, 1 pass CBR mode.
648 // Start at low target bitrate, raise the bitrate in the middle of the clip,
649 // scaling-up should occur after bitrate changed.
650 TEST_P(ResizeRealtimeTest, TestInternalResizeDownUpChangeBitRate) {
651   ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
652                                        0, 400);
653   DefaultConfig();
654   cfg_.g_w = 640;
655   cfg_.g_h = 480;
656   change_bitrate_ = true;
657   mismatch_psnr_ = 0.0;
658   mismatch_nframes_ = 0;
659   // Disable dropped frames.
660   cfg_.rc_dropframe_thresh = 0;
661   // Starting bitrate low.
662   cfg_.rc_target_bitrate = 80;
663   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
664
665   unsigned int last_w = cfg_.g_w;
666   unsigned int last_h = cfg_.g_h;
667   int resize_count = 0;
668   for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
669        info != frame_info_list_.end(); ++info) {
670     const size_t idx = info - frame_info_list_.begin();
671     ASSERT_EQ(info->w, GetFrameWidth(idx));
672     ASSERT_EQ(info->h, GetFrameHeight(idx));
673     if (info->w != last_w || info->h != last_h) {
674       resize_count++;
675       if (resize_count <= 2) {
676         // Verify that resize down occurs.
677         ASSERT_LT(info->w, last_w);
678         ASSERT_LT(info->h, last_h);
679       } else if (resize_count > 2) {
680         // Verify that resize up occurs.
681         ASSERT_GT(info->w, last_w);
682         ASSERT_GT(info->h, last_h);
683       }
684       last_w = info->w;
685       last_h = info->h;
686     }
687   }
688
689 #if CONFIG_VP9_DECODER
690   // Verify that we get 4 resize events in this test.
691   ASSERT_EQ(resize_count, 4) << "Resizing should occur twice.";
692   EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
693 #else
694   printf("Warning: VP9 decoder unavailable, unable to check resize count!\n");
695 #endif
696 }
697
698 vpx_img_fmt_t CspForFrameNumber(int frame) {
699   if (frame < 10) return VPX_IMG_FMT_I420;
700   if (frame < 20) return VPX_IMG_FMT_I444;
701   return VPX_IMG_FMT_I420;
702 }
703
704 class ResizeCspTest : public ResizeTest {
705  protected:
706 #if WRITE_COMPRESSED_STREAM
707   ResizeCspTest()
708       : ResizeTest(), frame0_psnr_(0.0), outfile_(nullptr), out_frames_(0) {}
709 #else
710   ResizeCspTest() : ResizeTest(), frame0_psnr_(0.0) {}
711 #endif
712
713   virtual ~ResizeCspTest() {}
714
715   virtual void BeginPassHook(unsigned int /*pass*/) {
716 #if WRITE_COMPRESSED_STREAM
717     outfile_ = fopen("vp91-2-05-cspchape.ivf", "wb");
718 #endif
719   }
720
721   virtual void EndPassHook() {
722 #if WRITE_COMPRESSED_STREAM
723     if (outfile_) {
724       if (!fseek(outfile_, 0, SEEK_SET))
725         write_ivf_file_header(&cfg_, out_frames_, outfile_);
726       fclose(outfile_);
727       outfile_ = nullptr;
728     }
729 #endif
730   }
731
732   virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
733                                   libvpx_test::Encoder *encoder) {
734     if (CspForFrameNumber(video->frame()) != VPX_IMG_FMT_I420 &&
735         cfg_.g_profile != 1) {
736       cfg_.g_profile = 1;
737       encoder->Config(&cfg_);
738     }
739     if (CspForFrameNumber(video->frame()) == VPX_IMG_FMT_I420 &&
740         cfg_.g_profile != 0) {
741       cfg_.g_profile = 0;
742       encoder->Config(&cfg_);
743     }
744   }
745
746   virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
747     if (frame0_psnr_ == 0.) frame0_psnr_ = pkt->data.psnr.psnr[0];
748     EXPECT_NEAR(pkt->data.psnr.psnr[0], frame0_psnr_, 2.0);
749   }
750
751 #if WRITE_COMPRESSED_STREAM
752   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
753     ++out_frames_;
754
755     // Write initial file header if first frame.
756     if (pkt->data.frame.pts == 0) write_ivf_file_header(&cfg_, 0, outfile_);
757
758     // Write frame header and data.
759     write_ivf_frame_header(pkt, outfile_);
760     (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile_);
761   }
762 #endif
763
764   double frame0_psnr_;
765 #if WRITE_COMPRESSED_STREAM
766   FILE *outfile_;
767   unsigned int out_frames_;
768 #endif
769 };
770
771 class ResizingCspVideoSource : public ::libvpx_test::DummyVideoSource {
772  public:
773   ResizingCspVideoSource() {
774     SetSize(kInitialWidth, kInitialHeight);
775     limit_ = 30;
776   }
777
778   virtual ~ResizingCspVideoSource() {}
779
780  protected:
781   virtual void Next() {
782     ++frame_;
783     SetImageFormat(CspForFrameNumber(frame_));
784     FillFrame();
785   }
786 };
787
788 TEST_P(ResizeCspTest, TestResizeCspWorks) {
789   ResizingCspVideoSource video;
790   init_flags_ = VPX_CODEC_USE_PSNR;
791   cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48;
792   cfg_.g_lag_in_frames = 0;
793   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
794 }
795
796 VP8_INSTANTIATE_TEST_SUITE(ResizeTest, ONE_PASS_TEST_MODES);
797 VP9_INSTANTIATE_TEST_SUITE(ResizeTest,
798                            ::testing::Values(::libvpx_test::kRealTime));
799 VP9_INSTANTIATE_TEST_SUITE(ResizeInternalTest,
800                            ::testing::Values(::libvpx_test::kOnePassBest));
801 VP9_INSTANTIATE_TEST_SUITE(ResizeRealtimeTest,
802                            ::testing::Values(::libvpx_test::kRealTime),
803                            ::testing::Range(5, 9));
804 VP9_INSTANTIATE_TEST_SUITE(ResizeCspTest,
805                            ::testing::Values(::libvpx_test::kRealTime));
806 }  // namespace