Update the bit estimation ratio adaptively

Improved the approach proposed in
https://aomedia-review.googlesource.com/c/aom/+/165905
Updated the bit estimation ratio adaptively for each
video instead of using a fixed model.

This BDrate gain is 1.6%(ovr_psnr) and 1.5%(ssim) (the
baseline: accurate_bit_estimate disabled). We found
that this approach works well for videos with background
motion.

Same as prvious CL, this is only enabled for aq_mode=0.

STATS_CHANGED

Change-Id: I30e9af783309297d062f9242788fa3f651fd14d3
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 45d6818..264783d 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -174,35 +174,31 @@
   return enumerator;
 }
 
+static int get_init_ratio(double sse) { return (int)(300000 / sse); }
+
 int av1_rc_bits_per_mb(const AV1_COMP *cpi, FRAME_TYPE frame_type, int qindex,
                        double correction_factor, int accurate_estimate) {
   const AV1_COMMON *const cm = &cpi->common;
   const int is_screen_content_type = cpi->is_screen_content_type;
   const aom_bit_depth_t bit_depth = cm->seq_params->bit_depth;
   const double q = av1_convert_qindex_to_q(qindex, bit_depth);
+  int enumerator = av1_get_bpmb_enumerator(frame_type, is_screen_content_type);
 
-  const int min_dim = AOMMIN(cm->width, cm->height);
+  assert(correction_factor <= MAX_BPB_FACTOR &&
+         correction_factor >= MIN_BPB_FACTOR);
 
   if (frame_type != KEY_FRAME && accurate_estimate) {
     assert(cpi->rec_sse != UINT64_MAX);
     const int mbs = cm->mi_params.MBs;
-    const int res = (min_dim < 480) ? 0 : ((min_dim < 720) ? 1 : 2);
-    const double sse_over_q2 = (double)(cpi->rec_sse << BPER_MB_NORMBITS) /
-                               ((double)q * q) / (double)mbs;
-    const double coef[3][2] = {
-      { 0.535, 3000.0 },  // < 480
-      { 0.590, 3000.0 },  // < 720
-      { 0.485, 1000.0 }   // 720
-    };
-    int bits = (int)(coef[res][0] * sse_over_q2 + coef[res][1]);
-    return (int)(bits * correction_factor);
+    const double sse_sqrt =
+        (double)((int)sqrt((double)(cpi->rec_sse)) << BPER_MB_NORMBITS) /
+        (double)mbs;
+    const int ratio = (cpi->rc.bit_est_ratio == 0) ? get_init_ratio(sse_sqrt)
+                                                   : cpi->rc.bit_est_ratio;
+    // Clamp the enumerator to lower the q fluctuations.
+    enumerator = AOMMIN(AOMMAX((int)(ratio * sse_sqrt), 20000), 170000);
   }
 
-  const int enumerator =
-      av1_get_bpmb_enumerator(frame_type, is_screen_content_type);
-  assert(correction_factor <= MAX_BPB_FACTOR &&
-         correction_factor >= MIN_BPB_FACTOR);
-
   // q based adjustment to baseline enumerator
   return (int)(enumerator * correction_factor / q);
 }
@@ -2048,7 +2044,8 @@
     pre_y += (pre_ystride << 6) - (sb_cols << 6);
   }
   assert(num_samples > 0);
-  if (num_samples > 0) cpi->rec_sse = fsse;
+  // Ensure rec_sse > 0
+  if (num_samples > 0) cpi->rec_sse = fsse > 0 ? fsse : 1;
 }
 
 int av1_rc_pick_q_and_bounds(AV1_COMP *cpi, int width, int height, int gf_index,
@@ -2168,6 +2165,19 @@
   // Post encode loop adjustment of Q prediction.
   av1_rc_update_rate_correction_factors(cpi, 0, cm->width, cm->height);
 
+  // Update bit estimation ratio.
+  if (cm->current_frame.frame_type != KEY_FRAME &&
+      cpi->sf.hl_sf.accurate_bit_estimate) {
+    const double q = av1_convert_qindex_to_q(cm->quant_params.base_qindex,
+                                             cm->seq_params->bit_depth);
+    const int this_bit_est_ratio =
+        (int)(rc->projected_frame_size * q / sqrt((double)cpi->rec_sse));
+    cpi->rc.bit_est_ratio =
+        cpi->rc.bit_est_ratio == 0
+            ? this_bit_est_ratio
+            : (7 * cpi->rc.bit_est_ratio + this_bit_est_ratio) / 8;
+  }
+
   // Keep a record of last Q and ambient average Q.
   if (current_frame->frame_type == KEY_FRAME) {
     p_rc->last_q[KEY_FRAME] = qindex;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 114778d..c8963a4 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -261,6 +261,11 @@
 
   int prev_coded_width;
   int prev_coded_height;
+
+  // The ratio used for inter frames in bit estimation.
+  // TODO(yunqing): if golden frame is treated differently (e.g. gf_cbr_boost_
+  // pct > THR), consider to add bit_est_ratio_g for golden frames.
+  int bit_est_ratio;
   /*!\endcond */
 } RATE_CONTROL;