Commit 40b50c6f55 for aom
commit 40b50c6f556df8df4e9876ffcdf842fbfd0d25b4
Author: Marco Paniconi <marpan@google.com>
Date: Wed Apr 15 21:02:04 2026 -0700
rtc-rc: Checks limts on inputs to external rc
Add checks to inputs and add rc_is_valid_ flag
to disallow invalid inputs/updates to the
external rc.
Added unittest to check some invalid inputs.
Bug: 501657371
Change-Id: Ib5fd66b121a347be97aaf434fe42d3cce0bd744e
diff --git a/av1/ratectrl_rtc.cc b/av1/ratectrl_rtc.cc
index 363521eabc..238484f4db 100644
--- a/av1/ratectrl_rtc.cc
+++ b/av1/ratectrl_rtc.cc
@@ -122,6 +122,7 @@ std::unique_ptr<AV1RateControlRTC> AV1RateControlRTC::Create(
cpi->common.mi_params.mi_rows, cpi->common.mi_params.mi_cols);
if (!cpi->cyclic_refresh) return nullptr;
}
+ rc_api->rc_is_valid_ = true;
return rc_api;
}
@@ -193,6 +194,7 @@ bool AV1RateControlRTC::InitRateControl(const AV1RateControlRtcConfig &rc_cfg) {
// Enable external rate control.
cpi_->rc.rtc_external_ratectrl = 1;
cpi_->sf.rt_sf.use_nonrd_pick_mode = 1;
+ rc_is_valid_ = true;
return true;
}
@@ -202,6 +204,7 @@ bool AV1RateControlRTC::UpdateRateControl(
rc_cfg.ss_number_layers > AOM_MAX_SS_LAYERS ||
rc_cfg.ts_number_layers < 1 ||
rc_cfg.ts_number_layers > AOM_MAX_TS_LAYERS) {
+ rc_is_valid_ = false;
return false;
}
if (cpi_->svc.number_spatial_layers != rc_cfg.ss_number_layers ||
@@ -209,11 +212,18 @@ bool AV1RateControlRTC::UpdateRateControl(
av1_free_svc_cyclic_refresh(cpi_);
const int num_layers = rc_cfg.ss_number_layers * rc_cfg.ts_number_layers;
if (num_layers > 1 && !av1_alloc_layer_context(cpi_, num_layers)) {
+ rc_is_valid_ = false;
return false;
}
AV1_COMMON *cm = &cpi_->common;
AV1EncoderConfig *oxcf = &cpi_->oxcf;
RATE_CONTROL *const rc = &cpi_->rc;
+ if (oxcf->frm_dim_cfg.width && oxcf->frm_dim_cfg.height &&
+ (rc_cfg.width > oxcf->frm_dim_cfg.width ||
+ rc_cfg.height > oxcf->frm_dim_cfg.height)) {
+ rc_is_valid_ = false;
+ return false;
+ }
initial_width_ = rc_cfg.width;
initial_height_ = rc_cfg.height;
cm->width = rc_cfg.width;
@@ -260,14 +270,26 @@ bool AV1RateControlRTC::UpdateRateControl(
LAYER_CONTEXT *lc = &cpi_->svc.layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc;
lc->layer_target_bitrate = 1000 * rc_cfg.layer_target_bitrate[layer];
+ if (rc_cfg.max_quantizers[layer] > 63 ||
+ rc_cfg.min_quantizers[layer] < 0 ||
+ rc_cfg.min_quantizers[layer] > rc_cfg.max_quantizers[layer]) {
+ rc_is_valid_ = false;
+ return false;
+ }
lc->max_q = rc_cfg.max_quantizers[layer];
lc->min_q = rc_cfg.min_quantizers[layer];
lrc->worst_quality =
av1_quantizer_to_qindex(rc_cfg.max_quantizers[layer]);
lrc->best_quality =
av1_quantizer_to_qindex(rc_cfg.min_quantizers[layer]);
- lc->scaling_factor_num = rc_cfg.scaling_factor_num[sl];
- lc->scaling_factor_den = rc_cfg.scaling_factor_den[sl];
+ // spatial scaling (scaling_factor_num[]/den[]) is always to a lower
+ // resolution, so den must be >= num.
+ if (rc_cfg.scaling_factor_den[sl] < rc_cfg.scaling_factor_num[sl]) {
+ rc_is_valid_ = false;
+ return false;
+ }
+ lc->scaling_factor_num = AOMMAX(1, rc_cfg.scaling_factor_num[sl]);
+ lc->scaling_factor_den = AOMMAX(1, rc_cfg.scaling_factor_den[sl]);
lc->framerate_factor = rc_cfg.ts_rate_decimator[tl];
if (tl == cpi_->svc.number_temporal_layers - 1)
target_bandwidth_svc += lc->layer_target_bitrate;
@@ -284,11 +306,20 @@ bool AV1RateControlRTC::UpdateRateControl(
DISABLE_SETJMP(cpi_);
}
check_reset_rc_flag(cpi_);
+ rc_is_valid_ = true;
return true;
}
FrameDropDecision AV1RateControlRTC::ComputeQP(
const AV1FrameParamsRTC &frame_params) {
+ if (!rc_is_valid_) return kFrameDropDecisionDrop;
+ if (frame_params.spatial_layer_id < 0 ||
+ frame_params.spatial_layer_id >= cpi_->svc.number_spatial_layers ||
+ frame_params.temporal_layer_id < 0 ||
+ frame_params.temporal_layer_id >= cpi_->svc.number_temporal_layers ||
+ initial_width_ == 0 || initial_height_ == 0) {
+ return kFrameDropDecisionDrop;
+ }
AV1_COMMON *const cm = &cpi_->common;
int width, height;
GF_GROUP *const gf_group = &cpi_->ppi->gf_group;
@@ -380,31 +411,47 @@ FrameDropDecision AV1RateControlRTC::ComputeQP(
}
int AV1RateControlRTC::GetQP() const {
- return cpi_->common.quant_params.base_qindex;
+ if (rc_is_valid_) return cpi_->common.quant_params.base_qindex;
+ return 0;
}
AV1LoopfilterLevel AV1RateControlRTC::GetLoopfilterLevel() const {
- av1_pick_filter_level(nullptr, cpi_, LPF_PICK_FROM_Q);
AV1LoopfilterLevel lpf_level;
- lpf_level.filter_level[0] = cpi_->common.lf.filter_level[0];
- lpf_level.filter_level[1] = cpi_->common.lf.filter_level[1];
- lpf_level.filter_level_u = cpi_->common.lf.filter_level_u;
- lpf_level.filter_level_v = cpi_->common.lf.filter_level_v;
+ if (rc_is_valid_) {
+ av1_pick_filter_level(nullptr, cpi_, LPF_PICK_FROM_Q);
+ lpf_level.filter_level[0] = cpi_->common.lf.filter_level[0];
+ lpf_level.filter_level[1] = cpi_->common.lf.filter_level[1];
+ lpf_level.filter_level_u = cpi_->common.lf.filter_level_u;
+ lpf_level.filter_level_v = cpi_->common.lf.filter_level_v;
+ } else {
+ lpf_level.filter_level[0] = 0;
+ lpf_level.filter_level[1] = 0;
+ lpf_level.filter_level_u = 0;
+ lpf_level.filter_level_v = 0;
+ }
return lpf_level;
}
AV1CdefInfo AV1RateControlRTC::GetCdefInfo() const {
- av1_pick_cdef_from_qp(&cpi_->common, /*skip_cdef=*/0, /*is_screen_content=*/0,
- /*avoid_uv_cdef=*/false);
AV1CdefInfo cdef_level;
- cdef_level.cdef_strength_y = cpi_->common.cdef_info.cdef_strengths[0];
- cdef_level.cdef_strength_uv = cpi_->common.cdef_info.cdef_uv_strengths[0];
- cdef_level.damping = cpi_->common.cdef_info.cdef_damping;
+ if (rc_is_valid_) {
+ av1_pick_cdef_from_qp(&cpi_->common, /*skip_cdef=*/0,
+ /*is_screen_content=*/0,
+ /*avoid_uv_cdef=*/false);
+ cdef_level.cdef_strength_y = cpi_->common.cdef_info.cdef_strengths[0];
+ cdef_level.cdef_strength_uv = cpi_->common.cdef_info.cdef_uv_strengths[0];
+ cdef_level.damping = cpi_->common.cdef_info.cdef_damping;
+ } else {
+ cdef_level.cdef_strength_y = 0;
+ cdef_level.cdef_strength_uv = 0;
+ cdef_level.damping = 0;
+ }
return cdef_level;
}
bool AV1RateControlRTC::GetSegmentationData(
AV1SegmentationData *segmentation_data) const {
+ if (!rc_is_valid_) return false;
if (cpi_->oxcf.q_cfg.aq_mode == 0) {
return false;
}
@@ -421,6 +468,7 @@ bool AV1RateControlRTC::GetSegmentationData(
}
void AV1RateControlRTC::PostEncodeUpdate(uint64_t encoded_frame_size) {
+ if (!rc_is_valid_) return;
cpi_->common.current_frame.frame_number++;
av1_rc_postencode_update(cpi_, encoded_frame_size);
if (cpi_->svc.spatial_layer_id == cpi_->svc.number_spatial_layers - 1) {
diff --git a/av1/ratectrl_rtc.h b/av1/ratectrl_rtc.h
index 3d0807b604..0eeaa68797 100644
--- a/av1/ratectrl_rtc.h
+++ b/av1/ratectrl_rtc.h
@@ -148,6 +148,7 @@ class AV1RateControlRTC {
AV1_COMP *cpi_;
int initial_width_;
int initial_height_;
+ bool rc_is_valid_ = false;
};
} // namespace aom
#endif // __cplusplus
diff --git a/test/ratectrl_rtc_test.cc b/test/ratectrl_rtc_test.cc
index 8d7e64258e..dc204e9462 100644
--- a/test/ratectrl_rtc_test.cc
+++ b/test/ratectrl_rtc_test.cc
@@ -258,6 +258,34 @@ class RcInterfaceTest : public ::libaom_test::EncoderTest,
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}
+ void RunSvcInvalidInputs() {
+ key_interval_ = 10000;
+ // Initial resolution is set to 640x480.
+ SetConfigSvc(3, 3);
+ rc_api_ = aom::AV1RateControlRTC::Create(rc_cfg_);
+ // Verfiy return false on UpdateRateControl if resolution goes above
+ // configured setting.
+ rc_cfg_.width = 1280;
+ rc_cfg_.height = 720;
+ ASSERT_FALSE(rc_api_->UpdateRateControl(rc_cfg_));
+ // Go back to original resolution.
+ rc_cfg_.width = 640;
+ rc_cfg_.height = 480;
+ ASSERT_TRUE(rc_api_->UpdateRateControl(rc_cfg_));
+ // Set layer_id beyond the range set in init (#spatial=3, #temporal=3).
+ // Expect ComputeQP() to return kFrameDropDecisionDrop.
+ frame_params_.spatial_layer_id = 4;
+ frame_params_.temporal_layer_id = 0;
+ ASSERT_EQ(rc_api_->ComputeQP(frame_params_), aom::kFrameDropDecisionDrop);
+ frame_params_.spatial_layer_id = 0;
+ frame_params_.temporal_layer_id = 4;
+ ASSERT_EQ(rc_api_->ComputeQP(frame_params_), aom::kFrameDropDecisionDrop);
+ // Start with valid (0, 0) layer_id, expect return kFrameDropDecisionOk.
+ frame_params_.spatial_layer_id = 0;
+ frame_params_.temporal_layer_id = 0;
+ ASSERT_EQ(rc_api_->ComputeQP(frame_params_), aom::kFrameDropDecisionOk);
+ }
+
void RunSvc() {
key_interval_ = 10000;
SetConfigSvc(3, 3);
@@ -684,6 +712,8 @@ TEST_P(RcInterfaceTest, OneLayerPeriodicKey) { RunOneLayerPeriodicKey(); }
TEST_P(RcInterfaceTest, OneLayerScreen) { RunOneLayerScreen(); }
+TEST_P(RcInterfaceTest, SvcInvalidInputs) { RunSvcInvalidInputs(); }
+
TEST_P(RcInterfaceTest, Svc) { RunSvc(); }
TEST_P(RcInterfaceTest, SvcPeriodicKey) { RunSvcPeriodicKey(); }