Commit 9768675263 for aom
commit 976867526367f571a1c09b994066af8364aed781
Author: Jerome Jiang <jianj@google.com>
Date: Thu Aug 27 12:46:23 2026 -0400
rtc: Add bit-depth support to external rate controller
Add bit_depth to AomAV1RateControlRtcConfig so callers can specify
the bit depth (8, 10, or 12) for standalone AV1 real-time rate control.
Previously, bit-depth was hardcoded to 8-bit in InitRateControl,
causing 10-bit encoding to estimate a weaker loopfilter level and
incorrect active quantizer parameters.
Add unit tests validating bit_depth initialization, invalid values,
dynamic update rejection, and 10-bit vs 8-bit loopfilter level estimation.
BUG=544795255
TAG=agy
CONV=851e7ad7-a30f-4721-84cf-0a5b1c3f2ea3
Change-Id: I570ab437a433f0ee236b07d055866e7e42a2eb1c
diff --git a/av1/ratectrl_rtc.cc b/av1/ratectrl_rtc.cc
index 238484f4db..6f76c8db45 100644
--- a/av1/ratectrl_rtc.cc
+++ b/av1/ratectrl_rtc.cc
@@ -63,6 +63,7 @@ void AomAV1RateControlRtcConfigInitDefault(AomAV1RateControlRtcConfig *config) {
config->min_quantizers[0] = config->min_quantizer;
config->scaling_factor_num[0] = 1;
config->scaling_factor_den[0] = 1;
+ config->bit_depth = 8;
}
} // namespace
@@ -156,8 +157,13 @@ bool AV1RateControlRTC::InitRateControl(const AV1RateControlRtcConfig &rc_cfg) {
AV1_COMMON *cm = &cpi_->common;
AV1EncoderConfig *oxcf = &cpi_->oxcf;
RATE_CONTROL *const rc = &cpi_->rc;
- cm->seq_params->profile = PROFILE_0;
- cm->seq_params->bit_depth = AOM_BITS_8;
+ const int bit_depth = rc_cfg.bit_depth == 0 ? 8 : rc_cfg.bit_depth;
+ if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) return false;
+#if !CONFIG_AV1_HIGHBITDEPTH
+ if (bit_depth > 8) return false;
+#endif
+ cm->seq_params->profile = (bit_depth == 12) ? PROFILE_2 : PROFILE_0;
+ cm->seq_params->bit_depth = static_cast<aom_bit_depth_t>(bit_depth);
cm->show_frame = 1;
oxcf->profile = cm->seq_params->profile;
oxcf->mode = REALTIME;
@@ -171,7 +177,7 @@ bool AV1RateControlRTC::InitRateControl(const AV1RateControlRtcConfig &rc_cfg) {
ceil(cpi_->framerate * rc_cfg.max_consec_drop_ms / 1000));
}
cpi_->svc.framedrop_mode = AOM_FULL_SUPERFRAME_DROP;
- oxcf->tool_cfg.bit_depth = AOM_BITS_8;
+ oxcf->tool_cfg.bit_depth = cm->seq_params->bit_depth;
oxcf->tool_cfg.superblock_size = AOM_SUPERBLOCK_SIZE_DYNAMIC;
oxcf->algo_cfg.loopfilter_control = LOOPFILTER_ALL;
cm->current_frame.frame_number = 0;
@@ -207,6 +213,12 @@ bool AV1RateControlRTC::UpdateRateControl(
rc_is_valid_ = false;
return false;
}
+ if (rc_cfg.bit_depth != 0 &&
+ rc_cfg.bit_depth !=
+ static_cast<int>(cpi_->common.seq_params->bit_depth)) {
+ rc_is_valid_ = false;
+ return false;
+ }
if (cpi_->svc.number_spatial_layers != rc_cfg.ss_number_layers ||
cpi_->svc.number_temporal_layers != rc_cfg.ts_number_layers)
av1_free_svc_cyclic_refresh(cpi_);
diff --git a/av1/ratectrl_rtc.h b/av1/ratectrl_rtc.h
index 0eeaa68797..f3bbe3b1cd 100644
--- a/av1/ratectrl_rtc.h
+++ b/av1/ratectrl_rtc.h
@@ -97,6 +97,8 @@ typedef struct AomAV1RateControlRtcConfig {
int min_quantizers[kAomAV1MaxLayers];
int scaling_factor_num[kAomAV1MaxSpatialLayers];
int scaling_factor_den[kAomAV1MaxSpatialLayers];
+ // Bit-depth (8, 10, or 12).
+ int bit_depth;
} AomAV1RateControlRtcConfig;
struct AomAV1RateControlRTC;
diff --git a/test/ratectrl_rtc_test.cc b/test/ratectrl_rtc_test.cc
index 4760d39042..8c78673bf2 100644
--- a/test/ratectrl_rtc_test.cc
+++ b/test/ratectrl_rtc_test.cc
@@ -551,6 +551,8 @@ class RcExternMethodsInterfaceTest
void TestGetCdefInfoRateControl();
void TestCreateRateControlConfig();
void TestDestroyRateControlRTC();
+ void TestBitDepthRateControl();
+ void TestLoopFilterLevelBitDepth();
void SetConfig();
private:
@@ -694,7 +696,7 @@ void RcExternMethodsInterfaceTest::TestCreateRateControlConfig() {
av1_ratecontrol_rtc_init_ratecontrol_config(&config);
ASSERT_EQ(config.width, 1280);
ASSERT_EQ(config.height, 720);
- // only width and height is checked. can be extended
+ ASSERT_EQ(config.bit_depth, 8);
av1_ratecontrol_rtc_destroy(controller);
}
@@ -706,6 +708,81 @@ void RcExternMethodsInterfaceTest::TestDestroyRateControlRTC() {
av1_ratecontrol_rtc_destroy(controller);
}
+void RcExternMethodsInterfaceTest::TestBitDepthRateControl() {
+ // Invalid bit-depth values should fail.
+ rc_cfg_.bit_depth = 9;
+ AomAV1RateControlRTC *invalid_controller =
+ av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_EQ(invalid_controller, nullptr);
+
+ rc_cfg_.bit_depth = -1;
+ invalid_controller = av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_EQ(invalid_controller, nullptr);
+
+ rc_cfg_.bit_depth = 14;
+ invalid_controller = av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_EQ(invalid_controller, nullptr);
+
+ // 8-bit depth is always supported.
+ rc_cfg_.bit_depth = 8;
+ AomAV1RateControlRTC *controller_8 = av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_NE(controller_8, nullptr);
+ // Attempting to change bit-depth dynamically should fail.
+ rc_cfg_.bit_depth = 10;
+ ASSERT_FALSE(av1_ratecontrol_rtc_update(controller_8, &rc_cfg_));
+ av1_ratecontrol_rtc_destroy(controller_8);
+
+#if CONFIG_AV1_HIGHBITDEPTH
+ rc_cfg_.bit_depth = 10;
+ AomAV1RateControlRTC *controller_10 = av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_NE(controller_10, nullptr);
+ rc_cfg_.bit_depth = 8;
+ ASSERT_FALSE(av1_ratecontrol_rtc_update(controller_10, &rc_cfg_));
+ av1_ratecontrol_rtc_destroy(controller_10);
+
+ rc_cfg_.bit_depth = 12;
+ AomAV1RateControlRTC *controller_12 = av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_NE(controller_12, nullptr);
+ av1_ratecontrol_rtc_destroy(controller_12);
+#else
+ rc_cfg_.bit_depth = 10;
+ ASSERT_EQ(av1_ratecontrol_rtc_create(&rc_cfg_), nullptr);
+ rc_cfg_.bit_depth = 12;
+ ASSERT_EQ(av1_ratecontrol_rtc_create(&rc_cfg_), nullptr);
+#endif
+}
+
+void RcExternMethodsInterfaceTest::TestLoopFilterLevelBitDepth() {
+#if CONFIG_AV1_HIGHBITDEPTH
+ frame_params_.spatial_layer_id = 0;
+ frame_params_.temporal_layer_id = 0;
+ frame_params_.frame_type = kAomKeyFrame;
+
+ rc_cfg_.bit_depth = 8;
+ AomAV1RateControlRTC *controller_8 = av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_NE(controller_8, nullptr);
+ ASSERT_EQ(av1_ratecontrol_rtc_compute_qp(controller_8, &frame_params_),
+ kAomFrameDropDecisionOk);
+ const AomAV1LoopfilterLevel lpf_8 =
+ av1_ratecontrol_rtc_get_loop_filter_level(controller_8);
+ av1_ratecontrol_rtc_destroy(controller_8);
+
+ rc_cfg_.bit_depth = 10;
+ AomAV1RateControlRTC *controller_10 = av1_ratecontrol_rtc_create(&rc_cfg_);
+ ASSERT_NE(controller_10, nullptr);
+ ASSERT_EQ(av1_ratecontrol_rtc_compute_qp(controller_10, &frame_params_),
+ kAomFrameDropDecisionOk);
+ const AomAV1LoopfilterLevel lpf_10 =
+ av1_ratecontrol_rtc_get_loop_filter_level(controller_10);
+ av1_ratecontrol_rtc_destroy(controller_10);
+
+ // For 10-bit AV1 encoding, the estimated loopfilter level should be stronger
+ // than for 8-bit at the same configuration.
+ EXPECT_GT(lpf_10.filter_level[0], lpf_8.filter_level[0]);
+ EXPECT_GT(lpf_10.filter_level[1], lpf_8.filter_level[1]);
+#endif // CONFIG_AV1_HIGHBITDEPTH
+}
+
TEST_P(RcInterfaceTest, OneLayer) { RunOneLayer(); }
TEST_P(RcInterfaceTest, OneLayerDropFramesCBR) { RunOneLayerDropFramesCBR(); }
@@ -764,6 +841,14 @@ TEST_P(RcExternMethodsInterfaceTest, DestroyRateControlRTCTest) {
TestDestroyRateControlRTC();
}
+TEST_P(RcExternMethodsInterfaceTest, BitDepthRateControllerTest) {
+ TestBitDepthRateControl();
+}
+
+TEST_P(RcExternMethodsInterfaceTest, LoopFilterLevelBitDepthTest) {
+ TestLoopFilterLevelBitDepth();
+}
+
AV1_INSTANTIATE_TEST_SUITE(RcInterfaceTest, ::testing::Values(0, 3));
AV1_INSTANTIATE_TEST_SUITE(RcExternMethodsInterfaceTest,
::testing::Values(0, 3));