• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2021 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 <fstream>  // NOLINT
12 #include <string>
13 
14 #include "./vpx_config.h"
15 #include "third_party/googletest/src/include/gtest/gtest.h"
16 #include "test/codec_factory.h"
17 #include "test/encode_test_driver.h"
18 #include "test/i420_video_source.h"
19 #include "test/util.h"
20 #include "test/video_source.h"
21 #include "vp8/vp8_ratectrl_rtc.h"
22 #include "vpx/vpx_codec.h"
23 #include "vpx_ports/bitops.h"
24 
25 namespace {
26 
27 struct Vp8RCTestVideo {
28   Vp8RCTestVideo() = default;
Vp8RCTestVideo__anondd2254110111::Vp8RCTestVideo29   Vp8RCTestVideo(const char *name_, int width_, int height_,
30                  unsigned int frames_)
31       : name(name_), width(width_), height(height_), frames(frames_) {}
32 
operator <<(std::ostream & os,const Vp8RCTestVideo & video)33   friend std::ostream &operator<<(std::ostream &os,
34                                   const Vp8RCTestVideo &video) {
35     os << video.name << " " << video.width << " " << video.height << " "
36        << video.frames;
37     return os;
38   }
39   const char *name;
40   int width;
41   int height;
42   unsigned int frames;
43 };
44 
45 const Vp8RCTestVideo kVp8RCTestVectors[] = {
46   Vp8RCTestVideo("niklas_640_480_30.yuv", 640, 480, 470),
47   Vp8RCTestVideo("desktop_office1.1280_720-020.yuv", 1280, 720, 300),
48 };
49 
50 class Vp8RcInterfaceTest
51     : public ::libvpx_test::EncoderTest,
52       public ::libvpx_test::CodecTestWith2Params<int, Vp8RCTestVideo> {
53  public:
Vp8RcInterfaceTest()54   Vp8RcInterfaceTest()
55       : EncoderTest(GET_PARAM(0)), key_interval_(3000), encoder_exit_(false),
56         frame_drop_thresh_(0) {}
57   ~Vp8RcInterfaceTest() override = default;
58 
59  protected:
SetUp()60   void SetUp() override {
61     InitializeConfig();
62     SetMode(::libvpx_test::kRealTime);
63   }
64 
65   // From error_resilience_test.cc
SetFrameFlags(int frame_num,int num_temp_layers)66   int SetFrameFlags(int frame_num, int num_temp_layers) {
67     int frame_flags = 0;
68     if (num_temp_layers == 2) {
69       if (frame_num % 2 == 0) {
70         // Layer 0: predict from L and ARF, update L.
71         frame_flags =
72             VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
73       } else {
74         // Layer 1: predict from L, G and ARF, and update G.
75         frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
76                       VP8_EFLAG_NO_UPD_ENTROPY;
77       }
78     } else if (num_temp_layers == 3) {
79       if (frame_num % 4 == 0) {
80         // Layer 0: predict from L, update L.
81         frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
82                       VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
83       } else if ((frame_num - 2) % 4 == 0) {
84         // Layer 1: predict from L, G,  update G.
85         frame_flags =
86             VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF;
87       } else if ((frame_num - 1) % 2 == 0) {
88         // Layer 2: predict from L, G, ARF; update ARG.
89         frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
90       }
91     }
92     return frame_flags;
93   }
94 
SetLayerId(int frame_num,int num_temp_layers)95   int SetLayerId(int frame_num, int num_temp_layers) {
96     int layer_id = 0;
97     if (num_temp_layers == 2) {
98       if (frame_num % 2 == 0) {
99         layer_id = 0;
100       } else {
101         layer_id = 1;
102       }
103     } else if (num_temp_layers == 3) {
104       if (frame_num % 4 == 0) {
105         layer_id = 0;
106       } else if ((frame_num - 2) % 4 == 0) {
107         layer_id = 1;
108       } else if ((frame_num - 1) % 2 == 0) {
109         layer_id = 2;
110       }
111     }
112     return layer_id;
113   }
114 
PreEncodeFrameHook(::libvpx_test::VideoSource * video,::libvpx_test::Encoder * encoder)115   void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
116                           ::libvpx_test::Encoder *encoder) override {
117     if (rc_cfg_.ts_number_layers > 1) {
118       const int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers);
119       const int frame_flags =
120           SetFrameFlags(video->frame(), cfg_.ts_number_layers);
121       frame_params_.temporal_layer_id = layer_id;
122       if (video->frame() > 0) {
123         encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
124         encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags);
125       }
126     } else {
127       if (video->frame() == 0) {
128         encoder->Control(VP8E_SET_CPUUSED, -6);
129         encoder->Control(VP8E_SET_RTC_EXTERNAL_RATECTRL, 1);
130         encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 1000);
131       } else if (frame_params_.frame_type == libvpx::RcFrameType::kInterFrame) {
132         // Disable golden frame update.
133         frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
134         frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
135       }
136     }
137     frame_params_.frame_type = video->frame() % key_interval_ == 0
138                                    ? libvpx::RcFrameType::kKeyFrame
139                                    : libvpx::RcFrameType::kInterFrame;
140     encoder_exit_ = video->frame() == test_video_.frames;
141   }
142 
PostEncodeFrameHook(::libvpx_test::Encoder * encoder)143   void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) override {
144     if (encoder_exit_) {
145       return;
146     }
147     int qp;
148     encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
149     if (rc_api_->ComputeQP(frame_params_) == libvpx::FrameDropDecision::kOk) {
150       ASSERT_EQ(rc_api_->GetQP(), qp);
151     } else {
152       num_drops_++;
153     }
154   }
155 
FramePktHook(const vpx_codec_cx_pkt_t * pkt)156   void FramePktHook(const vpx_codec_cx_pkt_t *pkt) override {
157     rc_api_->PostEncodeUpdate(pkt->data.frame.sz);
158   }
159 
RunOneLayer()160   void RunOneLayer() {
161     test_video_ = GET_PARAM(2);
162     target_bitrate_ = GET_PARAM(1);
163     SetConfig();
164     rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
165     ASSERT_TRUE(rc_api_->UpdateRateControl(rc_cfg_));
166 
167     ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
168                                          test_video_.height, 30, 1, 0,
169                                          test_video_.frames);
170 
171     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
172   }
173 
RunOneLayerDropFrames()174   void RunOneLayerDropFrames() {
175     test_video_ = GET_PARAM(2);
176     target_bitrate_ = GET_PARAM(1);
177     frame_drop_thresh_ = 30;
178     num_drops_ = 0;
179     // Use lower target_bitrate and max_quantizer to trigger drops.
180     target_bitrate_ = target_bitrate_ >> 2;
181     SetConfig();
182     rc_cfg_.max_quantizer = 56;
183     cfg_.rc_max_quantizer = 56;
184     rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
185     ASSERT_TRUE(rc_api_->UpdateRateControl(rc_cfg_));
186 
187     ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
188                                          test_video_.height, 30, 1, 0,
189                                          test_video_.frames);
190 
191     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
192     // Check that some frames were dropped, otherwise test has no value.
193     ASSERT_GE(num_drops_, 1);
194   }
195 
RunPeriodicKey()196   void RunPeriodicKey() {
197     test_video_ = GET_PARAM(2);
198     target_bitrate_ = GET_PARAM(1);
199     key_interval_ = 100;
200     frame_drop_thresh_ = 30;
201     SetConfig();
202     rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
203     ASSERT_TRUE(rc_api_->UpdateRateControl(rc_cfg_));
204 
205     ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
206                                          test_video_.height, 30, 1, 0,
207                                          test_video_.frames);
208 
209     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
210   }
211 
RunTemporalLayers2TL()212   void RunTemporalLayers2TL() {
213     test_video_ = GET_PARAM(2);
214     target_bitrate_ = GET_PARAM(1);
215     SetConfigTemporalLayers(2);
216     rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
217     ASSERT_TRUE(rc_api_->UpdateRateControl(rc_cfg_));
218 
219     ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
220                                          test_video_.height, 30, 1, 0,
221                                          test_video_.frames);
222 
223     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
224   }
225 
RunTemporalLayers3TL()226   void RunTemporalLayers3TL() {
227     test_video_ = GET_PARAM(2);
228     target_bitrate_ = GET_PARAM(1);
229     SetConfigTemporalLayers(3);
230     rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
231     ASSERT_TRUE(rc_api_->UpdateRateControl(rc_cfg_));
232 
233     ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
234                                          test_video_.height, 30, 1, 0,
235                                          test_video_.frames);
236 
237     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
238   }
239 
RunTemporalLayers3TLDropFrames()240   void RunTemporalLayers3TLDropFrames() {
241     test_video_ = GET_PARAM(2);
242     target_bitrate_ = GET_PARAM(1);
243     frame_drop_thresh_ = 30;
244     num_drops_ = 0;
245     // Use lower target_bitrate and max_quantizer to trigger drops.
246     target_bitrate_ = target_bitrate_ >> 2;
247     SetConfigTemporalLayers(3);
248     rc_cfg_.max_quantizer = 56;
249     cfg_.rc_max_quantizer = 56;
250     rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
251     ASSERT_TRUE(rc_api_->UpdateRateControl(rc_cfg_));
252 
253     ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
254                                          test_video_.height, 30, 1, 0,
255                                          test_video_.frames);
256 
257     ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
258     // Check that some frames were dropped, otherwise test has no value.
259     ASSERT_GE(num_drops_, 1);
260   }
261 
262  private:
SetConfig()263   void SetConfig() {
264     rc_cfg_.width = test_video_.width;
265     rc_cfg_.height = test_video_.height;
266     rc_cfg_.max_quantizer = 60;
267     rc_cfg_.min_quantizer = 2;
268     rc_cfg_.target_bandwidth = target_bitrate_;
269     rc_cfg_.buf_initial_sz = 600;
270     rc_cfg_.buf_optimal_sz = 600;
271     rc_cfg_.buf_sz = target_bitrate_;
272     rc_cfg_.undershoot_pct = 50;
273     rc_cfg_.overshoot_pct = 50;
274     rc_cfg_.max_intra_bitrate_pct = 1000;
275     rc_cfg_.framerate = 30.0;
276     rc_cfg_.layer_target_bitrate[0] = target_bitrate_;
277     rc_cfg_.frame_drop_thresh = frame_drop_thresh_;
278 
279     // Encoder settings for ground truth.
280     cfg_.g_w = test_video_.width;
281     cfg_.g_h = test_video_.height;
282     cfg_.rc_undershoot_pct = 50;
283     cfg_.rc_overshoot_pct = 50;
284     cfg_.rc_buf_initial_sz = 600;
285     cfg_.rc_buf_optimal_sz = 600;
286     cfg_.rc_buf_sz = target_bitrate_;
287     cfg_.rc_dropframe_thresh = 0;
288     cfg_.rc_min_quantizer = 2;
289     cfg_.rc_max_quantizer = 60;
290     cfg_.rc_end_usage = VPX_CBR;
291     cfg_.g_lag_in_frames = 0;
292     cfg_.g_error_resilient = 1;
293     cfg_.rc_target_bitrate = target_bitrate_;
294     cfg_.kf_min_dist = key_interval_;
295     cfg_.kf_max_dist = key_interval_;
296     cfg_.rc_dropframe_thresh = frame_drop_thresh_;
297   }
298 
SetConfigTemporalLayers(int temporal_layers)299   void SetConfigTemporalLayers(int temporal_layers) {
300     rc_cfg_.width = test_video_.width;
301     rc_cfg_.height = test_video_.height;
302     rc_cfg_.max_quantizer = 60;
303     rc_cfg_.min_quantizer = 2;
304     rc_cfg_.target_bandwidth = target_bitrate_;
305     rc_cfg_.buf_initial_sz = 600;
306     rc_cfg_.buf_optimal_sz = 600;
307     rc_cfg_.buf_sz = target_bitrate_;
308     rc_cfg_.undershoot_pct = 50;
309     rc_cfg_.overshoot_pct = 50;
310     rc_cfg_.max_intra_bitrate_pct = 1000;
311     rc_cfg_.framerate = 30.0;
312     rc_cfg_.frame_drop_thresh = frame_drop_thresh_;
313     if (temporal_layers == 2) {
314       rc_cfg_.layer_target_bitrate[0] = 60 * target_bitrate_ / 100;
315       rc_cfg_.layer_target_bitrate[1] = target_bitrate_;
316       rc_cfg_.ts_rate_decimator[0] = 2;
317       rc_cfg_.ts_rate_decimator[1] = 1;
318     } else if (temporal_layers == 3) {
319       rc_cfg_.layer_target_bitrate[0] = 40 * target_bitrate_ / 100;
320       rc_cfg_.layer_target_bitrate[1] = 60 * target_bitrate_ / 100;
321       rc_cfg_.layer_target_bitrate[2] = target_bitrate_;
322       rc_cfg_.ts_rate_decimator[0] = 4;
323       rc_cfg_.ts_rate_decimator[1] = 2;
324       rc_cfg_.ts_rate_decimator[2] = 1;
325     }
326 
327     rc_cfg_.ts_number_layers = temporal_layers;
328 
329     // Encoder settings for ground truth.
330     cfg_.g_w = test_video_.width;
331     cfg_.g_h = test_video_.height;
332     cfg_.rc_undershoot_pct = 50;
333     cfg_.rc_overshoot_pct = 50;
334     cfg_.rc_buf_initial_sz = 600;
335     cfg_.rc_buf_optimal_sz = 600;
336     cfg_.rc_buf_sz = target_bitrate_;
337     cfg_.rc_dropframe_thresh = 0;
338     cfg_.rc_min_quantizer = 2;
339     cfg_.rc_max_quantizer = 60;
340     cfg_.rc_end_usage = VPX_CBR;
341     cfg_.g_lag_in_frames = 0;
342     cfg_.g_error_resilient = 1;
343     cfg_.rc_target_bitrate = target_bitrate_;
344     cfg_.kf_min_dist = key_interval_;
345     cfg_.kf_max_dist = key_interval_;
346     cfg_.rc_dropframe_thresh = frame_drop_thresh_;
347     // 2 Temporal layers, no spatial layers, CBR mode.
348     cfg_.ss_number_layers = 1;
349     cfg_.ts_number_layers = temporal_layers;
350     if (temporal_layers == 2) {
351       cfg_.ts_rate_decimator[0] = 2;
352       cfg_.ts_rate_decimator[1] = 1;
353       cfg_.ts_periodicity = 2;
354       cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
355       cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
356     } else if (temporal_layers == 3) {
357       cfg_.ts_rate_decimator[0] = 4;
358       cfg_.ts_rate_decimator[1] = 2;
359       cfg_.ts_rate_decimator[2] = 1;
360       cfg_.ts_periodicity = 4;
361       cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
362       cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
363       cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
364     }
365   }
366 
367   std::unique_ptr<libvpx::VP8RateControlRTC> rc_api_;
368   libvpx::VP8RateControlRtcConfig rc_cfg_;
369   int key_interval_;
370   int target_bitrate_;
371   Vp8RCTestVideo test_video_;
372   libvpx::VP8FrameParamsQpRTC frame_params_;
373   bool encoder_exit_;
374   int frame_drop_thresh_;
375   int num_drops_;
376 };
377 
TEST_P(Vp8RcInterfaceTest,OneLayer)378 TEST_P(Vp8RcInterfaceTest, OneLayer) { RunOneLayer(); }
379 
TEST_P(Vp8RcInterfaceTest,OneLayerDropFrames)380 TEST_P(Vp8RcInterfaceTest, OneLayerDropFrames) { RunOneLayerDropFrames(); }
381 
TEST_P(Vp8RcInterfaceTest,OneLayerPeriodicKey)382 TEST_P(Vp8RcInterfaceTest, OneLayerPeriodicKey) { RunPeriodicKey(); }
383 
TEST_P(Vp8RcInterfaceTest,TemporalLayers2TL)384 TEST_P(Vp8RcInterfaceTest, TemporalLayers2TL) { RunTemporalLayers2TL(); }
385 
TEST_P(Vp8RcInterfaceTest,TemporalLayers3TL)386 TEST_P(Vp8RcInterfaceTest, TemporalLayers3TL) { RunTemporalLayers3TL(); }
387 
TEST_P(Vp8RcInterfaceTest,TemporalLayers3TLDropFrames)388 TEST_P(Vp8RcInterfaceTest, TemporalLayers3TLDropFrames) {
389   RunTemporalLayers3TLDropFrames();
390 }
391 
392 VP8_INSTANTIATE_TEST_SUITE(Vp8RcInterfaceTest,
393                            ::testing::Values(200, 400, 1000),
394                            ::testing::ValuesIn(kVp8RCTestVectors));
395 
396 }  // namespace
397