/* * Copyright (c) 2020 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "vp9/ratectrl_rtc.h" #include // NOLINT #include #include "./vpx_config.h" #include "third_party/googletest/src/include/gtest/gtest.h" #include "test/codec_factory.h" #include "test/encode_test_driver.h" #include "test/util.h" #include "test/video_source.h" #include "vpx/vpx_codec.h" #include "vpx_ports/bitops.h" namespace { const size_t kNumFrame = 850; struct FrameInfo { friend std::istream &operator>>(std::istream &is, FrameInfo &info) { is >> info.frame_id >> info.spatial_id >> info.temporal_id >> info.base_q >> info.target_bandwidth >> info.buffer_level >> info.filter_level_ >> info.bytes_used; return is; } int frame_id; int spatial_id; int temporal_id; // Base QP int base_q; size_t target_bandwidth; size_t buffer_level; // Loopfilter level int filter_level_; // Frame size for current frame, used for pose encode update size_t bytes_used; }; // This test runs the rate control interface and compare against ground truth // generated by encoders. // Settings for the encoder: // For 1 layer: // // examples/vpx_temporal_svc_encoder gipsrec_motion1.1280_720.yuv out vp9 // 1280 720 1 30 7 0 0 1 0 1000 // // For SVC (3 temporal layers, 3 spatial layers): // // examples/vp9_spatial_svc_encoder -f 10000 -w 1280 -h 720 -t 1/30 -sl 3 // -k 10000 -bl 100,140,200,250,350,500,450,630,900 -b 1600 --rc-end-usage=1 // --lag-in-frames=0 --passes=1 --speed=7 --threads=1 // --temporal-layering-mode=3 -aq 1 -rcstat 1 // gipsrec_motion1.1280_720.yuv -o out.webm // // - AQ_Mode 0 // - Disable golden refresh // - Bitrate x 2 at frame/superframe 200 // - Bitrate / 4 at frame/superframe 400 // // The generated file includes: // frame number, spatial layer ID, temporal layer ID, base QP, target // bandwidth, buffer level, loopfilter level, encoded frame size // TODO(jianj): Remove golden files, and run actual encoding in this test. class RcInterfaceTest : public ::testing::Test { public: explicit RcInterfaceTest() {} virtual ~RcInterfaceTest() {} protected: void RunOneLayer() { SetConfigOneLayer(); rc_api_->Create(rc_cfg_); FrameInfo frame_info; libvpx::VP9FrameParamsQpRTC frame_params; frame_params.frame_type = KEY_FRAME; frame_params.spatial_layer_id = 0; frame_params.temporal_layer_id = 0; std::ifstream one_layer_file; one_layer_file.open(libvpx_test::GetDataPath() + "/rc_interface_test_one_layer"); ASSERT_EQ(one_layer_file.rdstate() & std::ifstream::failbit, 0); for (size_t i = 0; i < kNumFrame; i++) { one_layer_file >> frame_info; if (frame_info.frame_id > 0) frame_params.frame_type = INTER_FRAME; if (frame_info.frame_id == 200) { rc_cfg_.target_bandwidth = rc_cfg_.target_bandwidth * 2; rc_api_->UpdateRateControl(rc_cfg_); } else if (frame_info.frame_id == 400) { rc_cfg_.target_bandwidth = rc_cfg_.target_bandwidth / 4; rc_api_->UpdateRateControl(rc_cfg_); } ASSERT_EQ(frame_info.spatial_id, 0); ASSERT_EQ(frame_info.temporal_id, 0); rc_api_->ComputeQP(frame_params); ASSERT_EQ(rc_api_->GetQP(), frame_info.base_q); ASSERT_EQ(rc_api_->GetLoopfilterLevel(), frame_info.filter_level_); rc_api_->PostEncodeUpdate(frame_info.bytes_used); } } void RunSVC() { SetConfigSVC(); rc_api_->Create(rc_cfg_); FrameInfo frame_info; libvpx::VP9FrameParamsQpRTC frame_params; frame_params.frame_type = KEY_FRAME; std::ifstream svc_file; svc_file.open(std::string(std::getenv("LIBVPX_TEST_DATA_PATH")) + "/rc_interface_test_svc"); ASSERT_EQ(svc_file.rdstate() & std::ifstream::failbit, 0); for (size_t i = 0; i < kNumFrame * rc_cfg_.ss_number_layers; i++) { svc_file >> frame_info; if (frame_info.frame_id > 0) frame_params.frame_type = INTER_FRAME; if (frame_info.frame_id == 200 * rc_cfg_.ss_number_layers) { for (int layer = 0; layer < rc_cfg_.ss_number_layers * rc_cfg_.ts_number_layers; layer++) rc_cfg_.layer_target_bitrate[layer] *= 2; rc_cfg_.target_bandwidth *= 2; rc_api_->UpdateRateControl(rc_cfg_); } else if (frame_info.frame_id == 400 * rc_cfg_.ss_number_layers) { for (int layer = 0; layer < rc_cfg_.ss_number_layers * rc_cfg_.ts_number_layers; layer++) rc_cfg_.layer_target_bitrate[layer] /= 4; rc_cfg_.target_bandwidth /= 4; rc_api_->UpdateRateControl(rc_cfg_); } frame_params.spatial_layer_id = frame_info.spatial_id; frame_params.temporal_layer_id = frame_info.temporal_id; rc_api_->ComputeQP(frame_params); ASSERT_EQ(rc_api_->GetQP(), frame_info.base_q); ASSERT_EQ(rc_api_->GetLoopfilterLevel(), frame_info.filter_level_); rc_api_->PostEncodeUpdate(frame_info.bytes_used); } } private: void SetConfigOneLayer() { rc_cfg_.width = 1280; rc_cfg_.height = 720; rc_cfg_.max_quantizer = 52; rc_cfg_.min_quantizer = 2; rc_cfg_.target_bandwidth = 1000; rc_cfg_.buf_initial_sz = 600; rc_cfg_.buf_optimal_sz = 600; rc_cfg_.buf_sz = 1000; rc_cfg_.undershoot_pct = 50; rc_cfg_.overshoot_pct = 50; rc_cfg_.max_intra_bitrate_pct = 1000; rc_cfg_.framerate = 30.0; rc_cfg_.ss_number_layers = 1; rc_cfg_.ts_number_layers = 1; rc_cfg_.scaling_factor_num[0] = 1; rc_cfg_.scaling_factor_den[0] = 1; rc_cfg_.layer_target_bitrate[0] = 1000; rc_cfg_.max_quantizers[0] = 52; rc_cfg_.min_quantizers[0] = 2; } void SetConfigSVC() { rc_cfg_.width = 1280; rc_cfg_.height = 720; rc_cfg_.max_quantizer = 56; rc_cfg_.min_quantizer = 2; rc_cfg_.target_bandwidth = 1600; rc_cfg_.buf_initial_sz = 500; rc_cfg_.buf_optimal_sz = 600; rc_cfg_.buf_sz = 1000; rc_cfg_.undershoot_pct = 50; rc_cfg_.overshoot_pct = 50; rc_cfg_.max_intra_bitrate_pct = 900; rc_cfg_.framerate = 30.0; rc_cfg_.ss_number_layers = 3; rc_cfg_.ts_number_layers = 3; rc_cfg_.scaling_factor_num[0] = 1; rc_cfg_.scaling_factor_den[0] = 4; rc_cfg_.scaling_factor_num[1] = 2; rc_cfg_.scaling_factor_den[1] = 4; rc_cfg_.scaling_factor_num[2] = 4; rc_cfg_.scaling_factor_den[2] = 4; rc_cfg_.ts_rate_decimator[0] = 4; rc_cfg_.ts_rate_decimator[1] = 2; rc_cfg_.ts_rate_decimator[2] = 1; rc_cfg_.layer_target_bitrate[0] = 100; rc_cfg_.layer_target_bitrate[1] = 140; rc_cfg_.layer_target_bitrate[2] = 200; rc_cfg_.layer_target_bitrate[3] = 250; rc_cfg_.layer_target_bitrate[4] = 350; rc_cfg_.layer_target_bitrate[5] = 500; rc_cfg_.layer_target_bitrate[6] = 450; rc_cfg_.layer_target_bitrate[7] = 630; rc_cfg_.layer_target_bitrate[8] = 900; for (int sl = 0; sl < rc_cfg_.ss_number_layers; ++sl) { for (int tl = 0; tl < rc_cfg_.ts_number_layers; ++tl) { const int i = sl * rc_cfg_.ts_number_layers + tl; rc_cfg_.max_quantizers[i] = 56; rc_cfg_.min_quantizers[i] = 2; } } } std::unique_ptr rc_api_; libvpx::VP9RateControlRtcConfig rc_cfg_; }; TEST_F(RcInterfaceTest, OneLayer) { RunOneLayer(); } TEST_F(RcInterfaceTest, SVC) { RunSVC(); } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }