1 /*
2  *  Copyright (c) 2015 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 
11 #include "third_party/googletest/src/include/gtest/gtest.h"
12 
13 #include "test/codec_factory.h"
14 #include "test/encode_test_driver.h"
15 #include "test/util.h"
16 #include "test/y4m_video_source.h"
17 #include "test/yuv_video_source.h"
18 #include "vp9/encoder/vp9_ratectrl.h"
19 
20 namespace {
21 
22 const unsigned int kFrames = 100;
23 const int kBitrate = 500;
24 
25 #define ARF_NOT_SEEN               1000001
26 #define ARF_SEEN_ONCE              1000000
27 
28 typedef struct {
29   const char *filename;
30   unsigned int width;
31   unsigned int height;
32   unsigned int framerate_num;
33   unsigned int framerate_den;
34   unsigned int input_bit_depth;
35   vpx_img_fmt fmt;
36   vpx_bit_depth_t bit_depth;
37   unsigned int profile;
38 } TestVideoParam;
39 
40 typedef struct {
41   libvpx_test::TestMode mode;
42   int cpu_used;
43 } TestEncodeParam;
44 
45 const TestVideoParam kTestVectors[] = {
46   // artificially increase framerate to trigger default check
47   {"hantro_collage_w352h288.yuv", 352, 288, 5000, 1,
48     8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
49   {"hantro_collage_w352h288.yuv", 352, 288, 30, 1,
50     8, VPX_IMG_FMT_I420, VPX_BITS_8, 0},
51   {"rush_hour_444.y4m", 352, 288, 30, 1,
52     8, VPX_IMG_FMT_I444, VPX_BITS_8, 1},
53 #if CONFIG_VP9_HIGHBITDEPTH
54   // Add list of profile 2/3 test videos here ...
55 #endif  // CONFIG_VP9_HIGHBITDEPTH
56 };
57 
58 const TestEncodeParam kEncodeVectors[] = {
59   {::libvpx_test::kOnePassGood, 2},
60   {::libvpx_test::kOnePassGood, 5},
61   {::libvpx_test::kTwoPassGood, 1},
62   {::libvpx_test::kTwoPassGood, 2},
63   {::libvpx_test::kTwoPassGood, 5},
64   {::libvpx_test::kRealTime, 5},
65 };
66 
67 const int kMinArfVectors[] = {
68   // NOTE: 0 refers to the default built-in logic in:
69   //       vp9_rc_get_default_min_gf_interval(...)
70   0, 4, 8, 12, 15
71 };
72 
is_extension_y4m(const char * filename)73 int is_extension_y4m(const char *filename) {
74   const char *dot = strrchr(filename, '.');
75   if (!dot || dot == filename)
76     return 0;
77   else
78     return !strcmp(dot, ".y4m");
79 }
80 
81 class ArfFreqTest
82     : public ::libvpx_test::EncoderTest,
83       public ::libvpx_test::CodecTestWith3Params<TestVideoParam, \
84                                                  TestEncodeParam, int> {
85  protected:
ArfFreqTest()86   ArfFreqTest()
87       : EncoderTest(GET_PARAM(0)),
88         test_video_param_(GET_PARAM(1)),
89         test_encode_param_(GET_PARAM(2)),
90         min_arf_requested_(GET_PARAM(3)) {
91   }
92 
~ArfFreqTest()93   virtual ~ArfFreqTest() {}
94 
SetUp()95   virtual void SetUp() {
96     InitializeConfig();
97     SetMode(test_encode_param_.mode);
98     if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
99       cfg_.g_lag_in_frames = 25;
100       cfg_.rc_end_usage = VPX_VBR;
101     } else {
102       cfg_.g_lag_in_frames = 0;
103       cfg_.rc_end_usage = VPX_CBR;
104       cfg_.rc_buf_sz = 1000;
105       cfg_.rc_buf_initial_sz = 500;
106       cfg_.rc_buf_optimal_sz = 600;
107     }
108     dec_cfg_.threads = 4;
109   }
110 
BeginPassHook(unsigned int)111   virtual void BeginPassHook(unsigned int) {
112     min_run_ = ARF_NOT_SEEN;
113     run_of_visible_frames_ = 0;
114   }
115 
GetNumFramesInPkt(const vpx_codec_cx_pkt_t * pkt)116   int GetNumFramesInPkt(const vpx_codec_cx_pkt_t *pkt) {
117     const uint8_t *buffer = reinterpret_cast<uint8_t*>(pkt->data.frame.buf);
118     const uint8_t marker = buffer[pkt->data.frame.sz - 1];
119     const int mag = ((marker >> 3) & 3) + 1;
120     int frames = (marker & 0x7) + 1;
121     const unsigned int index_sz = 2 + mag  * frames;
122     // Check for superframe or not.
123     // Assume superframe has only one visible frame, the rest being
124     // invisible. If superframe index is not found, then there is only
125     // one frame.
126     if (!((marker & 0xe0) == 0xc0 &&
127           pkt->data.frame.sz >= index_sz &&
128           buffer[pkt->data.frame.sz - index_sz] == marker)) {
129       frames = 1;
130     }
131     return frames;
132   }
133 
FramePktHook(const vpx_codec_cx_pkt_t * pkt)134   virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
135     if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
136       return;
137     const int frames = GetNumFramesInPkt(pkt);
138     if (frames == 1) {
139       run_of_visible_frames_++;
140     } else if (frames == 2) {
141       if (min_run_ == ARF_NOT_SEEN) {
142         min_run_ = ARF_SEEN_ONCE;
143       } else if (min_run_ == ARF_SEEN_ONCE ||
144                  run_of_visible_frames_ < min_run_) {
145         min_run_ = run_of_visible_frames_;
146       }
147       run_of_visible_frames_ = 1;
148     } else {
149       min_run_ = 0;
150       run_of_visible_frames_ = 1;
151     }
152   }
153 
PreEncodeFrameHook(::libvpx_test::VideoSource * video,::libvpx_test::Encoder * encoder)154   virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
155                                   ::libvpx_test::Encoder *encoder) {
156     if (video->frame() == 0) {
157       encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
158       encoder->Control(VP9E_SET_TILE_COLUMNS, 4);
159       encoder->Control(VP8E_SET_CPUUSED, test_encode_param_.cpu_used);
160       encoder->Control(VP9E_SET_MIN_GF_INTERVAL, min_arf_requested_);
161       if (test_encode_param_.mode != ::libvpx_test::kRealTime) {
162         encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
163         encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
164         encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
165         encoder->Control(VP8E_SET_ARNR_TYPE, 3);
166       }
167     }
168   }
169 
GetMinVisibleRun() const170   int GetMinVisibleRun() const {
171     return min_run_;
172   }
173 
GetMinArfDistanceRequested() const174   int GetMinArfDistanceRequested() const {
175     if (min_arf_requested_)
176       return min_arf_requested_;
177     else
178       return vp9_rc_get_default_min_gf_interval(
179           test_video_param_.width, test_video_param_.height,
180           (double)test_video_param_.framerate_num /
181           test_video_param_.framerate_den);
182   }
183 
184   TestVideoParam test_video_param_;
185   TestEncodeParam test_encode_param_;
186 
187  private:
188   int min_arf_requested_;
189   int min_run_;
190   int run_of_visible_frames_;
191 };
192 
TEST_P(ArfFreqTest,MinArfFreqTest)193 TEST_P(ArfFreqTest, MinArfFreqTest) {
194   cfg_.rc_target_bitrate = kBitrate;
195   cfg_.g_error_resilient = 0;
196   cfg_.g_profile = test_video_param_.profile;
197   cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
198   cfg_.g_bit_depth = test_video_param_.bit_depth;
199   init_flags_ = VPX_CODEC_USE_PSNR;
200   if (cfg_.g_bit_depth > 8)
201     init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;
202 
203   libvpx_test::VideoSource *video;
204   if (is_extension_y4m(test_video_param_.filename)) {
205     video = new libvpx_test::Y4mVideoSource(test_video_param_.filename,
206                                             0, kFrames);
207   } else {
208     video = new libvpx_test::YUVVideoSource(test_video_param_.filename,
209                                             test_video_param_.fmt,
210                                             test_video_param_.width,
211                                             test_video_param_.height,
212                                             test_video_param_.framerate_num,
213                                             test_video_param_.framerate_den,
214                                             0, kFrames);
215   }
216 
217   ASSERT_NO_FATAL_FAILURE(RunLoop(video));
218   const int min_run = GetMinVisibleRun();
219   const int min_arf_dist_requested = GetMinArfDistanceRequested();
220   if (min_run != ARF_NOT_SEEN && min_run != ARF_SEEN_ONCE) {
221     const int min_arf_dist = min_run + 1;
222     EXPECT_GE(min_arf_dist, min_arf_dist_requested);
223   }
224   delete(video);
225 }
226 
227 VP9_INSTANTIATE_TEST_CASE(
228     ArfFreqTest,
229     ::testing::ValuesIn(kTestVectors),
230     ::testing::ValuesIn(kEncodeVectors),
231     ::testing::ValuesIn(kMinArfVectors));
232 
233 #if CONFIG_VP9_HIGHBITDEPTH
234 # if CONFIG_VP10_ENCODER
235 // TODO(angiebird): 25-29 fail in high bitdepth mode.
236 INSTANTIATE_TEST_CASE_P(
237     DISABLED_VP10, ArfFreqTest,
238     ::testing::Combine(
239         ::testing::Values(static_cast<const libvpx_test::CodecFactory *>(
240             &libvpx_test::kVP10)),
241         ::testing::ValuesIn(kTestVectors),
242         ::testing::ValuesIn(kEncodeVectors),
243         ::testing::ValuesIn(kMinArfVectors)));
244 # endif  // CONFIG_VP10_ENCODER
245 #else
246 VP10_INSTANTIATE_TEST_CASE(
247     ArfFreqTest,
248     ::testing::ValuesIn(kTestVectors),
249     ::testing::ValuesIn(kEncodeVectors),
250     ::testing::ValuesIn(kMinArfVectors));
251 #endif  // CONFIG_VP9_HIGHBITDEPTH
252 }  // namespace
253