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
24namespace {
25
26#if WRITE_COMPRESSED_STREAM
27static void mem_put_le16(char *const mem, const unsigned int val) {
28  mem[0] = val;
29  mem[1] = val >> 8;
30}
31
32static 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
39static 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
60static 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
66static 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
82const unsigned int kInitialWidth = 320;
83const unsigned int kInitialHeight = 240;
84
85struct 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
94void 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
246class 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
267class 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
288TEST_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
308const unsigned int kStepDownFrame = 3;
309const unsigned int kStepUpFrame = 6;
310
311class 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
391TEST_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
420TEST_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
429class 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
498TEST_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.
527TEST_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.
565TEST_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
610vpx_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
616class 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
683class 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
700TEST_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
708VP8_INSTANTIATE_TEST_CASE(ResizeTest, ONE_PASS_TEST_MODES);
709VP9_INSTANTIATE_TEST_CASE(ResizeTest,
710                          ::testing::Values(::libvpx_test::kRealTime));
711VP9_INSTANTIATE_TEST_CASE(ResizeInternalTest,
712                          ::testing::Values(::libvpx_test::kOnePassBest));
713VP9_INSTANTIATE_TEST_CASE(ResizeRealtimeTest,
714                          ::testing::Values(::libvpx_test::kRealTime),
715                          ::testing::Range(5, 9));
716VP9_INSTANTIATE_TEST_CASE(ResizeCspTest,
717                          ::testing::Values(::libvpx_test::kRealTime));
718}  // namespace
719