2 * Copyright (c) 2021 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.
11 #include <fstream> // NOLINT
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"
27 struct Vp8RCTestVideo {
29 Vp8RCTestVideo(const char *name_, int width_, int height_,
31 : name(name_), width(width_), height(height_), frames(frames_) {}
33 friend std::ostream &operator<<(std::ostream &os,
34 const Vp8RCTestVideo &video) {
35 os << video.name << " " << video.width << " " << video.height << " "
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),
50 class Vp8RcInterfaceTest
51 : public ::libvpx_test::EncoderTest,
52 public ::libvpx_test::CodecTestWith2Params<int, Vp8RCTestVideo> {
55 : EncoderTest(GET_PARAM(0)), key_interval_(3000), encoder_exit_(false) {}
56 virtual ~Vp8RcInterfaceTest() {}
59 virtual void SetUp() {
61 SetMode(::libvpx_test::kRealTime);
64 // From error_resilience_test.cc
65 int SetFrameFlags(int frame_num, int num_temp_layers) {
67 if (num_temp_layers == 2) {
68 if (frame_num % 2 == 0) {
69 // Layer 0: predict from L and ARF, update L.
71 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF;
73 // Layer 1: predict from L, G and ARF, and update G.
74 frame_flags = VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST |
75 VP8_EFLAG_NO_UPD_ENTROPY;
77 } else if (num_temp_layers == 3) {
78 if (frame_num % 4 == 0) {
79 // Layer 0: predict from L, update L.
80 frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF |
81 VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF;
82 } else if ((frame_num - 2) % 4 == 0) {
83 // Layer 1: predict from L, G, update G.
85 VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_REF_ARF;
86 } else if ((frame_num - 1) % 2 == 0) {
87 // Layer 2: predict from L, G, ARF; update ARG.
88 frame_flags = VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST;
94 int SetLayerId(int frame_num, int num_temp_layers) {
96 if (num_temp_layers == 2) {
97 if (frame_num % 2 == 0) {
102 } else if (num_temp_layers == 3) {
103 if (frame_num % 4 == 0) {
105 } else if ((frame_num - 2) % 4 == 0) {
107 } else if ((frame_num - 1) % 2 == 0) {
114 virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
115 ::libvpx_test::Encoder *encoder) {
116 if (rc_cfg_.ts_number_layers > 1) {
117 const int layer_id = SetLayerId(video->frame(), cfg_.ts_number_layers);
118 const int frame_flags =
119 SetFrameFlags(video->frame(), cfg_.ts_number_layers);
120 frame_params_.temporal_layer_id = layer_id;
121 if (video->frame() > 0) {
122 encoder->Control(VP8E_SET_TEMPORAL_LAYER_ID, layer_id);
123 encoder->Control(VP8E_SET_FRAME_FLAGS, frame_flags);
126 if (video->frame() == 0) {
127 encoder->Control(VP8E_SET_CPUUSED, -6);
128 encoder->Control(VP8E_SET_RTC_EXTERNAL_RATECTRL, 1);
129 encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 1000);
131 if (frame_params_.frame_type == INTER_FRAME) {
132 // Disable golden frame update.
133 frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
134 frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
137 frame_params_.frame_type =
138 video->frame() % key_interval_ == 0 ? KEY_FRAME : INTER_FRAME;
139 encoder_exit_ = video->frame() == test_video_.frames;
142 virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
147 encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
148 rc_api_->ComputeQP(frame_params_);
149 ASSERT_EQ(rc_api_->GetQP(), qp);
152 virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
153 rc_api_->PostEncodeUpdate(pkt->data.frame.sz);
157 test_video_ = GET_PARAM(2);
158 target_bitrate_ = GET_PARAM(1);
159 if (test_video_.width == 1280 && target_bitrate_ == 200) return;
160 if (test_video_.width == 640 && target_bitrate_ == 1000) return;
162 rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
163 rc_api_->UpdateRateControl(rc_cfg_);
165 ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
166 test_video_.height, 30, 1, 0,
169 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
172 void RunPeriodicKey() {
173 test_video_ = GET_PARAM(2);
174 target_bitrate_ = GET_PARAM(1);
175 if (test_video_.width == 1280 && target_bitrate_ == 200) return;
176 if (test_video_.width == 640 && target_bitrate_ == 1000) return;
179 rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
180 rc_api_->UpdateRateControl(rc_cfg_);
182 ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
183 test_video_.height, 30, 1, 0,
186 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
189 void RunTemporalLayers2TL() {
190 test_video_ = GET_PARAM(2);
191 target_bitrate_ = GET_PARAM(1);
192 if (test_video_.width == 1280 && target_bitrate_ == 200) return;
193 if (test_video_.width == 640 && target_bitrate_ == 1000) return;
194 SetConfigTemporalLayers(2);
195 rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
196 rc_api_->UpdateRateControl(rc_cfg_);
198 ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
199 test_video_.height, 30, 1, 0,
202 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
205 void RunTemporalLayers3TL() {
206 test_video_ = GET_PARAM(2);
207 target_bitrate_ = GET_PARAM(1);
208 if (test_video_.width == 1280 && target_bitrate_ == 200) return;
209 if (test_video_.width == 640 && target_bitrate_ == 1000) return;
210 SetConfigTemporalLayers(3);
211 rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
212 rc_api_->UpdateRateControl(rc_cfg_);
214 ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
215 test_video_.height, 30, 1, 0,
218 ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
223 rc_cfg_.width = test_video_.width;
224 rc_cfg_.height = test_video_.height;
225 rc_cfg_.max_quantizer = 60;
226 rc_cfg_.min_quantizer = 2;
227 rc_cfg_.target_bandwidth = target_bitrate_;
228 rc_cfg_.buf_initial_sz = 600;
229 rc_cfg_.buf_optimal_sz = 600;
230 rc_cfg_.buf_sz = target_bitrate_;
231 rc_cfg_.undershoot_pct = 50;
232 rc_cfg_.overshoot_pct = 50;
233 rc_cfg_.max_intra_bitrate_pct = 1000;
234 rc_cfg_.framerate = 30.0;
235 rc_cfg_.layer_target_bitrate[0] = target_bitrate_;
237 // Encoder settings for ground truth.
238 cfg_.g_w = test_video_.width;
239 cfg_.g_h = test_video_.height;
240 cfg_.rc_undershoot_pct = 50;
241 cfg_.rc_overshoot_pct = 50;
242 cfg_.rc_buf_initial_sz = 600;
243 cfg_.rc_buf_optimal_sz = 600;
244 cfg_.rc_buf_sz = target_bitrate_;
245 cfg_.rc_dropframe_thresh = 0;
246 cfg_.rc_min_quantizer = 2;
247 cfg_.rc_max_quantizer = 60;
248 cfg_.rc_end_usage = VPX_CBR;
249 cfg_.g_lag_in_frames = 0;
250 cfg_.g_error_resilient = 1;
251 cfg_.rc_target_bitrate = target_bitrate_;
252 cfg_.kf_min_dist = key_interval_;
253 cfg_.kf_max_dist = key_interval_;
256 void SetConfigTemporalLayers(int temporal_layers) {
257 rc_cfg_.width = test_video_.width;
258 rc_cfg_.height = test_video_.height;
259 rc_cfg_.max_quantizer = 60;
260 rc_cfg_.min_quantizer = 2;
261 rc_cfg_.target_bandwidth = target_bitrate_;
262 rc_cfg_.buf_initial_sz = 600;
263 rc_cfg_.buf_optimal_sz = 600;
264 rc_cfg_.buf_sz = target_bitrate_;
265 rc_cfg_.undershoot_pct = 50;
266 rc_cfg_.overshoot_pct = 50;
267 rc_cfg_.max_intra_bitrate_pct = 1000;
268 rc_cfg_.framerate = 30.0;
269 if (temporal_layers == 2) {
270 rc_cfg_.layer_target_bitrate[0] = 60 * target_bitrate_ / 100;
271 rc_cfg_.layer_target_bitrate[1] = target_bitrate_;
272 rc_cfg_.ts_rate_decimator[0] = 2;
273 rc_cfg_.ts_rate_decimator[1] = 1;
274 } else if (temporal_layers == 3) {
275 rc_cfg_.layer_target_bitrate[0] = 40 * target_bitrate_ / 100;
276 rc_cfg_.layer_target_bitrate[1] = 60 * target_bitrate_ / 100;
277 rc_cfg_.layer_target_bitrate[2] = target_bitrate_;
278 rc_cfg_.ts_rate_decimator[0] = 4;
279 rc_cfg_.ts_rate_decimator[1] = 2;
280 rc_cfg_.ts_rate_decimator[2] = 1;
283 rc_cfg_.ts_number_layers = temporal_layers;
285 // Encoder settings for ground truth.
286 cfg_.g_w = test_video_.width;
287 cfg_.g_h = test_video_.height;
288 cfg_.rc_undershoot_pct = 50;
289 cfg_.rc_overshoot_pct = 50;
290 cfg_.rc_buf_initial_sz = 600;
291 cfg_.rc_buf_optimal_sz = 600;
292 cfg_.rc_buf_sz = target_bitrate_;
293 cfg_.rc_dropframe_thresh = 0;
294 cfg_.rc_min_quantizer = 2;
295 cfg_.rc_max_quantizer = 60;
296 cfg_.rc_end_usage = VPX_CBR;
297 cfg_.g_lag_in_frames = 0;
298 cfg_.g_error_resilient = 1;
299 cfg_.rc_target_bitrate = target_bitrate_;
300 cfg_.kf_min_dist = key_interval_;
301 cfg_.kf_max_dist = key_interval_;
302 // 2 Temporal layers, no spatial layers, CBR mode.
303 cfg_.ss_number_layers = 1;
304 cfg_.ts_number_layers = temporal_layers;
305 if (temporal_layers == 2) {
306 cfg_.ts_rate_decimator[0] = 2;
307 cfg_.ts_rate_decimator[1] = 1;
308 cfg_.ts_periodicity = 2;
309 cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
310 cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate;
311 } else if (temporal_layers == 3) {
312 cfg_.ts_rate_decimator[0] = 4;
313 cfg_.ts_rate_decimator[1] = 2;
314 cfg_.ts_rate_decimator[2] = 1;
315 cfg_.ts_periodicity = 4;
316 cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
317 cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
318 cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate;
322 std::unique_ptr<libvpx::VP8RateControlRTC> rc_api_;
323 libvpx::VP8RateControlRtcConfig rc_cfg_;
326 Vp8RCTestVideo test_video_;
327 libvpx::VP8FrameParamsQpRTC frame_params_;
331 TEST_P(Vp8RcInterfaceTest, OneLayer) { RunOneLayer(); }
333 TEST_P(Vp8RcInterfaceTest, OneLayerPeriodicKey) { RunPeriodicKey(); }
335 TEST_P(Vp8RcInterfaceTest, TemporalLayers2TL) { RunTemporalLayers2TL(); }
337 TEST_P(Vp8RcInterfaceTest, TemporalLayers3TL) { RunTemporalLayers3TL(); }
339 VP8_INSTANTIATE_TEST_SUITE(Vp8RcInterfaceTest,
340 ::testing::Values(200, 400, 1000),
341 ::testing::ValuesIn(kVp8RCTestVectors));