rtc: Fixes to rate control under bandwidth change
Reset buffer level when there is significant change
in bandwidth via change_config, for both 1 layer and svc.
Also clamp the buffer_level to maximum_buffer_size in
set_rc_buffer_sizes().
This allows better response in rate control for CBR mode
when the application changes the bitrate on the fly.
Change-Id: I9ddb889c4a0ca3eb60484b127734a14b91f4c269
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index b668ebf..9e69f89 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -735,7 +735,7 @@
av1_set_high_precision_mv(cpi, 1, 0);
- set_rc_buffer_sizes(p_rc, rc_cfg);
+ set_rc_buffer_sizes(cpi);
// Under a configuration change, where maximum_buffer_size may change,
// keep buffer level clipped to the maximum allowed buffer size.
@@ -815,6 +815,8 @@
if (cpi->ppi->use_svc)
av1_update_layer_context_change_config(cpi, rc_cfg->target_bandwidth);
+ check_reset_rc_flag(cpi);
+
// restore the value of lag_in_frame for LAP stage.
if (lap_lag_in_frames != -1) {
cpi->oxcf.gf_cfg.lag_in_frames = lap_lag_in_frames;
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index b5b9158..7c5e76e 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1882,6 +1882,7 @@
cpi->rc.frames_to_key--;
cpi->rc.rc_2_frame = 0;
cpi->rc.rc_1_frame = 0;
+ cpi->rc.prev_avg_frame_bandwidth = cpi->rc.avg_frame_bandwidth;
}
int av1_find_qindex(double desired_q, aom_bit_depth_t bit_depth,
diff --git a/av1/encoder/rc_utils.h b/av1/encoder/rc_utils.h
index df77357..0a9d02d 100644
--- a/av1/encoder/rc_utils.h
+++ b/av1/encoder/rc_utils.h
@@ -19,8 +19,30 @@
extern "C" {
#endif
-static AOM_INLINE void set_rc_buffer_sizes(PRIMARY_RATE_CONTROL *p_rc,
- const RateControlCfg *rc_cfg) {
+static AOM_INLINE void check_reset_rc_flag(AV1_COMP *cpi) {
+ RATE_CONTROL *rc = &cpi->rc;
+ PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
+ if (cpi->common.current_frame.frame_number >
+ (unsigned int)cpi->svc.number_spatial_layers) {
+ if (cpi->ppi->use_svc) {
+ av1_svc_check_reset_layer_rc_flag(cpi);
+ } else {
+ if (rc->avg_frame_bandwidth > (3 * rc->prev_avg_frame_bandwidth >> 1) ||
+ rc->avg_frame_bandwidth < (rc->prev_avg_frame_bandwidth >> 1)) {
+ rc->rc_1_frame = 0;
+ rc->rc_2_frame = 0;
+ rc->bits_off_target = p_rc->optimal_buffer_level;
+ rc->buffer_level = p_rc->optimal_buffer_level;
+ }
+ }
+ }
+}
+
+static AOM_INLINE void set_rc_buffer_sizes(AV1_COMP *cpi) {
+ RATE_CONTROL *rc = &cpi->rc;
+ PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
+ const RateControlCfg *const rc_cfg = &cpi->oxcf.rc_cfg;
+
const int64_t bandwidth = rc_cfg->target_bandwidth;
const int64_t starting = rc_cfg->starting_buffer_level_ms;
const int64_t optimal = rc_cfg->optimal_buffer_level_ms;
@@ -31,6 +53,11 @@
(optimal == 0) ? bandwidth / 8 : optimal * bandwidth / 1000;
p_rc->maximum_buffer_size =
(maximum == 0) ? bandwidth / 8 : maximum * bandwidth / 1000;
+
+ // Under a configuration change, where maximum_buffer_size may change,
+ // keep buffer level clipped to the maximum allowed buffer size.
+ rc->bits_off_target = AOMMIN(rc->bits_off_target, p_rc->maximum_buffer_size);
+ rc->buffer_level = AOMMIN(rc->buffer_level, p_rc->maximum_buffer_size);
}
static AOM_INLINE void config_target_level(AV1_COMP *const cpi,
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c
index 0ad0cf6..5cff958 100644
--- a/av1/encoder/svc_layercontext.c
+++ b/av1/encoder/svc_layercontext.c
@@ -488,3 +488,28 @@
}
}
}
+
+void av1_svc_check_reset_layer_rc_flag(AV1_COMP *const cpi) {
+ SVC *const svc = &cpi->svc;
+ for (int sl = 0; sl < svc->number_spatial_layers; ++sl) {
+ // Check for reset based on avg_frame_bandwidth for spatial layer sl.
+ int layer = LAYER_IDS_TO_IDX(sl, svc->number_temporal_layers - 1,
+ svc->number_temporal_layers);
+ LAYER_CONTEXT *lc = &svc->layer_context[layer];
+ RATE_CONTROL *lrc = &lc->rc;
+ if (lrc->avg_frame_bandwidth > (3 * lrc->prev_avg_frame_bandwidth >> 1) ||
+ lrc->avg_frame_bandwidth < (lrc->prev_avg_frame_bandwidth >> 1)) {
+ // Reset for all temporal layers with spatial layer sl.
+ for (int tl = 0; tl < svc->number_temporal_layers; ++tl) {
+ int layer2 = LAYER_IDS_TO_IDX(sl, tl, svc->number_temporal_layers);
+ LAYER_CONTEXT *lc2 = &svc->layer_context[layer2];
+ RATE_CONTROL *lrc2 = &lc2->rc;
+ PRIMARY_RATE_CONTROL *const lp_rc = &lc2->p_rc;
+ lrc2->rc_1_frame = 0;
+ lrc2->rc_2_frame = 0;
+ lrc2->bits_off_target = lp_rc->optimal_buffer_level;
+ lrc2->buffer_level = lp_rc->optimal_buffer_level;
+ }
+ }
+ }
+}
diff --git a/av1/encoder/svc_layercontext.h b/av1/encoder/svc_layercontext.h
index 5ceaf0f..817e362 100644
--- a/av1/encoder/svc_layercontext.h
+++ b/av1/encoder/svc_layercontext.h
@@ -277,6 +277,8 @@
void av1_set_svc_fixed_mode(struct AV1_COMP *const cpi);
+void av1_svc_check_reset_layer_rc_flag(struct AV1_COMP *const cpi);
+
#ifdef __cplusplus
} // extern "C"
#endif