Home | History | Annotate | Download | only in test
      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, 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:
    248   ResizingVideoSource() {
    249     SetSize(kInitialWidth, kInitialHeight);
    250     limit_ = 350;
    251   }
    252   int flag_codec_;
    253   virtual ~ResizingVideoSource() {}
    254 
    255  protected:
    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:
    271   ResizeTest() : EncoderTest(GET_PARAM(0)) {}
    272 
    273   virtual ~ResizeTest() {}
    274 
    275   virtual void SetUp() {
    276     InitializeConfig();
    277     SetMode(GET_PARAM(1));
    278   }
    279 
    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 
    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)
    302         << "Frame " << frame << " had unexpected width";
    303     EXPECT_EQ(expected_h, info->h)
    304         << "Frame " << frame << " 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
    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 
    320   virtual ~ResizeInternalTest() {}
    321 
    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 
    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 
    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 
    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
    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 
    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 
    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:
    433   ResizeRealtimeTest() : EncoderTest(GET_PARAM(0)) {}
    434   virtual ~ResizeRealtimeTest() {}
    435 
    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 
    450   virtual void SetUp() {
    451     InitializeConfig();
    452     SetMode(GET_PARAM(1));
    453     set_cpu_used_ = GET_PARAM(2);
    454   }
    455 
    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 
    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 
    467   unsigned int GetMismatchFrames() { return mismatch_nframes_; }
    468 
    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 
    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)
    517         << "Frame " << frame << " had unexpected width";
    518     EXPECT_EQ(expected_h, info->h)
    519         << "Frame " << frame << " 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.
    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.
    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 
    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
    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 
    625   virtual ~ResizeCspTest() {}
    626 
    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 
    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 
    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 
    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
    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:
    685   ResizingCspVideoSource() {
    686     SetSize(kInitialWidth, kInitialHeight);
    687     limit_ = 30;
    688   }
    689 
    690   virtual ~ResizingCspVideoSource() {}
    691 
    692  protected:
    693   virtual void Next() {
    694     ++frame_;
    695     SetImageFormat(CspForFrameNumber(frame_));
    696     FillFrame();
    697   }
    698 };
    699 
    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