2 * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
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.
10 #include "vp9/ratectrl_rtc.h"
12 #include <fstream> // NOLINT
15 #include "./vpx_config.h"
16 #include "third_party/googletest/src/include/gtest/gtest.h"
17 #include "test/codec_factory.h"
18 #include "test/encode_test_driver.h"
19 #include "test/i420_video_source.h"
20 #include "test/util.h"
21 #include "test/video_source.h"
22 #include "vpx/vpx_codec.h"
23 #include "vpx_ports/bitops.h"
27 const size_t kNumFrames = 300;
29 const int kTemporalId[4] = { 0, 2, 1, 2 };
32 : public ::libvpx_test::EncoderTest,
33 public ::libvpx_test::CodecTestWith2Params<int, vpx_rc_mode> {
36 : EncoderTest(GET_PARAM(0)), aq_mode_(GET_PARAM(1)), key_interval_(3000),
37 encoder_exit_(false) {}
39 virtual ~RcInterfaceTest() {}
42 virtual void SetUp() {
44 SetMode(::libvpx_test::kRealTime);
47 virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
48 libvpx_test::Encoder *encoder) {
49 if (video->frame() == 0) {
50 encoder->Control(VP8E_SET_CPUUSED, 7);
51 encoder->Control(VP9E_SET_AQ_MODE, aq_mode_);
52 encoder->Control(VP9E_SET_TUNE_CONTENT, 0);
53 encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 1000);
54 encoder->Control(VP9E_SET_RTC_EXTERNAL_RATECTRL, 1);
56 frame_params_.frame_type =
57 video->frame() % key_interval_ == 0 ? KEY_FRAME : INTER_FRAME;
58 if (rc_cfg_.rc_mode == VPX_CBR && frame_params_.frame_type == INTER_FRAME) {
59 // Disable golden frame update.
60 frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
61 frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
63 encoder_exit_ = video->frame() == kNumFrames;
66 virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
70 int loopfilter_level, qp;
71 encoder->Control(VP9E_GET_LOOPFILTER_LEVEL, &loopfilter_level);
72 encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
73 rc_api_->ComputeQP(frame_params_);
74 ASSERT_EQ(rc_api_->GetQP(), qp);
75 ASSERT_EQ(rc_api_->GetLoopfilterLevel(), loopfilter_level);
78 virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
79 rc_api_->PostEncodeUpdate(pkt->data.frame.sz);
83 SetConfig(GET_PARAM(2));
84 rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
85 frame_params_.spatial_layer_id = 0;
86 frame_params_.temporal_layer_id = 0;
88 ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
89 1280, 720, 30, 1, 0, kNumFrames);
91 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
94 void RunOneLayerVBRPeriodicKey() {
95 if (GET_PARAM(2) != VPX_VBR) return;
98 rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
99 frame_params_.spatial_layer_id = 0;
100 frame_params_.temporal_layer_id = 0;
102 ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
103 1280, 720, 30, 1, 0, kNumFrames);
105 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
109 void SetConfig(vpx_rc_mode rc_mode) {
110 rc_cfg_.width = 1280;
111 rc_cfg_.height = 720;
112 rc_cfg_.max_quantizer = 52;
113 rc_cfg_.min_quantizer = 2;
114 rc_cfg_.target_bandwidth = 1000;
115 rc_cfg_.buf_initial_sz = 600;
116 rc_cfg_.buf_optimal_sz = 600;
117 rc_cfg_.buf_sz = 1000;
118 rc_cfg_.undershoot_pct = 50;
119 rc_cfg_.overshoot_pct = 50;
120 rc_cfg_.max_intra_bitrate_pct = 1000;
121 rc_cfg_.framerate = 30.0;
122 rc_cfg_.ss_number_layers = 1;
123 rc_cfg_.ts_number_layers = 1;
124 rc_cfg_.scaling_factor_num[0] = 1;
125 rc_cfg_.scaling_factor_den[0] = 1;
126 rc_cfg_.layer_target_bitrate[0] = 1000;
127 rc_cfg_.max_quantizers[0] = 52;
128 rc_cfg_.min_quantizers[0] = 2;
129 rc_cfg_.rc_mode = rc_mode;
130 rc_cfg_.aq_mode = aq_mode_;
132 // Encoder settings for ground truth.
135 cfg_.rc_undershoot_pct = 50;
136 cfg_.rc_overshoot_pct = 50;
137 cfg_.rc_buf_initial_sz = 600;
138 cfg_.rc_buf_optimal_sz = 600;
139 cfg_.rc_buf_sz = 1000;
140 cfg_.rc_dropframe_thresh = 0;
141 cfg_.rc_min_quantizer = 2;
142 cfg_.rc_max_quantizer = 52;
143 cfg_.rc_end_usage = rc_mode;
144 cfg_.g_lag_in_frames = 0;
145 cfg_.g_error_resilient = 0;
146 cfg_.rc_target_bitrate = 1000;
147 cfg_.kf_min_dist = key_interval_;
148 cfg_.kf_max_dist = key_interval_;
151 std::unique_ptr<libvpx::VP9RateControlRTC> rc_api_;
152 libvpx::VP9RateControlRtcConfig rc_cfg_;
155 libvpx::VP9FrameParamsQpRTC frame_params_;
159 class RcInterfaceSvcTest : public ::libvpx_test::EncoderTest,
160 public ::libvpx_test::CodecTestWithParam<int> {
162 RcInterfaceSvcTest() : EncoderTest(GET_PARAM(0)), aq_mode_(GET_PARAM(1)) {}
163 virtual ~RcInterfaceSvcTest() {}
166 virtual void SetUp() {
168 SetMode(::libvpx_test::kRealTime);
171 virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
172 ::libvpx_test::Encoder *encoder) {
173 if (video->frame() == 0) {
174 encoder->Control(VP8E_SET_CPUUSED, 7);
175 encoder->Control(VP9E_SET_AQ_MODE, aq_mode_);
176 encoder->Control(VP9E_SET_TUNE_CONTENT, 0);
177 encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 900);
178 encoder->Control(VP9E_SET_RTC_EXTERNAL_RATECTRL, 1);
179 encoder->Control(VP9E_SET_SVC, 1);
180 encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
183 frame_params_.frame_type = video->frame() == 0 ? KEY_FRAME : INTER_FRAME;
184 if (rc_cfg_.rc_mode == VPX_CBR && frame_params_.frame_type == INTER_FRAME) {
185 // Disable golden frame update.
186 frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
187 frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
189 encoder_exit_ = video->frame() == kNumFrames;
190 current_superframe_ = video->frame();
193 virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
194 ::libvpx_test::CxDataIterator iter = encoder->GetCxData();
195 while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
196 ParseSuperframeSizes(static_cast<const uint8_t *>(pkt->data.frame.buf),
198 for (int sl = 0; sl < rc_cfg_.ss_number_layers; sl++) {
199 frame_params_.spatial_layer_id = sl;
200 frame_params_.temporal_layer_id = kTemporalId[current_superframe_ % 4];
201 rc_api_->ComputeQP(frame_params_);
202 frame_params_.frame_type = INTER_FRAME;
203 rc_api_->PostEncodeUpdate(sizes_[sl]);
206 if (!encoder_exit_) {
207 int loopfilter_level, qp;
208 encoder->Control(VP9E_GET_LOOPFILTER_LEVEL, &loopfilter_level);
209 encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
210 ASSERT_EQ(rc_api_->GetQP(), qp);
211 ASSERT_EQ(rc_api_->GetLoopfilterLevel(), loopfilter_level);
214 // This method needs to be overridden because non-reference frames are
215 // expected to be mismatched frames as the encoder will avoid loopfilter on
217 virtual void MismatchHook(const vpx_image_t * /*img1*/,
218 const vpx_image_t * /*img2*/) {}
222 rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
225 ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
226 1280, 720, 30, 1, 0, kNumFrames);
228 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
232 vpx_codec_err_t ParseSuperframeSizes(const uint8_t *data, size_t data_sz) {
233 uint8_t marker = *(data + data_sz - 1);
234 if ((marker & 0xe0) == 0xc0) {
235 const uint32_t frames = (marker & 0x7) + 1;
236 const uint32_t mag = ((marker >> 3) & 0x3) + 1;
237 const size_t index_sz = 2 + mag * frames;
238 // This chunk is marked as having a superframe index but doesn't have
239 // enough data for it, thus it's an invalid superframe index.
240 if (data_sz < index_sz) return VPX_CODEC_CORRUPT_FRAME;
242 const uint8_t marker2 = *(data + data_sz - index_sz);
243 // This chunk is marked as having a superframe index but doesn't have
244 // the matching marker byte at the front of the index therefore it's an
246 if (marker != marker2) return VPX_CODEC_CORRUPT_FRAME;
248 const uint8_t *x = &data[data_sz - index_sz + 1];
249 for (uint32_t i = 0; i < frames; ++i) {
250 uint32_t this_sz = 0;
252 for (uint32_t j = 0; j < mag; ++j) this_sz |= (*x++) << (j * 8);
259 void SetEncoderSvc() {
260 cfg_.ss_number_layers = 3;
261 cfg_.ts_number_layers = 3;
262 cfg_.g_timebase.num = 1;
263 cfg_.g_timebase.den = 30;
264 svc_params_.scaling_factor_num[0] = 72;
265 svc_params_.scaling_factor_den[0] = 288;
266 svc_params_.scaling_factor_num[1] = 144;
267 svc_params_.scaling_factor_den[1] = 288;
268 svc_params_.scaling_factor_num[2] = 288;
269 svc_params_.scaling_factor_den[2] = 288;
270 for (int i = 0; i < VPX_MAX_LAYERS; ++i) {
271 svc_params_.max_quantizers[i] = 56;
272 svc_params_.min_quantizers[i] = 2;
273 svc_params_.speed_per_layer[i] = 7;
275 cfg_.rc_end_usage = VPX_CBR;
276 cfg_.g_lag_in_frames = 0;
277 cfg_.g_error_resilient = 0;
279 cfg_.ts_rate_decimator[0] = 4;
280 cfg_.ts_rate_decimator[1] = 2;
281 cfg_.ts_rate_decimator[2] = 1;
282 cfg_.temporal_layering_mode = 3;
284 cfg_.rc_buf_initial_sz = 500;
285 cfg_.rc_buf_optimal_sz = 600;
286 cfg_.rc_buf_sz = 1000;
287 cfg_.rc_min_quantizer = 2;
288 cfg_.rc_max_quantizer = 56;
290 cfg_.kf_max_dist = 9999;
291 cfg_.rc_target_bitrate = 1600;
292 cfg_.rc_overshoot_pct = 50;
293 cfg_.rc_undershoot_pct = 50;
295 cfg_.layer_target_bitrate[0] = 100;
296 cfg_.layer_target_bitrate[1] = 140;
297 cfg_.layer_target_bitrate[2] = 200;
298 cfg_.layer_target_bitrate[3] = 250;
299 cfg_.layer_target_bitrate[4] = 350;
300 cfg_.layer_target_bitrate[5] = 500;
301 cfg_.layer_target_bitrate[6] = 450;
302 cfg_.layer_target_bitrate[7] = 630;
303 cfg_.layer_target_bitrate[8] = 900;
306 void SetConfigSvc() {
307 rc_cfg_.width = 1280;
308 rc_cfg_.height = 720;
309 rc_cfg_.max_quantizer = 56;
310 rc_cfg_.min_quantizer = 2;
311 rc_cfg_.target_bandwidth = 1600;
312 rc_cfg_.buf_initial_sz = 500;
313 rc_cfg_.buf_optimal_sz = 600;
314 rc_cfg_.buf_sz = 1000;
315 rc_cfg_.undershoot_pct = 50;
316 rc_cfg_.overshoot_pct = 50;
317 rc_cfg_.max_intra_bitrate_pct = 900;
318 rc_cfg_.framerate = 30.0;
319 rc_cfg_.ss_number_layers = 3;
320 rc_cfg_.ts_number_layers = 3;
321 rc_cfg_.rc_mode = VPX_CBR;
322 rc_cfg_.aq_mode = aq_mode_;
324 rc_cfg_.scaling_factor_num[0] = 1;
325 rc_cfg_.scaling_factor_den[0] = 4;
326 rc_cfg_.scaling_factor_num[1] = 2;
327 rc_cfg_.scaling_factor_den[1] = 4;
328 rc_cfg_.scaling_factor_num[2] = 4;
329 rc_cfg_.scaling_factor_den[2] = 4;
331 rc_cfg_.ts_rate_decimator[0] = 4;
332 rc_cfg_.ts_rate_decimator[1] = 2;
333 rc_cfg_.ts_rate_decimator[2] = 1;
335 rc_cfg_.layer_target_bitrate[0] = 100;
336 rc_cfg_.layer_target_bitrate[1] = 140;
337 rc_cfg_.layer_target_bitrate[2] = 200;
338 rc_cfg_.layer_target_bitrate[3] = 250;
339 rc_cfg_.layer_target_bitrate[4] = 350;
340 rc_cfg_.layer_target_bitrate[5] = 500;
341 rc_cfg_.layer_target_bitrate[6] = 450;
342 rc_cfg_.layer_target_bitrate[7] = 630;
343 rc_cfg_.layer_target_bitrate[8] = 900;
345 for (int sl = 0; sl < rc_cfg_.ss_number_layers; ++sl) {
346 for (int tl = 0; tl < rc_cfg_.ts_number_layers; ++tl) {
347 const int i = sl * rc_cfg_.ts_number_layers + tl;
348 rc_cfg_.max_quantizers[i] = 56;
349 rc_cfg_.min_quantizers[i] = 2;
355 std::unique_ptr<libvpx::VP9RateControlRTC> rc_api_;
356 libvpx::VP9RateControlRtcConfig rc_cfg_;
357 vpx_svc_extra_cfg_t svc_params_;
358 libvpx::VP9FrameParamsQpRTC frame_params_;
360 int current_superframe_;
364 TEST_P(RcInterfaceTest, OneLayer) { RunOneLayer(); }
366 TEST_P(RcInterfaceTest, OneLayerVBRPeriodicKey) { RunOneLayerVBRPeriodicKey(); }
368 TEST_P(RcInterfaceSvcTest, Svc) { RunSvc(); }
370 VP9_INSTANTIATE_TEST_SUITE(RcInterfaceTest, ::testing::Values(0, 3),
371 ::testing::Values(VPX_CBR, VPX_VBR));
372 VP9_INSTANTIATE_TEST_SUITE(RcInterfaceSvcTest, ::testing::Values(0, 3));