ref: 65a1751e5b98bf7f1d21bcbfdef352af34fb205d
parent: ca40ca9bed87687eb0b534bf3974c95182dd29a1
author: Jerome Jiang <jianj@google.com>
date: Tue Aug 31 06:22:22 EDT 2021
Add vp8 support to rc lib For 1 layer CBR only. Support for temporal layers comes later. Rename the library to libvpxrc Bug: b/188853141 Change-Id: Ib7f977b64c05b1a0596870cb7f8e6768cb483850
--- a/libs.mk
+++ b/libs.mk
@@ -94,15 +94,28 @@
INSTALL_MAPS += include/vpx/% $(SRC_PATH_BARE)/$(VP9_PREFIX)/%
CODEC_DOC_SRCS += vpx/vp8.h vpx/vp8cx.h vpx/vpx_ext_ratectrl.h
CODEC_DOC_SECTIONS += vp9 vp9_encoder
+endif
- RC_RTC_SRCS := $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS))
- RC_RTC_SRCS += $(VP9_PREFIX)vp9cx.mk vpx/vp8.h vpx/vp8cx.h
- RC_RTC_SRCS += vpx/vpx_ext_ratectrl.h
+RC_RTC_SRCS := vpx/vp8.h vpx/vp8cx.h
+RC_RTC_SRCS += vpx/vpx_ext_ratectrl.h
+RC_RTC_SRCS += vpx/internal/vpx_ratectrl_rtc.h
+ifeq ($(CONFIG_VP9_ENCODER),yes)
+ VP9_PREFIX=vp9/
+ RC_RTC_SRCS += $(addprefix $(VP9_PREFIX),$(call enabled,VP9_CX_SRCS))
+ RC_RTC_SRCS += $(VP9_PREFIX)vp9cx.mk
RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.cc
RC_RTC_SRCS += $(VP9_PREFIX)ratectrl_rtc.h
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)ratectrl_rtc.cc
INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP9_PREFIX)ratectrl_rtc.h
endif
+ifeq ($(CONFIG_VP8_ENCODER),yes)
+ VP8_PREFIX=vp8/
+ RC_RTC_SRCS += $(addprefix $(VP8_PREFIX),$(call enabled,VP8_CX_SRCS))
+ RC_RTC_SRCS += $(VP8_PREFIX)vp8_ratectrl_rtc.cc
+ RC_RTC_SRCS += $(VP8_PREFIX)vp8_ratectrl_rtc.h
+ INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP8_PREFIX)vp8_ratectrl_rtc.cc
+ INSTALL-SRCS-$(CONFIG_CODEC_SRCS) += $(VP8_PREFIX)vp8_ratectrl_rtc.h
+endif
ifeq ($(CONFIG_VP9_DECODER),yes)
VP9_PREFIX=vp9/
@@ -126,7 +139,7 @@
ifeq ($(CONFIG_MSVS),yes)
CODEC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxmt,vpxmd)
GTEST_LIB=$(if $(CONFIG_STATIC_MSVCRT),gtestmt,gtestmd)
-RC_RTC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vp9rcmt,vp9rcmd)
+RC_RTC_LIB=$(if $(CONFIG_STATIC_MSVCRT),vpxrcmt,vpxrcmd)
# This variable uses deferred expansion intentionally, since the results of
# $(wildcard) may change during the course of the Make.
VS_PLATFORMS = $(foreach d,$(wildcard */Release/$(CODEC_LIB).lib),$(word 1,$(subst /, ,$(d))))
@@ -249,16 +262,16 @@
vpx.$(VCPROJ_SFX): vpx_config.asm
vpx.$(VCPROJ_SFX): $(RTCD)
-vp9rc.$(VCPROJ_SFX): \
+vpxrc.$(VCPROJ_SFX): \
VCPROJ_SRCS=$(filter-out $(addprefix %, $(ASM_INCLUDES)), $^)
-vp9rc.$(VCPROJ_SFX): $(RC_RTC_SRCS)
+vpxrc.$(VCPROJ_SFX): $(RC_RTC_SRCS)
@echo " [CREATE] $@"
$(qexec)$(GEN_VCPROJ) \
$(if $(CONFIG_SHARED),--dll,--lib) \
--target=$(TOOLCHAIN) \
$(if $(CONFIG_STATIC_MSVCRT),--static-crt) \
- --name=vp9rc \
+ --name=vpxrc \
--proj-guid=C26FF952-9494-4838-9A3F-7F3D4F613385 \
--ver=$(CONFIG_VS_VERSION) \
--src-path-bare="$(SRC_PATH_BARE)" \
@@ -275,10 +288,10 @@
$(VCPROJ_SRCS)) \
--src-path-bare="$(SRC_PATH_BARE)" \
-PROJECTS-yes += vp9rc.$(VCPROJ_SFX)
+PROJECTS-yes += vpxrc.$(VCPROJ_SFX)
-vp9rc.$(VCPROJ_SFX): vpx_config.asm
-vp9rc.$(VCPROJ_SFX): $(RTCD)
+vpxrc.$(VCPROJ_SFX): vpx_config.asm
+vpxrc.$(VCPROJ_SFX): $(RTCD)
endif # ifeq ($(CONFIG_MSVS),yes)
else # ifeq ($(CONFIG_EXTERNAL_BUILD),yes)
@@ -398,12 +411,11 @@
INSTALL_MAPS += $(LIBSUBDIR)/pkgconfig/%.pc %.pc
CLEAN-OBJS += vpx.pc
-ifeq ($(CONFIG_VP9_ENCODER),yes)
+ifeq ($(CONFIG_ENCODERS),yes)
RC_RTC_OBJS=$(call objs,$(RC_RTC_SRCS))
- RC_RTC_OBJS=$(call objs,$(RC_RTC_SRCS))
OBJS-yes += $(RC_RTC_OBJS)
- LIBS-yes += $(BUILD_PFX)libvp9rc.a $(BUILD_PFX)libvp9rc_g.a
- $(BUILD_PFX)libvp9rc_g.a: $(RC_RTC_OBJS)
+ LIBS-yes += $(BUILD_PFX)libvpxrc.a $(BUILD_PFX)libvpxrc_g.a
+ $(BUILD_PFX)libvpxrc_g.a: $(RC_RTC_OBJS)
endif
ifeq ($(CONFIG_VP9_ENCODER)$(CONFIG_RATE_CTRL),yesyes)
@@ -493,7 +505,7 @@
$(call enabled,TEST_INTRA_PRED_SPEED_SRCS))
TEST_INTRA_PRED_SPEED_OBJS := $(sort $(call objs,$(TEST_INTRA_PRED_SPEED_SRCS)))
-ifeq ($(CONFIG_VP9_ENCODER),yes)
+ifeq ($(CONFIG_ENCODERS),yes)
RC_INTERFACE_TEST_BIN=./test_rc_interface$(EXE_SFX)
RC_INTERFACE_TEST_SRCS=$(call addprefix_clean,test/,\
$(call enabled,RC_INTERFACE_TEST_SRCS))
@@ -599,11 +611,11 @@
-L. -l$(CODEC_LIB) -l$(GTEST_LIB) $^
endif # TEST_INTRA_PRED_SPEED
-ifeq ($(CONFIG_VP9_ENCODER),yes)
+ifeq ($(CONFIG_ENCODERS),yes)
ifneq ($(strip $(RC_INTERFACE_TEST_OBJS)),)
PROJECTS-$(CONFIG_MSVS) += test_rc_interface.$(VCPROJ_SFX)
test_rc_interface.$(VCPROJ_SFX): $(RC_INTERFACE_TEST_SRCS) vpx.$(VCPROJ_SFX) \
- vp9rc.$(VCPROJ_SFX) gtest.$(VCPROJ_SFX)
+ vpxrc.$(VCPROJ_SFX) gtest.$(VCPROJ_SFX)
@echo " [CREATE] $@"
$(qexec)$(GEN_VCPROJ) \
--exe \
@@ -661,7 +673,7 @@
-L. -lvpx -lgtest $(extralibs) -lm))
endif # TEST_INTRA_PRED_SPEED
-ifeq ($(CONFIG_VP9_ENCODER),yes)
+ifeq ($(CONFIG_ENCODERS),yes)
ifneq ($(strip $(RC_INTERFACE_TEST_OBJS)),)
$(RC_INTERFACE_TEST_OBJS) $(RC_INTERFACE_TEST_OBJS:.o=.d): \
CXXFLAGS += $(GTEST_INCLUDES)
@@ -668,12 +680,12 @@
OBJS-yes += $(RC_INTERFACE_TEST_OBJS)
BINS-yes += $(RC_INTERFACE_TEST_BIN)
-$(RC_INTERFACE_TEST_BIN): $(TEST_LIBS) libvp9rc.a
+$(RC_INTERFACE_TEST_BIN): $(TEST_LIBS) libvpxrc.a
$(eval $(call linkerxx_template,$(RC_INTERFACE_TEST_BIN), \
$(RC_INTERFACE_TEST_OBJS) \
- -L. -lvpx -lgtest -lvp9rc $(extralibs) -lm))
+ -L. -lvpx -lgtest -lvpxrc $(extralibs) -lm))
endif # RC_INTERFACE_TEST
-endif # CONFIG_VP9_ENCODER
+endif # CONFIG_ENCODERS
ifneq ($(strip $(SIMPLE_ENCODE_TEST_OBJS)),)
$(SIMPLE_ENCODE_TEST_OBJS) $(SIMPLE_ENCODE_TEST_OBJS:.o=.d): \
--- a/test/ratectrl_rtc_test.cc
+++ /dev/null
@@ -1,378 +1,0 @@
-/*
- * 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 <fstream> // NOLINT
-#include <string>
-
-#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/i420_video_source.h"
-#include "test/util.h"
-#include "test/video_source.h"
-#include "vpx/vpx_codec.h"
-#include "vpx_ports/bitops.h"
-
-namespace {
-
-const size_t kNumFrames = 300;
-
-const int kTemporalId[4] = { 0, 2, 1, 2 };
-
-class RcInterfaceTest
- : public ::libvpx_test::EncoderTest,
- public ::libvpx_test::CodecTestWith2Params<int, vpx_rc_mode> {
- public:
- RcInterfaceTest()
- : EncoderTest(GET_PARAM(0)), aq_mode_(GET_PARAM(1)), key_interval_(3000),
- encoder_exit_(false) {}
-
- virtual ~RcInterfaceTest() {}
-
- protected:
- virtual void SetUp() {
- InitializeConfig();
- SetMode(::libvpx_test::kRealTime);
- }
-
- virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
- libvpx_test::Encoder *encoder) {
- if (video->frame() == 0) {
- encoder->Control(VP8E_SET_CPUUSED, 7);
- encoder->Control(VP9E_SET_AQ_MODE, aq_mode_);
- encoder->Control(VP9E_SET_TUNE_CONTENT, 0);
- encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 1000);
- encoder->Control(VP9E_SET_RTC_EXTERNAL_RATECTRL, 1);
- }
- frame_params_.frame_type =
- video->frame() % key_interval_ == 0 ? KEY_FRAME : INTER_FRAME;
- if (rc_cfg_.rc_mode == VPX_CBR && frame_params_.frame_type == INTER_FRAME) {
- // Disable golden frame update.
- frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
- frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
- }
- encoder_exit_ = video->frame() == kNumFrames;
- }
-
- virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
- if (encoder_exit_) {
- return;
- }
- int loopfilter_level, qp;
- encoder->Control(VP9E_GET_LOOPFILTER_LEVEL, &loopfilter_level);
- encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
- rc_api_->ComputeQP(frame_params_);
- ASSERT_EQ(rc_api_->GetQP(), qp);
- ASSERT_EQ(rc_api_->GetLoopfilterLevel(), loopfilter_level);
- }
-
- virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
- rc_api_->PostEncodeUpdate(pkt->data.frame.sz);
- }
-
- void RunOneLayer() {
- SetConfig(GET_PARAM(2));
- rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
- frame_params_.spatial_layer_id = 0;
- frame_params_.temporal_layer_id = 0;
-
- ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
- 1280, 720, 30, 1, 0, kNumFrames);
-
- ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- }
-
- void RunOneLayerVBRPeriodicKey() {
- if (GET_PARAM(2) != VPX_VBR) return;
- key_interval_ = 100;
- SetConfig(VPX_VBR);
- rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
- frame_params_.spatial_layer_id = 0;
- frame_params_.temporal_layer_id = 0;
-
- ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
- 1280, 720, 30, 1, 0, kNumFrames);
-
- ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- }
-
- private:
- void SetConfig(vpx_rc_mode rc_mode) {
- 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;
- rc_cfg_.rc_mode = rc_mode;
- rc_cfg_.aq_mode = aq_mode_;
-
- // Encoder settings for ground truth.
- cfg_.g_w = 1280;
- cfg_.g_h = 720;
- cfg_.rc_undershoot_pct = 50;
- cfg_.rc_overshoot_pct = 50;
- cfg_.rc_buf_initial_sz = 600;
- cfg_.rc_buf_optimal_sz = 600;
- cfg_.rc_buf_sz = 1000;
- cfg_.rc_dropframe_thresh = 0;
- cfg_.rc_min_quantizer = 2;
- cfg_.rc_max_quantizer = 52;
- cfg_.rc_end_usage = rc_mode;
- cfg_.g_lag_in_frames = 0;
- cfg_.g_error_resilient = 0;
- cfg_.rc_target_bitrate = 1000;
- cfg_.kf_min_dist = key_interval_;
- cfg_.kf_max_dist = key_interval_;
- }
-
- std::unique_ptr<libvpx::VP9RateControlRTC> rc_api_;
- libvpx::VP9RateControlRtcConfig rc_cfg_;
- int aq_mode_;
- int key_interval_;
- libvpx::VP9FrameParamsQpRTC frame_params_;
- bool encoder_exit_;
-};
-
-class RcInterfaceSvcTest : public ::libvpx_test::EncoderTest,
- public ::libvpx_test::CodecTestWithParam<int> {
- public:
- RcInterfaceSvcTest() : EncoderTest(GET_PARAM(0)), aq_mode_(GET_PARAM(1)) {}
- virtual ~RcInterfaceSvcTest() {}
-
- protected:
- virtual void SetUp() {
- InitializeConfig();
- SetMode(::libvpx_test::kRealTime);
- }
-
- virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
- ::libvpx_test::Encoder *encoder) {
- if (video->frame() == 0) {
- encoder->Control(VP8E_SET_CPUUSED, 7);
- encoder->Control(VP9E_SET_AQ_MODE, aq_mode_);
- encoder->Control(VP9E_SET_TUNE_CONTENT, 0);
- encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 900);
- encoder->Control(VP9E_SET_RTC_EXTERNAL_RATECTRL, 1);
- encoder->Control(VP9E_SET_SVC, 1);
- encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
- }
-
- frame_params_.frame_type = video->frame() == 0 ? KEY_FRAME : INTER_FRAME;
- if (rc_cfg_.rc_mode == VPX_CBR && frame_params_.frame_type == INTER_FRAME) {
- // Disable golden frame update.
- frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
- frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
- }
- encoder_exit_ = video->frame() == kNumFrames;
- current_superframe_ = video->frame();
- }
-
- virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
- ::libvpx_test::CxDataIterator iter = encoder->GetCxData();
- while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
- ParseSuperframeSizes(static_cast<const uint8_t *>(pkt->data.frame.buf),
- pkt->data.frame.sz);
- for (int sl = 0; sl < rc_cfg_.ss_number_layers; sl++) {
- frame_params_.spatial_layer_id = sl;
- frame_params_.temporal_layer_id = kTemporalId[current_superframe_ % 4];
- rc_api_->ComputeQP(frame_params_);
- frame_params_.frame_type = INTER_FRAME;
- rc_api_->PostEncodeUpdate(sizes_[sl]);
- }
- }
- if (!encoder_exit_) {
- int loopfilter_level, qp;
- encoder->Control(VP9E_GET_LOOPFILTER_LEVEL, &loopfilter_level);
- encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
- ASSERT_EQ(rc_api_->GetQP(), qp);
- ASSERT_EQ(rc_api_->GetLoopfilterLevel(), loopfilter_level);
- }
- }
- // This method needs to be overridden because non-reference frames are
- // expected to be mismatched frames as the encoder will avoid loopfilter on
- // these frames.
- virtual void MismatchHook(const vpx_image_t * /*img1*/,
- const vpx_image_t * /*img2*/) {}
-
- void RunSvc() {
- SetConfigSvc();
- rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
- SetEncoderSvc();
-
- ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
- 1280, 720, 30, 1, 0, kNumFrames);
-
- ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
- }
-
- private:
- vpx_codec_err_t ParseSuperframeSizes(const uint8_t *data, size_t data_sz) {
- uint8_t marker = *(data + data_sz - 1);
- if ((marker & 0xe0) == 0xc0) {
- const uint32_t frames = (marker & 0x7) + 1;
- const uint32_t mag = ((marker >> 3) & 0x3) + 1;
- const size_t index_sz = 2 + mag * frames;
- // This chunk is marked as having a superframe index but doesn't have
- // enough data for it, thus it's an invalid superframe index.
- if (data_sz < index_sz) return VPX_CODEC_CORRUPT_FRAME;
- {
- const uint8_t marker2 = *(data + data_sz - index_sz);
- // This chunk is marked as having a superframe index but doesn't have
- // the matching marker byte at the front of the index therefore it's an
- // invalid chunk.
- if (marker != marker2) return VPX_CODEC_CORRUPT_FRAME;
- }
- const uint8_t *x = &data[data_sz - index_sz + 1];
- for (uint32_t i = 0; i < frames; ++i) {
- uint32_t this_sz = 0;
-
- for (uint32_t j = 0; j < mag; ++j) this_sz |= (*x++) << (j * 8);
- sizes_[i] = this_sz;
- }
- }
- return VPX_CODEC_OK;
- }
-
- void SetEncoderSvc() {
- cfg_.ss_number_layers = 3;
- cfg_.ts_number_layers = 3;
- cfg_.g_timebase.num = 1;
- cfg_.g_timebase.den = 30;
- svc_params_.scaling_factor_num[0] = 72;
- svc_params_.scaling_factor_den[0] = 288;
- svc_params_.scaling_factor_num[1] = 144;
- svc_params_.scaling_factor_den[1] = 288;
- svc_params_.scaling_factor_num[2] = 288;
- svc_params_.scaling_factor_den[2] = 288;
- for (int i = 0; i < VPX_MAX_LAYERS; ++i) {
- svc_params_.max_quantizers[i] = 56;
- svc_params_.min_quantizers[i] = 2;
- svc_params_.speed_per_layer[i] = 7;
- }
- cfg_.rc_end_usage = VPX_CBR;
- cfg_.g_lag_in_frames = 0;
- cfg_.g_error_resilient = 0;
- // 3 temporal layers
- cfg_.ts_rate_decimator[0] = 4;
- cfg_.ts_rate_decimator[1] = 2;
- cfg_.ts_rate_decimator[2] = 1;
- cfg_.temporal_layering_mode = 3;
-
- cfg_.rc_buf_initial_sz = 500;
- cfg_.rc_buf_optimal_sz = 600;
- cfg_.rc_buf_sz = 1000;
- cfg_.rc_min_quantizer = 2;
- cfg_.rc_max_quantizer = 56;
- cfg_.g_threads = 1;
- cfg_.kf_max_dist = 9999;
- cfg_.rc_target_bitrate = 1600;
- cfg_.rc_overshoot_pct = 50;
- cfg_.rc_undershoot_pct = 50;
-
- cfg_.layer_target_bitrate[0] = 100;
- cfg_.layer_target_bitrate[1] = 140;
- cfg_.layer_target_bitrate[2] = 200;
- cfg_.layer_target_bitrate[3] = 250;
- cfg_.layer_target_bitrate[4] = 350;
- cfg_.layer_target_bitrate[5] = 500;
- cfg_.layer_target_bitrate[6] = 450;
- cfg_.layer_target_bitrate[7] = 630;
- cfg_.layer_target_bitrate[8] = 900;
- }
-
- 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_.rc_mode = VPX_CBR;
- rc_cfg_.aq_mode = aq_mode_;
-
- 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;
- }
- }
- }
-
- int aq_mode_;
- std::unique_ptr<libvpx::VP9RateControlRTC> rc_api_;
- libvpx::VP9RateControlRtcConfig rc_cfg_;
- vpx_svc_extra_cfg_t svc_params_;
- libvpx::VP9FrameParamsQpRTC frame_params_;
- bool encoder_exit_;
- int current_superframe_;
- uint32_t sizes_[8];
-};
-
-TEST_P(RcInterfaceTest, OneLayer) { RunOneLayer(); }
-
-TEST_P(RcInterfaceTest, OneLayerVBRPeriodicKey) { RunOneLayerVBRPeriodicKey(); }
-
-TEST_P(RcInterfaceSvcTest, Svc) { RunSvc(); }
-
-VP9_INSTANTIATE_TEST_SUITE(RcInterfaceTest, ::testing::Values(0, 3),
- ::testing::Values(VPX_CBR, VPX_VBR));
-VP9_INSTANTIATE_TEST_SUITE(RcInterfaceSvcTest, ::testing::Values(0, 3));
-} // namespace
-
-int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
--- a/test/test.mk
+++ b/test/test.mk
@@ -213,9 +213,11 @@
TEST_INTRA_PRED_SPEED_SRCS-yes := test_intra_pred_speed.cc
TEST_INTRA_PRED_SPEED_SRCS-yes += ../md5_utils.h ../md5_utils.c
-RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) := ratectrl_rtc_test.cc
-RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) += encode_test_driver.cc
-RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) += encode_test_driver.h
+RC_INTERFACE_TEST_SRCS-yes := test_rc_interface.cc
+RC_INTERFACE_TEST_SRCS-$(CONFIG_VP9_ENCODER) += vp9_ratectrl_rtc_test.cc
+RC_INTERFACE_TEST_SRCS-$(CONFIG_VP8_ENCODER) += vp8_ratectrl_rtc_test.cc
+RC_INTERFACE_TEST_SRCS-$(CONFIG_ENCODERS) += encode_test_driver.cc
+RC_INTERFACE_TEST_SRCS-$(CONFIG_ENCODERS) += encode_test_driver.h
RC_INTERFACE_TEST_SRCS-yes += decode_test_driver.cc
RC_INTERFACE_TEST_SRCS-yes += decode_test_driver.h
RC_INTERFACE_TEST_SRCS-yes += codec_factory.h
--- /dev/null
+++ b/test/test_rc_interface.cc
@@ -1,0 +1,6 @@
+#include "third_party/googletest/src/include/gtest/gtest.h"
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
--- /dev/null
+++ b/test/vp8_ratectrl_rtc_test.cc
@@ -1,0 +1,180 @@
+/*
+ * Copyright (c) 2021 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 <fstream> // NOLINT
+#include <string>
+
+#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/i420_video_source.h"
+#include "test/util.h"
+#include "test/video_source.h"
+#include "vp8/vp8_ratectrl_rtc.h"
+#include "vpx/vpx_codec.h"
+#include "vpx_ports/bitops.h"
+
+namespace {
+
+struct Vp8RCTestVideo {
+ Vp8RCTestVideo() {}
+ Vp8RCTestVideo(const char *name_, int width_, int height_,
+ unsigned int frames_)
+ : name(name_), width(width_), height(height_), frames(frames_) {}
+
+ friend std::ostream &operator<<(std::ostream &os,
+ const Vp8RCTestVideo &video) {
+ os << video.name << " " << video.width << " " << video.height << " "
+ << video.frames;
+ return os;
+ }
+ const char *name;
+ int width;
+ int height;
+ unsigned int frames;
+};
+
+const Vp8RCTestVideo kVp8RCTestVectors[] = {
+ Vp8RCTestVideo("niklas_640_480_30.yuv", 640, 480, 470),
+ Vp8RCTestVideo("desktop_office1.1280_720-020.yuv", 1280, 720, 300),
+};
+
+class Vp8RcInterfaceTest
+ : public ::libvpx_test::EncoderTest,
+ public ::libvpx_test::CodecTestWith2Params<int, Vp8RCTestVideo> {
+ public:
+ Vp8RcInterfaceTest()
+ : EncoderTest(GET_PARAM(0)), key_interval_(3000), encoder_exit_(false) {}
+ virtual ~Vp8RcInterfaceTest() {}
+
+ protected:
+ virtual void SetUp() {
+ InitializeConfig();
+ SetMode(::libvpx_test::kRealTime);
+ }
+
+ virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
+ ::libvpx_test::Encoder *encoder) {
+ if (video->frame() == 0) {
+ encoder->Control(VP8E_SET_CPUUSED, -6);
+ encoder->Control(VP8E_SET_RTC_EXTERNAL_RATECTRL, 1);
+ encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 1000);
+ }
+ frame_params_.frame_type =
+ video->frame() % key_interval_ == 0 ? KEY_FRAME : INTER_FRAME;
+ if (frame_params_.frame_type == INTER_FRAME) {
+ // Disable golden frame update.
+ frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
+ frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
+ }
+ encoder_exit_ = video->frame() == test_video_.frames;
+ }
+
+ virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
+ if (encoder_exit_) {
+ return;
+ }
+ int qp;
+ encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
+ rc_api_->ComputeQP(frame_params_);
+ ASSERT_EQ(rc_api_->GetQP(), qp);
+ }
+
+ virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
+ rc_api_->PostEncodeUpdate(pkt->data.frame.sz);
+ }
+
+ void RunOneLayer() {
+ test_video_ = GET_PARAM(2);
+ target_bitrate_ = GET_PARAM(1);
+ if (test_video_.width == 1280 && target_bitrate_ == 200) return;
+ if (test_video_.width == 640 && target_bitrate_ == 1000) return;
+ SetConfig();
+ rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
+ rc_api_->UpdateRateControl(rc_cfg_);
+
+ ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
+ test_video_.height, 30, 1, 0,
+ test_video_.frames);
+
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ }
+
+ void RunPeriodicKey() {
+ test_video_ = GET_PARAM(2);
+ target_bitrate_ = GET_PARAM(1);
+ if (test_video_.width == 1280 && target_bitrate_ == 200) return;
+ if (test_video_.width == 640 && target_bitrate_ == 1000) return;
+ key_interval_ = 100;
+ SetConfig();
+ rc_api_ = libvpx::VP8RateControlRTC::Create(rc_cfg_);
+ rc_api_->UpdateRateControl(rc_cfg_);
+
+ ::libvpx_test::I420VideoSource video(test_video_.name, test_video_.width,
+ test_video_.height, 30, 1, 0,
+ test_video_.frames);
+
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ }
+
+ private:
+ void SetConfig() {
+ rc_cfg_.width = test_video_.width;
+ rc_cfg_.height = test_video_.height;
+ rc_cfg_.max_quantizer = 60;
+ rc_cfg_.min_quantizer = 2;
+ rc_cfg_.target_bandwidth = target_bitrate_;
+ rc_cfg_.buf_initial_sz = 600;
+ rc_cfg_.buf_optimal_sz = 600;
+ rc_cfg_.buf_sz = target_bitrate_;
+ rc_cfg_.undershoot_pct = 50;
+ rc_cfg_.overshoot_pct = 50;
+ rc_cfg_.max_intra_bitrate_pct = 1000;
+ rc_cfg_.framerate = 30.0;
+ rc_cfg_.layer_target_bitrate[0] = target_bitrate_;
+
+ // Encoder settings for ground truth.
+ cfg_.g_w = test_video_.width;
+ cfg_.g_h = test_video_.height;
+ cfg_.rc_undershoot_pct = 50;
+ cfg_.rc_overshoot_pct = 50;
+ cfg_.rc_buf_initial_sz = 600;
+ cfg_.rc_buf_optimal_sz = 600;
+ cfg_.rc_buf_sz = target_bitrate_;
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_min_quantizer = 2;
+ cfg_.rc_max_quantizer = 60;
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_error_resilient = 1;
+ cfg_.rc_target_bitrate = target_bitrate_;
+ cfg_.kf_min_dist = key_interval_;
+ cfg_.kf_max_dist = key_interval_;
+ }
+
+ std::unique_ptr<libvpx::VP8RateControlRTC> rc_api_;
+ libvpx::VP8RateControlRtcConfig rc_cfg_;
+ int key_interval_;
+ int target_bitrate_;
+ Vp8RCTestVideo test_video_;
+ libvpx::VP8FrameParamsQpRTC frame_params_;
+ bool encoder_exit_;
+};
+
+TEST_P(Vp8RcInterfaceTest, OneLayer) { RunOneLayer(); }
+
+TEST_P(Vp8RcInterfaceTest, OneLayerPeriodicKey) { RunPeriodicKey(); }
+
+VP8_INSTANTIATE_TEST_SUITE(Vp8RcInterfaceTest,
+ ::testing::Values(200, 400, 1000),
+ ::testing::ValuesIn(kVp8RCTestVectors));
+
+} // namespace
--- /dev/null
+++ b/test/vp9_ratectrl_rtc_test.cc
@@ -1,0 +1,373 @@
+/*
+ * 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 <fstream> // NOLINT
+#include <string>
+
+#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/i420_video_source.h"
+#include "test/util.h"
+#include "test/video_source.h"
+#include "vpx/vpx_codec.h"
+#include "vpx_ports/bitops.h"
+
+namespace {
+
+const size_t kNumFrames = 300;
+
+const int kTemporalId[4] = { 0, 2, 1, 2 };
+
+class RcInterfaceTest
+ : public ::libvpx_test::EncoderTest,
+ public ::libvpx_test::CodecTestWith2Params<int, vpx_rc_mode> {
+ public:
+ RcInterfaceTest()
+ : EncoderTest(GET_PARAM(0)), aq_mode_(GET_PARAM(1)), key_interval_(3000),
+ encoder_exit_(false) {}
+
+ virtual ~RcInterfaceTest() {}
+
+ protected:
+ virtual void SetUp() {
+ InitializeConfig();
+ SetMode(::libvpx_test::kRealTime);
+ }
+
+ virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
+ libvpx_test::Encoder *encoder) {
+ if (video->frame() == 0) {
+ encoder->Control(VP8E_SET_CPUUSED, 7);
+ encoder->Control(VP9E_SET_AQ_MODE, aq_mode_);
+ encoder->Control(VP9E_SET_TUNE_CONTENT, 0);
+ encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 1000);
+ encoder->Control(VP9E_SET_RTC_EXTERNAL_RATECTRL, 1);
+ }
+ frame_params_.frame_type =
+ video->frame() % key_interval_ == 0 ? KEY_FRAME : INTER_FRAME;
+ if (rc_cfg_.rc_mode == VPX_CBR && frame_params_.frame_type == INTER_FRAME) {
+ // Disable golden frame update.
+ frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
+ frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
+ }
+ encoder_exit_ = video->frame() == kNumFrames;
+ }
+
+ virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
+ if (encoder_exit_) {
+ return;
+ }
+ int loopfilter_level, qp;
+ encoder->Control(VP9E_GET_LOOPFILTER_LEVEL, &loopfilter_level);
+ encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
+ rc_api_->ComputeQP(frame_params_);
+ ASSERT_EQ(rc_api_->GetQP(), qp);
+ ASSERT_EQ(rc_api_->GetLoopfilterLevel(), loopfilter_level);
+ }
+
+ virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
+ rc_api_->PostEncodeUpdate(pkt->data.frame.sz);
+ }
+
+ void RunOneLayer() {
+ SetConfig(GET_PARAM(2));
+ rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
+ frame_params_.spatial_layer_id = 0;
+ frame_params_.temporal_layer_id = 0;
+
+ ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
+ 1280, 720, 30, 1, 0, kNumFrames);
+
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ }
+
+ void RunOneLayerVBRPeriodicKey() {
+ if (GET_PARAM(2) != VPX_VBR) return;
+ key_interval_ = 100;
+ SetConfig(VPX_VBR);
+ rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
+ frame_params_.spatial_layer_id = 0;
+ frame_params_.temporal_layer_id = 0;
+
+ ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
+ 1280, 720, 30, 1, 0, kNumFrames);
+
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ }
+
+ private:
+ void SetConfig(vpx_rc_mode rc_mode) {
+ 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;
+ rc_cfg_.rc_mode = rc_mode;
+ rc_cfg_.aq_mode = aq_mode_;
+
+ // Encoder settings for ground truth.
+ cfg_.g_w = 1280;
+ cfg_.g_h = 720;
+ cfg_.rc_undershoot_pct = 50;
+ cfg_.rc_overshoot_pct = 50;
+ cfg_.rc_buf_initial_sz = 600;
+ cfg_.rc_buf_optimal_sz = 600;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_dropframe_thresh = 0;
+ cfg_.rc_min_quantizer = 2;
+ cfg_.rc_max_quantizer = 52;
+ cfg_.rc_end_usage = rc_mode;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_error_resilient = 0;
+ cfg_.rc_target_bitrate = 1000;
+ cfg_.kf_min_dist = key_interval_;
+ cfg_.kf_max_dist = key_interval_;
+ }
+
+ std::unique_ptr<libvpx::VP9RateControlRTC> rc_api_;
+ libvpx::VP9RateControlRtcConfig rc_cfg_;
+ int aq_mode_;
+ int key_interval_;
+ libvpx::VP9FrameParamsQpRTC frame_params_;
+ bool encoder_exit_;
+};
+
+class RcInterfaceSvcTest : public ::libvpx_test::EncoderTest,
+ public ::libvpx_test::CodecTestWithParam<int> {
+ public:
+ RcInterfaceSvcTest() : EncoderTest(GET_PARAM(0)), aq_mode_(GET_PARAM(1)) {}
+ virtual ~RcInterfaceSvcTest() {}
+
+ protected:
+ virtual void SetUp() {
+ InitializeConfig();
+ SetMode(::libvpx_test::kRealTime);
+ }
+
+ virtual void PreEncodeFrameHook(libvpx_test::VideoSource *video,
+ ::libvpx_test::Encoder *encoder) {
+ if (video->frame() == 0) {
+ encoder->Control(VP8E_SET_CPUUSED, 7);
+ encoder->Control(VP9E_SET_AQ_MODE, aq_mode_);
+ encoder->Control(VP9E_SET_TUNE_CONTENT, 0);
+ encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 900);
+ encoder->Control(VP9E_SET_RTC_EXTERNAL_RATECTRL, 1);
+ encoder->Control(VP9E_SET_SVC, 1);
+ encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
+ }
+
+ frame_params_.frame_type = video->frame() == 0 ? KEY_FRAME : INTER_FRAME;
+ if (rc_cfg_.rc_mode == VPX_CBR && frame_params_.frame_type == INTER_FRAME) {
+ // Disable golden frame update.
+ frame_flags_ |= VP8_EFLAG_NO_UPD_GF;
+ frame_flags_ |= VP8_EFLAG_NO_UPD_ARF;
+ }
+ encoder_exit_ = video->frame() == kNumFrames;
+ current_superframe_ = video->frame();
+ }
+
+ virtual void PostEncodeFrameHook(::libvpx_test::Encoder *encoder) {
+ ::libvpx_test::CxDataIterator iter = encoder->GetCxData();
+ while (const vpx_codec_cx_pkt_t *pkt = iter.Next()) {
+ ParseSuperframeSizes(static_cast<const uint8_t *>(pkt->data.frame.buf),
+ pkt->data.frame.sz);
+ for (int sl = 0; sl < rc_cfg_.ss_number_layers; sl++) {
+ frame_params_.spatial_layer_id = sl;
+ frame_params_.temporal_layer_id = kTemporalId[current_superframe_ % 4];
+ rc_api_->ComputeQP(frame_params_);
+ frame_params_.frame_type = INTER_FRAME;
+ rc_api_->PostEncodeUpdate(sizes_[sl]);
+ }
+ }
+ if (!encoder_exit_) {
+ int loopfilter_level, qp;
+ encoder->Control(VP9E_GET_LOOPFILTER_LEVEL, &loopfilter_level);
+ encoder->Control(VP8E_GET_LAST_QUANTIZER, &qp);
+ ASSERT_EQ(rc_api_->GetQP(), qp);
+ ASSERT_EQ(rc_api_->GetLoopfilterLevel(), loopfilter_level);
+ }
+ }
+ // This method needs to be overridden because non-reference frames are
+ // expected to be mismatched frames as the encoder will avoid loopfilter on
+ // these frames.
+ virtual void MismatchHook(const vpx_image_t * /*img1*/,
+ const vpx_image_t * /*img2*/) {}
+
+ void RunSvc() {
+ SetConfigSvc();
+ rc_api_ = libvpx::VP9RateControlRTC::Create(rc_cfg_);
+ SetEncoderSvc();
+
+ ::libvpx_test::I420VideoSource video("desktop_office1.1280_720-020.yuv",
+ 1280, 720, 30, 1, 0, kNumFrames);
+
+ ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+ }
+
+ private:
+ vpx_codec_err_t ParseSuperframeSizes(const uint8_t *data, size_t data_sz) {
+ uint8_t marker = *(data + data_sz - 1);
+ if ((marker & 0xe0) == 0xc0) {
+ const uint32_t frames = (marker & 0x7) + 1;
+ const uint32_t mag = ((marker >> 3) & 0x3) + 1;
+ const size_t index_sz = 2 + mag * frames;
+ // This chunk is marked as having a superframe index but doesn't have
+ // enough data for it, thus it's an invalid superframe index.
+ if (data_sz < index_sz) return VPX_CODEC_CORRUPT_FRAME;
+ {
+ const uint8_t marker2 = *(data + data_sz - index_sz);
+ // This chunk is marked as having a superframe index but doesn't have
+ // the matching marker byte at the front of the index therefore it's an
+ // invalid chunk.
+ if (marker != marker2) return VPX_CODEC_CORRUPT_FRAME;
+ }
+ const uint8_t *x = &data[data_sz - index_sz + 1];
+ for (uint32_t i = 0; i < frames; ++i) {
+ uint32_t this_sz = 0;
+
+ for (uint32_t j = 0; j < mag; ++j) this_sz |= (*x++) << (j * 8);
+ sizes_[i] = this_sz;
+ }
+ }
+ return VPX_CODEC_OK;
+ }
+
+ void SetEncoderSvc() {
+ cfg_.ss_number_layers = 3;
+ cfg_.ts_number_layers = 3;
+ cfg_.g_timebase.num = 1;
+ cfg_.g_timebase.den = 30;
+ svc_params_.scaling_factor_num[0] = 72;
+ svc_params_.scaling_factor_den[0] = 288;
+ svc_params_.scaling_factor_num[1] = 144;
+ svc_params_.scaling_factor_den[1] = 288;
+ svc_params_.scaling_factor_num[2] = 288;
+ svc_params_.scaling_factor_den[2] = 288;
+ for (int i = 0; i < VPX_MAX_LAYERS; ++i) {
+ svc_params_.max_quantizers[i] = 56;
+ svc_params_.min_quantizers[i] = 2;
+ svc_params_.speed_per_layer[i] = 7;
+ }
+ cfg_.rc_end_usage = VPX_CBR;
+ cfg_.g_lag_in_frames = 0;
+ cfg_.g_error_resilient = 0;
+ // 3 temporal layers
+ cfg_.ts_rate_decimator[0] = 4;
+ cfg_.ts_rate_decimator[1] = 2;
+ cfg_.ts_rate_decimator[2] = 1;
+ cfg_.temporal_layering_mode = 3;
+
+ cfg_.rc_buf_initial_sz = 500;
+ cfg_.rc_buf_optimal_sz = 600;
+ cfg_.rc_buf_sz = 1000;
+ cfg_.rc_min_quantizer = 2;
+ cfg_.rc_max_quantizer = 56;
+ cfg_.g_threads = 1;
+ cfg_.kf_max_dist = 9999;
+ cfg_.rc_target_bitrate = 1600;
+ cfg_.rc_overshoot_pct = 50;
+ cfg_.rc_undershoot_pct = 50;
+
+ cfg_.layer_target_bitrate[0] = 100;
+ cfg_.layer_target_bitrate[1] = 140;
+ cfg_.layer_target_bitrate[2] = 200;
+ cfg_.layer_target_bitrate[3] = 250;
+ cfg_.layer_target_bitrate[4] = 350;
+ cfg_.layer_target_bitrate[5] = 500;
+ cfg_.layer_target_bitrate[6] = 450;
+ cfg_.layer_target_bitrate[7] = 630;
+ cfg_.layer_target_bitrate[8] = 900;
+ }
+
+ 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_.rc_mode = VPX_CBR;
+ rc_cfg_.aq_mode = aq_mode_;
+
+ 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;
+ }
+ }
+ }
+
+ int aq_mode_;
+ std::unique_ptr<libvpx::VP9RateControlRTC> rc_api_;
+ libvpx::VP9RateControlRtcConfig rc_cfg_;
+ vpx_svc_extra_cfg_t svc_params_;
+ libvpx::VP9FrameParamsQpRTC frame_params_;
+ bool encoder_exit_;
+ int current_superframe_;
+ uint32_t sizes_[8];
+};
+
+TEST_P(RcInterfaceTest, OneLayer) { RunOneLayer(); }
+
+TEST_P(RcInterfaceTest, OneLayerVBRPeriodicKey) { RunOneLayerVBRPeriodicKey(); }
+
+TEST_P(RcInterfaceSvcTest, Svc) { RunSvc(); }
+
+VP9_INSTANTIATE_TEST_SUITE(RcInterfaceTest, ::testing::Values(0, 3),
+ ::testing::Values(VPX_CBR, VPX_VBR));
+VP9_INSTANTIATE_TEST_SUITE(RcInterfaceSvcTest, ::testing::Values(0, 3));
+} // namespace
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -4017,7 +4017,8 @@
if (frame_over_shoot_limit == 0) frame_over_shoot_limit = 1;
/* Are we are overshooting and up against the limit of active max Q. */
- if (((cpi->pass != 2) ||
+ if (!cpi->rt_always_update_correction_factor &&
+ ((cpi->pass != 2) ||
(cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER)) &&
(Q == cpi->active_worst_quality) &&
(cpi->active_worst_quality < cpi->worst_quality) &&
@@ -4446,8 +4447,7 @@
}
}
- if (cpi->rt_always_update_correction_factor || !active_worst_qchanged)
- vp8_update_rate_correction_factors(cpi, 2);
+ if (!active_worst_qchanged) vp8_update_rate_correction_factors(cpi, 2);
cpi->last_q[cm->frame_type] = cm->base_qindex;
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -327,7 +327,8 @@
int initial_boost = 32; /* |3.0 * per_frame_bandwidth| */
/* Boost depends somewhat on frame rate: only used for 1 layer case. */
if (cpi->oxcf.number_of_layers == 1) {
- kf_boost = VPXMAX(initial_boost, (int)(2 * cpi->output_framerate - 16));
+ kf_boost =
+ VPXMAX(initial_boost, (int)round(2 * cpi->output_framerate - 16));
} else {
/* Initial factor: set target size to: |3.0 * per_frame_bandwidth|. */
kf_boost = initial_boost;
--- /dev/null
+++ b/vp8/vp8_ratectrl_rtc.cc
@@ -1,0 +1,288 @@
+/*
+ * Copyright (c) 2021 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 <new>
+#include "vp8/vp8_ratectrl_rtc.h"
+#include "vp8/encoder/ratectrl.h"
+
+namespace libvpx {
+/* Quant MOD */
+static const int kQTrans[] = {
+ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19,
+ 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 35, 37, 39, 41,
+ 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 64, 67, 70, 73, 76, 79,
+ 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 127,
+};
+
+static const unsigned char kf_high_motion_minq[QINDEX_RANGE] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5,
+ 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10,
+ 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16,
+ 16, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
+ 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30
+};
+
+static const unsigned char inter_minq[QINDEX_RANGE] = {
+ 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11,
+ 11, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24,
+ 24, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38,
+ 39, 39, 40, 41, 42, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 50, 51, 52, 53,
+ 54, 55, 55, 56, 57, 58, 59, 60, 60, 61, 62, 63, 64, 65, 66, 67, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100
+};
+
+static int rescale(int val, int num, int denom) {
+ int64_t llnum = num;
+ int64_t llden = denom;
+ int64_t llval = val;
+
+ return (int)(llval * llnum / llden);
+}
+
+std::unique_ptr<VP8RateControlRTC> VP8RateControlRTC::Create(
+ const VP8RateControlRtcConfig &cfg) {
+ std::unique_ptr<VP8RateControlRTC> rc_api(new (std::nothrow)
+ VP8RateControlRTC());
+ if (!rc_api) return nullptr;
+ rc_api->cpi_ = static_cast<VP8_COMP *>(vpx_memalign(32, sizeof(*cpi_)));
+ if (!rc_api->cpi_) return nullptr;
+ vp8_zero(*rc_api->cpi_);
+
+ rc_api->InitRateControl(cfg);
+
+ return rc_api;
+}
+
+void VP8RateControlRTC::InitRateControl(const VP8RateControlRtcConfig &rc_cfg) {
+ VP8_COMMON *cm = &cpi_->common;
+ VP8_CONFIG *oxcf = &cpi_->oxcf;
+ oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
+ cpi_->pass = 0;
+ cm->show_frame = 1;
+ oxcf->drop_frames_water_mark = 0;
+ cm->current_video_frame = 0;
+ cpi_->auto_gold = 1;
+ cpi_->key_frame_count = 1;
+ cpi_->rate_correction_factor = 1.0;
+ cpi_->key_frame_rate_correction_factor = 1.0;
+ cpi_->cyclic_refresh_mode_enabled = 0;
+ cpi_->auto_worst_q = 1;
+ cpi_->kf_overspend_bits = 0;
+ cpi_->kf_bitrate_adjustment = 0;
+ cpi_->gf_overspend_bits = 0;
+ cpi_->non_gf_bitrate_adjustment = 0;
+ UpdateRateControl(rc_cfg);
+ cpi_->buffer_level = oxcf->starting_buffer_level;
+ cpi_->bits_off_target = oxcf->starting_buffer_level;
+}
+
+void VP8RateControlRTC::UpdateRateControl(
+ const VP8RateControlRtcConfig &rc_cfg) {
+ VP8_COMMON *cm = &cpi_->common;
+ VP8_CONFIG *oxcf = &cpi_->oxcf;
+
+ cm->Width = rc_cfg.width;
+ cm->Height = rc_cfg.height;
+ oxcf->Width = rc_cfg.width;
+ oxcf->Height = rc_cfg.height;
+ oxcf->worst_allowed_q = kQTrans[rc_cfg.max_quantizer];
+ oxcf->best_allowed_q = kQTrans[rc_cfg.min_quantizer];
+ cpi_->worst_quality = oxcf->worst_allowed_q;
+ cpi_->best_quality = oxcf->best_allowed_q;
+ cpi_->output_framerate = rc_cfg.framerate;
+ oxcf->target_bandwidth = 1000 * rc_cfg.target_bandwidth;
+ oxcf->fixed_q = -1;
+ oxcf->error_resilient_mode = 1;
+ oxcf->starting_buffer_level_in_ms = rc_cfg.buf_initial_sz;
+ oxcf->optimal_buffer_level_in_ms = rc_cfg.buf_optimal_sz;
+ oxcf->maximum_buffer_size_in_ms = rc_cfg.buf_sz;
+ oxcf->starting_buffer_level = rc_cfg.buf_initial_sz;
+ oxcf->optimal_buffer_level = rc_cfg.buf_optimal_sz;
+ oxcf->maximum_buffer_size = rc_cfg.buf_sz;
+ oxcf->number_of_layers = 1;
+ cpi_->buffered_mode = oxcf->optimal_buffer_level > 0;
+ oxcf->under_shoot_pct = rc_cfg.undershoot_pct;
+ oxcf->over_shoot_pct = rc_cfg.overshoot_pct;
+ cpi_->oxcf.rc_max_intra_bitrate_pct = rc_cfg.max_intra_bitrate_pct;
+ cpi_->framerate = rc_cfg.framerate;
+ for (int i = 0; i < KEY_FRAME_CONTEXT; ++i) {
+ cpi_->prior_key_frame_distance[i] =
+ static_cast<int>(cpi_->output_framerate);
+ }
+
+ cpi_->total_actual_bits = 0;
+ cpi_->total_target_vs_actual = 0;
+
+ cm->mb_rows = cm->Height >> 4;
+ cm->mb_cols = cm->Width >> 4;
+ cm->MBs = cm->mb_rows * cm->mb_cols;
+ cm->mode_info_stride = cm->mb_cols + 1;
+
+ oxcf->starting_buffer_level =
+ rescale((int)oxcf->starting_buffer_level, oxcf->target_bandwidth, 1000);
+ /* Set or reset optimal and maximum buffer levels. */
+ if (oxcf->optimal_buffer_level == 0) {
+ oxcf->optimal_buffer_level = oxcf->target_bandwidth / 8;
+ } else {
+ oxcf->optimal_buffer_level =
+ rescale((int)oxcf->optimal_buffer_level, oxcf->target_bandwidth, 1000);
+ }
+ if (oxcf->maximum_buffer_size == 0) {
+ oxcf->maximum_buffer_size = oxcf->target_bandwidth / 8;
+ } else {
+ oxcf->maximum_buffer_size =
+ rescale((int)oxcf->maximum_buffer_size, oxcf->target_bandwidth, 1000);
+ }
+
+ if (cpi_->bits_off_target > oxcf->maximum_buffer_size) {
+ cpi_->bits_off_target = oxcf->maximum_buffer_size;
+ cpi_->buffer_level = cpi_->bits_off_target;
+ }
+
+ vp8_new_framerate(cpi_, cpi_->framerate);
+}
+
+void VP8RateControlRTC::ComputeQP(const VP8FrameParamsQpRTC &frame_params) {
+ VP8_COMMON *const cm = &cpi_->common;
+ cm->frame_type = frame_params.frame_type;
+ cm->refresh_golden_frame = (cm->frame_type == KEY_FRAME) ? 1 : 0;
+ cm->refresh_alt_ref_frame = (cm->frame_type == KEY_FRAME) ? 1 : 0;
+ if (cm->frame_type == KEY_FRAME && cpi_->common.current_video_frame > 0) {
+ cpi_->common.frame_flags |= FRAMEFLAGS_KEY;
+ }
+
+ vp8_pick_frame_size(cpi_);
+
+ if (cpi_->buffer_level >= cpi_->oxcf.optimal_buffer_level &&
+ cpi_->buffered_mode) {
+ /* Max adjustment is 1/4 */
+ int Adjustment = cpi_->active_worst_quality / 4;
+ if (Adjustment) {
+ int buff_lvl_step;
+ if (cpi_->buffer_level < cpi_->oxcf.maximum_buffer_size) {
+ buff_lvl_step = (int)((cpi_->oxcf.maximum_buffer_size -
+ cpi_->oxcf.optimal_buffer_level) /
+ Adjustment);
+ if (buff_lvl_step) {
+ Adjustment =
+ (int)((cpi_->buffer_level - cpi_->oxcf.optimal_buffer_level) /
+ buff_lvl_step);
+ } else {
+ Adjustment = 0;
+ }
+ }
+ cpi_->active_worst_quality -= Adjustment;
+ if (cpi_->active_worst_quality < cpi_->active_best_quality) {
+ cpi_->active_worst_quality = cpi_->active_best_quality;
+ }
+ }
+ }
+
+ if (cpi_->ni_frames > 150) {
+ int q = cpi_->active_worst_quality;
+ if (cm->frame_type == KEY_FRAME) {
+ cpi_->active_best_quality = kf_high_motion_minq[q];
+ } else {
+ cpi_->active_best_quality = inter_minq[q];
+ }
+
+ if (cpi_->buffer_level >= cpi_->oxcf.maximum_buffer_size) {
+ cpi_->active_best_quality = cpi_->best_quality;
+
+ } else if (cpi_->buffer_level > cpi_->oxcf.optimal_buffer_level) {
+ int Fraction =
+ (int)(((cpi_->buffer_level - cpi_->oxcf.optimal_buffer_level) * 128) /
+ (cpi_->oxcf.maximum_buffer_size -
+ cpi_->oxcf.optimal_buffer_level));
+ int min_qadjustment =
+ ((cpi_->active_best_quality - cpi_->best_quality) * Fraction) / 128;
+
+ cpi_->active_best_quality -= min_qadjustment;
+ }
+ }
+
+ /* Clip the active best and worst quality values to limits */
+ if (cpi_->active_worst_quality > cpi_->worst_quality) {
+ cpi_->active_worst_quality = cpi_->worst_quality;
+ }
+ if (cpi_->active_best_quality < cpi_->best_quality) {
+ cpi_->active_best_quality = cpi_->best_quality;
+ }
+ if (cpi_->active_worst_quality < cpi_->active_best_quality) {
+ cpi_->active_worst_quality = cpi_->active_best_quality;
+ }
+
+ q_ = vp8_regulate_q(cpi_, cpi_->this_frame_target);
+ vp8_set_quantizer(cpi_, q_);
+}
+
+int VP8RateControlRTC::GetQP() const { return q_; }
+
+void VP8RateControlRTC::PostEncodeUpdate(uint64_t encoded_frame_size) {
+ VP8_COMMON *const cm = &cpi_->common;
+
+ cpi_->total_byte_count += encoded_frame_size;
+ cpi_->projected_frame_size = static_cast<int>(encoded_frame_size << 3);
+
+ vp8_update_rate_correction_factors(cpi_, 2);
+
+ cpi_->last_q[cm->frame_type] = cm->base_qindex;
+
+ if (cm->frame_type == KEY_FRAME) {
+ vp8_adjust_key_frame_context(cpi_);
+ }
+
+ /* Keep a record of ambient average Q. */
+ if (cm->frame_type != KEY_FRAME) {
+ cpi_->avg_frame_qindex =
+ (2 + 3 * cpi_->avg_frame_qindex + cm->base_qindex) >> 2;
+ }
+ /* Keep a record from which we can calculate the average Q excluding
+ * key frames.
+ */
+ if (cm->frame_type != KEY_FRAME) {
+ cpi_->ni_frames++;
+ /* Damp value for first few frames */
+ if (cpi_->ni_frames > 150) {
+ cpi_->ni_tot_qi += q_;
+ cpi_->ni_av_qi = (cpi_->ni_tot_qi / cpi_->ni_frames);
+ } else {
+ cpi_->ni_tot_qi += q_;
+ cpi_->ni_av_qi =
+ ((cpi_->ni_tot_qi / cpi_->ni_frames) + cpi_->worst_quality + 1) / 2;
+ }
+
+ /* If the average Q is higher than what was used in the last
+ * frame (after going through the recode loop to keep the frame
+ * size within range) then use the last frame value - 1. The -1
+ * is designed to stop Q and hence the data rate, from
+ * progressively falling away during difficult sections, but at
+ * the same time reduce the number of itterations around the
+ * recode loop.
+ */
+ if (q_ > cpi_->ni_av_qi) cpi_->ni_av_qi = q_ - 1;
+ }
+
+ cpi_->bits_off_target +=
+ cpi_->av_per_frame_bandwidth - cpi_->projected_frame_size;
+ if (cpi_->bits_off_target > cpi_->oxcf.maximum_buffer_size) {
+ cpi_->bits_off_target = cpi_->oxcf.maximum_buffer_size;
+ }
+
+ cpi_->total_actual_bits += cpi_->projected_frame_size;
+ cpi_->buffer_level = cpi_->bits_off_target;
+
+ cpi_->common.current_video_frame++;
+ cpi_->frames_since_key++;
+}
+} // namespace libvpx
--- /dev/null
+++ b/vp8/vp8_ratectrl_rtc.h
@@ -1,0 +1,62 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+
+#ifndef VPX_VP8_RATECTRL_RTC_H_
+#define VPX_VP8_RATECTRL_RTC_H_
+
+#include <cstdint>
+#include <memory>
+
+#include "vp8/encoder/onyx_int.h"
+#include "vp8/common/common.h"
+#include "vpx/internal/vpx_ratectrl_rtc.h"
+
+namespace libvpx {
+struct VP8RateControlRtcConfig : public VpxRateControlRtcConfig {
+ public:
+ VP8RateControlRtcConfig() {
+ vp8_zero(layer_target_bitrate);
+ vp8_zero(ts_rate_decimator);
+ }
+};
+
+struct VP8FrameParamsQpRTC {
+ FRAME_TYPE frame_type;
+};
+
+class VP8RateControlRTC {
+ public:
+ static std::unique_ptr<VP8RateControlRTC> Create(
+ const VP8RateControlRtcConfig &cfg);
+ ~VP8RateControlRTC() {
+ if (cpi_) {
+ vpx_free(cpi_->gf_active_flags);
+ vpx_free(cpi_);
+ }
+ }
+
+ void UpdateRateControl(const VP8RateControlRtcConfig &rc_cfg);
+ // GetQP() needs to be called after ComputeQP() to get the latest QP
+ int GetQP() const;
+ // int GetLoopfilterLevel() const;
+ void ComputeQP(const VP8FrameParamsQpRTC &frame_params);
+ // Feedback to rate control with the size of current encoded frame
+ void PostEncodeUpdate(uint64_t encoded_frame_size);
+
+ private:
+ VP8RateControlRTC() {}
+ void InitRateControl(const VP8RateControlRtcConfig &cfg);
+ VP8_COMP *cpi_;
+ int q_;
+};
+
+} // namespace libvpx
+
+#endif // VPX_VP8_RATECTRL_RTC_H_
--- a/vp9/ratectrl_rtc.h
+++ b/vp9/ratectrl_rtc.h
@@ -22,28 +22,14 @@
#include "vp9/encoder/vp9_encoder.h"
#include "vp9/encoder/vp9_firstpass.h"
#include "vp9/vp9_cx_iface.h"
+#include "vpx/internal/vpx_ratectrl_rtc.h"
#include "vpx_mem/vpx_mem.h"
namespace libvpx {
-struct VP9RateControlRtcConfig {
+struct VP9RateControlRtcConfig : public VpxRateControlRtcConfig {
public:
VP9RateControlRtcConfig() {
- width = 1280;
- height = 720;
- max_quantizer = 63;
- min_quantizer = 2;
- target_bandwidth = 1000;
- buf_initial_sz = 600;
- buf_optimal_sz = 600;
- buf_sz = 1000;
- undershoot_pct = overshoot_pct = 50;
- max_intra_bitrate_pct = 50;
- max_inter_bitrate_pct = 0;
- framerate = 30.0;
- ss_number_layers = ts_number_layers = 1;
- rc_mode = VPX_CBR;
- aq_mode = 0;
vp9_zero(max_quantizers);
vp9_zero(min_quantizers);
vp9_zero(scaling_factor_den);
@@ -52,26 +38,10 @@
vp9_zero(ts_rate_decimator);
scaling_factor_num[0] = 1;
scaling_factor_den[0] = 1;
- layer_target_bitrate[0] = static_cast<int>(target_bandwidth);
max_quantizers[0] = max_quantizer;
min_quantizers[0] = min_quantizer;
- ts_rate_decimator[0] = 1;
}
- int width;
- int height;
- // 0-63
- int max_quantizer;
- int min_quantizer;
- int64_t target_bandwidth;
- int64_t buf_initial_sz;
- int64_t buf_optimal_sz;
- int64_t buf_sz;
- int undershoot_pct;
- int overshoot_pct;
- int max_intra_bitrate_pct;
- int max_inter_bitrate_pct;
- double framerate;
// Number of spatial layers
int ss_number_layers;
// Number of temporal layers
@@ -80,11 +50,6 @@
int min_quantizers[VPX_MAX_LAYERS];
int scaling_factor_num[VPX_SS_MAX_LAYERS];
int scaling_factor_den[VPX_SS_MAX_LAYERS];
- int layer_target_bitrate[VPX_MAX_LAYERS];
- int ts_rate_decimator[VPX_TS_MAX_LAYERS];
- // vbr, cbr
- enum vpx_rc_mode rc_mode;
- int aq_mode;
};
struct VP9FrameParamsQpRTC {
@@ -94,7 +59,7 @@
};
// This interface allows using VP9 real-time rate control without initializing
-// the encoder. To use this interface, you need to link with libvp9rc.a.
+// the encoder. To use this interface, you need to link with libvpxrc.a.
//
// #include "vp9/ratectrl_rtc.h"
// VP9RateControlRTC rc_api;
--- /dev/null
+++ b/vpx/internal/vpx_ratectrl_rtc.h
@@ -1,0 +1,62 @@
+/*
+ * Copyright (c) 2021 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.
+ */
+
+#ifndef VPX_VPX_RATECTRL_RTC_H_
+#define VPX_VPX_RATECTRL_RTC_H_
+
+#include "vpx/vpx_encoder.h"
+
+namespace libvpx {
+struct VpxRateControlRtcConfig {
+ public:
+ VpxRateControlRtcConfig() {
+ width = 1280;
+ height = 720;
+ max_quantizer = 63;
+ min_quantizer = 2;
+ target_bandwidth = 1000;
+ buf_initial_sz = 600;
+ buf_optimal_sz = 600;
+ buf_sz = 1000;
+ undershoot_pct = overshoot_pct = 50;
+ max_intra_bitrate_pct = 50;
+ max_inter_bitrate_pct = 0;
+ framerate = 30.0;
+ ts_number_layers = 1;
+ rc_mode = VPX_CBR;
+ aq_mode = 0;
+ layer_target_bitrate[0] = static_cast<int>(target_bandwidth);
+ ts_rate_decimator[0] = 1;
+ }
+
+ int width;
+ int height;
+ // 0-63
+ int max_quantizer;
+ int min_quantizer;
+ int64_t target_bandwidth;
+ int64_t buf_initial_sz;
+ int64_t buf_optimal_sz;
+ int64_t buf_sz;
+ int undershoot_pct;
+ int overshoot_pct;
+ int max_intra_bitrate_pct;
+ int max_inter_bitrate_pct;
+ double framerate;
+ // Number of temporal layers
+ int ts_number_layers;
+ int layer_target_bitrate[VPX_MAX_LAYERS];
+ int ts_rate_decimator[VPX_TS_MAX_LAYERS];
+ // vbr, cbr
+ enum vpx_rc_mode rc_mode;
+ int aq_mode;
+};
+} // namespace libvpx
+#endif
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -747,7 +747,7 @@
*
* This will turn off cyclic refresh for vp8.
*
- * With those, the rate control is expected to work exactly the same as the
+ * With this, the rate control is expected to work exactly the same as the
* interface provided in vp8_ratectrl_rtc.cc/h
*
* Supported in codecs: VP8
--- a/vpx/vpx_codec.mk
+++ b/vpx/vpx_codec.mk
@@ -33,6 +33,7 @@
API_SRCS-yes += src/vpx_encoder.c
API_SRCS-yes += vpx_encoder.h
API_SRCS-yes += internal/vpx_codec_internal.h
+API_SRCS-yes += internal/vpx_ratectrl_rtc.h
API_SRCS-yes += src/vpx_codec.c
API_SRCS-yes += src/vpx_image.c
API_SRCS-yes += vpx_codec.h