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));