rtc: Allow QP to decrease more aggressively for static content

For RTC static content, with stable buffer level, relax the
limit on how much QP can change frame-to-frame and allow for
a delta bias. This allows for faster quality ramp-up and QP
convergence on static content following scene change.
Added feature to control it, enabled for screen content at
the higher speed settings.

Bug: 362936830
Change-Id: I751ebde7295b1e70851aeec00406674fa112d2e6
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 4fd5ec6..df948e8 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -624,6 +624,26 @@
                          ? AOMMIN(8, AOMMAX(1, rc->q_1_frame / 16))
                          : AOMMIN(16, AOMMAX(1, rc->q_1_frame / 8));
   }
+  // For screen static content with stable buffer level: relax the
+  // limit on max_delta_down and apply bias qp, based on buffer fullness.
+  // Only for high speeds levels for now to avoid bdrate regression.
+  if (cpi->sf.rt_sf.rc_faster_convergence_static == 1 &&
+      cpi->sf.rt_sf.check_scene_detection && rc->frame_source_sad == 0 &&
+      rc->static_since_last_scene_change &&
+      p_rc->buffer_level > (p_rc->optimal_buffer_level >> 1) &&
+      cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ &&
+      cpi->cyclic_refresh->counter_encode_maxq_scene_change > 4) {
+    int qp_delta = 32;
+    int qp_bias = 16;
+    if (p_rc->buffer_level > p_rc->optimal_buffer_level) {
+      qp_delta = 60;
+      qp_bias = 32;
+    }
+    if (cpi->rc.rc_1_frame == 1) q = q - qp_bias;
+    max_delta_down = AOMMAX(max_delta_down, qp_delta);
+    max_delta_up = AOMMIN(max_delta_up, 4);
+  }
+
   // If resolution changes or avg_frame_bandwidth significantly changed,
   // then set this flag to indicate change in target bits per macroblock.
   const int change_target_bits_mb =
@@ -3307,7 +3327,11 @@
   if (num_samples > 0)
     rc->percent_blocks_with_motion =
         ((num_samples - num_zero_temp_sad) * 100) / num_samples;
-  if (rc->high_source_sad) cpi->rc.frames_since_scene_change = 0;
+  if (rc->frame_source_sad > 0) rc->static_since_last_scene_change = 0;
+  if (rc->high_source_sad) {
+    cpi->rc.frames_since_scene_change = 0;
+    rc->static_since_last_scene_change = 1;
+  }
   // Update the high_motion_content_screen_rtc flag on TL0. Avoid the update
   // if too many consecutive frame drops occurred.
   const uint64_t thresh_high_motion = 9 * 64 * 64;
@@ -3706,6 +3730,7 @@
     }
     rc->frame_number_encoded = 0;
     cpi->ppi->rtc_ref.non_reference_frame = 0;
+    rc->static_since_last_scene_change = 0;
   } else {
     *frame_type = INTER_FRAME;
     gf_group->update_type[cpi->gf_frame_index] = LF_UPDATE;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 1d159ae..356023b 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -195,6 +195,7 @@
   uint64_t prev_avg_source_sad;
   uint64_t frame_source_sad;
   uint64_t spatial_variance_keyframe;
+  int static_since_last_scene_change;
   int last_encoded_size_keyframe;
   int last_target_size_keyframe;
   int frames_since_scene_change;
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 2cc0659..ea340a9 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1580,6 +1580,7 @@
       sf->rt_sf.dct_only_palette_nonrd = 1;
       sf->rt_sf.prune_palette_search_nonrd = 1;
       sf->rt_sf.prune_intra_mode_using_best_sad_so_far = true;
+      sf->rt_sf.rc_faster_convergence_static = 1;
     }
     if (speed >= 11) {
       sf->rt_sf.skip_lf_screen = 2;
@@ -2327,6 +2328,7 @@
   rt_sf->higher_thresh_scene_detection = 1;
   rt_sf->skip_newmv_flat_blocks_screen = 0;
   rt_sf->skip_encoding_non_reference_slide_change = 0;
+  rt_sf->rc_faster_convergence_static = 0;
 }
 
 static fractional_mv_step_fp
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 5aec86f..00b415f 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1922,6 +1922,10 @@
 
   // Flag to force skip encoding for non_reference_frame on slide/scene changes.
   int skip_encoding_non_reference_slide_change;
+
+  // Flag to indicate more aggressive QP downward adjustment for screen static
+  // content, to make convergence to min_qp faster.
+  int rc_faster_convergence_static;
 } REAL_TIME_SPEED_FEATURES;
 
 /*!\endcond */
diff --git a/av1/encoder/svc_layercontext.c b/av1/encoder/svc_layercontext.c
index 5b2e2d8..52c0500 100644
--- a/av1/encoder/svc_layercontext.c
+++ b/av1/encoder/svc_layercontext.c
@@ -230,6 +230,8 @@
   const int last_target_size_keyframe = cpi->rc.last_target_size_keyframe;
   const int max_consec_drop = cpi->rc.max_consec_drop;
   const int postencode_drop = cpi->rc.postencode_drop;
+  const int static_since_last_scene_change =
+      cpi->rc.static_since_last_scene_change;
   // Restore layer rate control.
   cpi->rc = lc->rc;
   cpi->ppi->p_rc = lc->p_rc;
@@ -247,6 +249,7 @@
   cpi->rc.last_target_size_keyframe = last_target_size_keyframe;
   cpi->rc.max_consec_drop = max_consec_drop;
   cpi->rc.postencode_drop = postencode_drop;
+  cpi->rc.static_since_last_scene_change = static_since_last_scene_change;
   // For spatial-svc, allow cyclic-refresh to be applied on the spatial layers,
   // for the base temporal layer.
   if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ &&