Integrate BITRATE_ACCURACY with new ARF q feature

av1_get_arf_q_index_q_mode() can not be directly used
in BITRATE_ACCURACY because it's using
active_worst_quality (cq_level) as leaf frame q index, but in
BITRATE_ACCURACY, we are tuning the leaf frame q index and
therefore we will need to parameterize active_worst_quality.

We rename av1_get_arf_q_index_q_mode() as av1_tpl_get_q_index()
and decompose it into two functions, av1_tpl_get_qstep_ratio()
and av1_get_q_index_from_qstep_ratio().

av1_tpl_get_qstep_ratio() aims at computing the qstep
ratio between leaf frame q index and arf frame q index.

av1_get_q_index_from_qstep_ratio() finds arf q index based on
the qstep ratio with respect to the leaf frame q index.

We pass the qstep ratio into av1_q_mode_estimate_base_q()
so that it can be used to infer arf q index from
leaf frame q index.

Change-Id: If68a8ffee00656ec22df01c7cc003de5e9540071
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 9f3b3ca..af01945 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -1040,11 +1040,12 @@
           gop_bit_budget -= cpi->vbr_rc_info.keyframe_bitrate;
         }
         // Use the gop_bit_budget to determine gf_group->q_val.
-        int arf_q =
-            av1_get_arf_q_index_q_mode(cpi, cpi->ppi->tpl_data.tpl_frame);
+        const double arf_qstep_ratio =
+            av1_tpl_get_qstep_ratio(&cpi->ppi->tpl_data, cpi->gf_frame_index);
         av1_q_mode_estimate_base_q(&cpi->ppi->gf_group,
                                    cpi->ppi->tpl_data.txfm_stats_list,
-                                   gop_bit_budget, cpi->gf_frame_index, arf_q);
+                                   gop_bit_budget, cpi->gf_frame_index,
+                                   arf_qstep_ratio, cm->seq_params->bit_depth);
       }
 #endif
     }
diff --git a/av1/encoder/encoder_utils.c b/av1/encoder/encoder_utils.c
index 2116527..b44f03b 100644
--- a/av1/encoder/encoder_utils.c
+++ b/av1/encoder/encoder_utils.c
@@ -552,8 +552,9 @@
       cpi->ppi->tpl_data.tpl_frame[cpi->gf_frame_index].is_valid &&
       is_frame_tpl_eligible(gf_group, cpi->gf_frame_index) &&
       !is_lossless_requested(&cpi->oxcf.rc_cfg) && !frame_is_intra_only(cm)) {
-    *q = av1_get_arf_q_index_q_mode(
-        cpi, &cpi->ppi->tpl_data.tpl_frame[cpi->gf_frame_index]);
+    *q = av1_tpl_get_q_index(&cpi->ppi->tpl_data, cpi->gf_frame_index,
+                             cpi->rc.active_worst_quality,
+                             cm->seq_params->bit_depth);
     *top_index = *bottom_index = *q;
     if (gf_group->update_type[cpi->gf_frame_index] == ARF_UPDATE)
       cpi->ppi->p_rc.arf_q = *q;
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index a43d816..c81fa23 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -1069,11 +1069,12 @@
             gop_bit_budget -= cpi->vbr_rc_info.keyframe_bitrate;
           }
           // Use the gop_bit_budget to determine gf_group->q_val.
-          int arf_q =
-              av1_get_arf_q_index_q_mode(cpi, cpi->ppi->tpl_data.tpl_frame);
+          const double arf_qstep_ratio =
+              av1_tpl_get_qstep_ratio(&cpi->ppi->tpl_data, cpi->gf_frame_index);
           av1_q_mode_estimate_base_q(
               &cpi->ppi->gf_group, cpi->ppi->tpl_data.txfm_stats_list,
-              gop_bit_budget, cpi->gf_frame_index, arf_q);
+              gop_bit_budget, cpi->gf_frame_index, arf_qstep_ratio,
+              cpi->common.seq_params->bit_depth);
         }
 #endif  // CONFIG_BITRATE_ACCURACY
       }
@@ -3869,7 +3870,8 @@
       (int64_t)(stats->duration * oxcf->rc_cfg.target_bandwidth / 10000000.0);
 
 #if CONFIG_BITRATE_ACCURACY
-  vbr_rc_init(&cpi->vbr_rc_info, cpi->ppi->twopass.bits_left, stats->count);
+  vbr_rc_init(&cpi->vbr_rc_info, cpi->ppi->twopass.bits_left,
+              (int)round(stats->count));
 #endif
 
   // This variable monitors how far behind the second ref update is lagging.
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index ca13f14..ac82abe 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1779,50 +1779,6 @@
   return min_boost - (int)(boost * arf_boost_factor);
 }
 
-#if !CONFIG_REALTIME_ONLY
-// TODO(jingning): Need further refactoring to reduce the data structure
-// access scope.
-int av1_get_arf_q_index_q_mode(AV1_COMP *cpi, TplDepFrame *tpl_frame) {
-  AV1_COMMON *cm = &cpi->common;
-  double lef_qstep = av1_dc_quant_QTX(cpi->rc.active_worst_quality, 0,
-                                      cm->seq_params->bit_depth);
-
-  TplParams *tpl_data = &cpi->ppi->tpl_data;
-  TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
-
-  int tpl_stride = tpl_frame->stride;
-  int64_t intra_cost_base = 0;
-  int64_t mc_dep_cost_base = 0;
-  int64_t pred_error = 1;
-  int64_t recn_error = 1;
-  const int step = 1 << tpl_data->tpl_stats_block_mis_log2;
-
-  for (int row = 0; row < cm->mi_params.mi_rows; row += step) {
-    for (int col = 0; col < cm->mi_params.mi_cols; col += step) {
-      TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos(
-          row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)];
-      int64_t mc_dep_delta =
-          RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate,
-                 this_stats->mc_dep_dist);
-      intra_cost_base += (this_stats->recrf_dist << RDDIV_BITS);
-      pred_error += (this_stats->srcrf_sse << RDDIV_BITS);
-      recn_error += (this_stats->srcrf_dist << RDDIV_BITS);
-      mc_dep_cost_base += (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta;
-    }
-  }
-  double r0 = (double)intra_cost_base / mc_dep_cost_base;
-
-  int arf_qp;
-  double tgt_qstep;
-  for (arf_qp = cpi->rc.active_worst_quality; arf_qp > 0; --arf_qp) {
-    tgt_qstep = av1_dc_quant_QTX(arf_qp, 0, cm->seq_params->bit_depth);
-    if (tgt_qstep + 0.1 <= lef_qstep * sqrt(r0)) break;
-  }
-
-  return arf_qp;
-}
-#endif
-
 static int rc_pick_q_and_bounds_q_mode(const AV1_COMP *cpi, int width,
                                        int height, int gf_index,
                                        int *bottom_index, int *top_index) {
@@ -3107,15 +3063,22 @@
   }
 }
 
+#if !CONFIG_REALTIME_ONLY
+// TODO(angiebird): move this function to tpl_model.c
 /*
  * Compute the q_indices for the entire GOP.
  * Intended to be used only with AOM_Q mode.
  */
 void av1_q_mode_compute_gop_q_indices(int gf_frame_index, int base_q_index,
-                                      int arf_q, struct GF_GROUP *gf_group) {
+                                      double arf_qstep_ratio,
+                                      aom_bit_depth_t bit_depth,
+                                      struct GF_GROUP *gf_group) {
+  const int arf_q = av1_get_q_index_from_qstep_ratio(
+      base_q_index, arf_qstep_ratio, bit_depth);
   for (int gf_index = gf_frame_index; gf_index < gf_group->size; ++gf_index) {
-    int height = gf_group_pyramid_level(gf_group, gf_index);
+    const int height = gf_group_pyramid_level(gf_group, gf_index);
     gf_group->q_val[gf_index] = av1_q_mode_get_q_index(
         base_q_index, gf_group->update_type[gf_index], height, arf_q);
   }
 }
+#endif  // !CONFIG_REALTIME_ONLY
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 45c6ff3..583bdf2 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -707,18 +707,22 @@
  */
 int av1_encodedframe_overshoot_cbr(struct AV1_COMP *cpi, int *q);
 
+#if !CONFIG_REALTIME_ONLY
 /*!\brief Compute the q_indices for the entire GOP.
  *
  * Intended to be used only with AOM_Q mode.
  *
  * \param[in]       gf_frame_index    Index of the current frame
  * \param[in]       base_q_index      Base q index
- * \param[in]       bit_depth         Bit depth
- * \param[in]       arf_q             ARF q index
+ * \param[in]       arf_qstep_ratio   The quantize step ratio between arf q
+ * index and base q index \param[in]       bit_depth         Bit depth
  * \param[out]      gf_group          Pointer to the GOP
  */
 void av1_q_mode_compute_gop_q_indices(int gf_frame_index, int base_q_index,
-                                      int arf_q, struct GF_GROUP *gf_group);
+                                      double arf_qstep_ratio,
+                                      aom_bit_depth_t bit_depth,
+                                      struct GF_GROUP *gf_group);
+#endif  // !CONFIG_REALTIME_ONLY
 
 /*!\brief Compute the q_indices for a single frame.
  *
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 6d06670..0116398 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1960,20 +1960,24 @@
 int av1_q_mode_estimate_base_q(GF_GROUP *gf_group,
                                const TplTxfmStats *txfm_stats_list,
                                double bit_budget, int gf_frame_index,
-                               int arf_q) {
+                               double arf_qstep_ratio,
+                               aom_bit_depth_t bit_depth) {
   int q_max = 255;  // Maximum q value.
   int q_min = 0;    // Minimum q value.
   int q = (q_max + q_min) / 2;
 
-  av1_q_mode_compute_gop_q_indices(gf_frame_index, q_max, arf_q, gf_group);
+  av1_q_mode_compute_gop_q_indices(gf_frame_index, q_max, arf_qstep_ratio,
+                                   bit_depth, gf_group);
   double q_max_estimate = av1_estimate_gop_bitrate(
       gf_group->q_val, gf_group->size, txfm_stats_list);
-  av1_q_mode_compute_gop_q_indices(gf_frame_index, q_min, arf_q, gf_group);
+  av1_q_mode_compute_gop_q_indices(gf_frame_index, q_min, arf_qstep_ratio,
+                                   bit_depth, gf_group);
   double q_min_estimate = av1_estimate_gop_bitrate(
       gf_group->q_val, gf_group->size, txfm_stats_list);
 
   while (true) {
-    av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_q, gf_group);
+    av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+                                     bit_depth, gf_group);
 
     double estimate = av1_estimate_gop_bitrate(gf_group->q_val, gf_group->size,
                                                txfm_stats_list);
@@ -2001,6 +2005,53 @@
   }
 
   // Before returning, update the gop q_val.
-  av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_q, gf_group);
+  av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+                                   bit_depth, gf_group);
   return q;
 }
+
+double av1_tpl_get_qstep_ratio(const TplParams *tpl_data, int gf_frame_index) {
+  const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_frame_index];
+  const TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
+
+  const int tpl_stride = tpl_frame->stride;
+  int64_t intra_cost_base = 0;
+  int64_t mc_dep_cost_base = 0;
+  int64_t pred_error = 1;
+  int64_t recn_error = 1;
+  const int step = 1 << tpl_data->tpl_stats_block_mis_log2;
+
+  for (int row = 0; row < tpl_frame->mi_rows; row += step) {
+    for (int col = 0; col < tpl_frame->mi_cols; col += step) {
+      const TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos(
+          row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)];
+      const int64_t mc_dep_delta =
+          RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate,
+                 this_stats->mc_dep_dist);
+      intra_cost_base += (this_stats->recrf_dist << RDDIV_BITS);
+      pred_error += (this_stats->srcrf_sse << RDDIV_BITS);
+      recn_error += (this_stats->srcrf_dist << RDDIV_BITS);
+      mc_dep_cost_base += (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta;
+    }
+  }
+  const double r0 = (double)intra_cost_base / mc_dep_cost_base;
+  return sqrt(r0);
+}
+
+int av1_get_q_index_from_qstep_ratio(int leaf_qindex, double qstep_ratio,
+                                     aom_bit_depth_t bit_depth) {
+  const double leaf_qstep = av1_dc_quant_QTX(leaf_qindex, 0, bit_depth);
+  const double target_qstep = leaf_qstep * qstep_ratio;
+  int qindex = leaf_qindex;
+  for (qindex = leaf_qindex; qindex > 0; --qindex) {
+    const double qstep = av1_dc_quant_QTX(qindex, 0, bit_depth);
+    if (qstep + 0.1 <= target_qstep) break;
+  }
+  return qindex;
+}
+
+int av1_tpl_get_q_index(const TplParams *tpl_data, int gf_frame_index,
+                        int leaf_qindex, aom_bit_depth_t bit_depth) {
+  const double qstep_ratio = av1_tpl_get_qstep_ratio(tpl_data, gf_frame_index);
+  return av1_get_q_index_from_qstep_ratio(leaf_qindex, qstep_ratio, bit_depth);
+}
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index 2019fb1..b5aabf8 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -487,15 +487,52 @@
  * \param[in]       stats             Transform stats struct
  * \param[in]       bit_budget        The specified bit budget to achieve
  * \param[in]       gf_frame_index    current frame in the GOP
- * \param[in]       bit_depth         Bit depth
- * \param[in]       arf_q             ARF q index
+ * \param[in]       arf_qstep_ratio   ARF q step ratio
+ * \param[in]       bit_depth         bit depth
  *
  * \return Returns the optimal base q index to use.
  */
 int av1_q_mode_estimate_base_q(struct GF_GROUP *gf_group,
                                const TplTxfmStats *txfm_stats_list,
                                double bit_budget, int gf_frame_index,
-                               int arf_q);
+                               double arf_qstep_ratio,
+                               aom_bit_depth_t bit_depth);
+
+/*!\brief Get current frame's q_index from tpl stats and leaf_qindex
+ *
+ * \param[in]       tpl_data          TPL struct
+ * \param[in]       gf_frame_index    current frame index in the GOP
+ * \param[in]       leaf_qindex       q index of leaf frame
+ * \param[in]       bit_depth         bit depth
+ *
+ * \return q_index
+ */
+int av1_tpl_get_q_index(const TplParams *tpl_data, int gf_frame_index,
+                        int leaf_qindex, aom_bit_depth_t bit_depth);
+
+/*!\brief Compute the ratio between arf q step and the leaf q step based on TPL
+ * stats
+ *
+ * \param[in]       tpl_data          TPL struct
+ * \param[in]       gf_frame_index    current frame index in the GOP
+ * \param[in]       leaf_qindex       q index of leaf frame
+ * \param[in]       bit_depth         bit depth
+ *
+ * \return qstep_ratio
+ */
+double av1_tpl_get_qstep_ratio(const TplParams *tpl_data, int gf_frame_index);
+
+/*!\brief Find a q index whose step size is near qstep_ratio * leaf_qstep
+ *
+ * \param[in]       leaf_qindex       q index of leaf frame
+ * \param[in]       qstep_ratio       step ratio between target q index and leaf
+ *                                    q index
+ * \param[in]       bit_depth         bit depth
+ *
+ * \return q_index
+ */
+int av1_get_q_index_from_qstep_ratio(int leaf_qindex, double qstep_ratio,
+                                     aom_bit_depth_t bit_depth);
 
 /*!\endcond */
 #ifdef __cplusplus
diff --git a/test/ratectrl_test.cc b/test/ratectrl_test.cc
index 735deee..ffb6b9f 100644
--- a/test/ratectrl_test.cc
+++ b/test/ratectrl_test.cc
@@ -39,32 +39,40 @@
   EXPECT_EQ(q_index, base_q_index);
 }
 
+#if !CONFIG_REALTIME_ONLY
+// TODO(angiebird): Move this test to tpl_mode_test.cc
 TEST(RatectrlTest, QModeComputeGOPQIndicesTest) {
-  int base_q_index = 36;
-  int arf_q = 36;
+  const int base_q_index = 80;
+  const double arf_qstep_ratio = 0.5;
+  const aom_bit_depth_t bit_depth = AOM_BITS_8;
 
-  int gf_frame_index = 0;
+  const int gf_frame_index = 0;
   GF_GROUP gf_group = {};
   gf_group.size = 5;
-  int layer_depth[5] = { 1, 3, 2, 3, 1 };
-  int update_type[5] = { KF_UPDATE, INTNL_ARF_UPDATE, INTNL_OVERLAY_UPDATE,
-                         INTNL_ARF_UPDATE, ARF_UPDATE };
+  const int layer_depth[5] = { 1, 3, 2, 3, 1 };
+  const int update_type[5] = { KF_UPDATE, INTNL_ARF_UPDATE,
+                               INTNL_OVERLAY_UPDATE, INTNL_ARF_UPDATE,
+                               ARF_UPDATE };
 
   for (int i = 0; i < gf_group.size; i++) {
     gf_group.layer_depth[i] = layer_depth[i];
     gf_group.update_type[i] = update_type[i];
   }
 
-  av1_q_mode_compute_gop_q_indices(gf_frame_index, base_q_index, arf_q,
-                                   &gf_group);
+  const int arf_q = av1_get_q_index_from_qstep_ratio(
+      base_q_index, arf_qstep_ratio, bit_depth);
+
+  av1_q_mode_compute_gop_q_indices(gf_frame_index, base_q_index,
+                                   arf_qstep_ratio, bit_depth, &gf_group);
 
   for (int i = 0; i < gf_group.size; i++) {
-    if (arf_q == base_q_index) {
-      EXPECT_EQ(gf_group.q_val[i], base_q_index);
+    if (layer_depth[i] == 1) {
+      EXPECT_EQ(gf_group.q_val[i], arf_q);
     } else {
-      EXPECT_LE(gf_group.q_val[i], base_q_index);
+      EXPECT_GT(gf_group.q_val[i], arf_q);
     }
   }
 }
+#endif  // !CONFIG_REALTIME_ONLY
 
 }  // namespace
diff --git a/test/tpl_model_test.cc b/test/tpl_model_test.cc
index bac6da8..720804e 100644
--- a/test/tpl_model_test.cc
+++ b/test/tpl_model_test.cc
@@ -233,13 +233,15 @@
  * Helper method to brute-force search for the closest q_index
  * that achieves the specified bit budget.
  */
-int find_gop_q_iterative(double bit_budget, int arf_q, GF_GROUP gf_group,
-                         TplTxfmStats *stats_list, int gf_frame_index) {
+int find_gop_q_iterative(double bit_budget, double arf_qstep_ratio,
+                         GF_GROUP gf_group, TplTxfmStats *stats_list,
+                         int gf_frame_index, aom_bit_depth_t bit_depth) {
   // Brute force iterative method to find the optimal q.
   // Use the result to test against the binary search result.
 
   // Initial estimate when q = 255
-  av1_q_mode_compute_gop_q_indices(gf_frame_index, 255, arf_q, &gf_group);
+  av1_q_mode_compute_gop_q_indices(gf_frame_index, 255, arf_qstep_ratio,
+                                   bit_depth, &gf_group);
   double curr_estimate =
       av1_estimate_gop_bitrate(gf_group.q_val, gf_group.size, stats_list);
   double best_estimate_budget_distance = fabs(curr_estimate - bit_budget);
@@ -247,7 +249,8 @@
 
   // Start at q = 254 because we already have an estimate for q = 255.
   for (int q = 254; q >= 0; q--) {
-    av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_q, &gf_group);
+    av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+                                     bit_depth, &gf_group);
     curr_estimate =
         av1_estimate_gop_bitrate(gf_group.q_val, gf_group.size, stats_list);
     double curr_estimate_budget_distance = fabs(curr_estimate - bit_budget);
@@ -266,7 +269,8 @@
   const int gf_group_update_types[25] = { 0, 3, 6, 6, 6, 1, 5, 1, 5, 6, 1, 5, 1,
                                           5, 6, 6, 1, 5, 1, 5, 6, 1, 5, 1, 4 };
   const int gf_frame_index = 0;
-  const int arf_q = 144;
+  const double arf_qstep_ratio = 2;
+  const aom_bit_depth_t bit_depth = AOM_BITS_8;
 
   for (int i = 0; i < gf_group.size; i++) {
     gf_group.update_type[i] = gf_group_update_types[i];
@@ -284,11 +288,13 @@
 
   for (double bit_budget : bit_budgets) {
     // Binary search method to find the optimal q.
-    int result = av1_q_mode_estimate_base_q(&gf_group, stats_list, bit_budget,
-                                            gf_frame_index, arf_q);
+    const int result =
+        av1_q_mode_estimate_base_q(&gf_group, stats_list, bit_budget,
+                                   gf_frame_index, arf_qstep_ratio, bit_depth);
 
-    int test_result = find_gop_q_iterative(bit_budget, arf_q, gf_group,
-                                           stats_list, gf_frame_index);
+    const int test_result =
+        find_gop_q_iterative(bit_budget, arf_qstep_ratio, gf_group, stats_list,
+                             gf_frame_index, bit_depth);
 
     if (bit_budget == 0) {
       EXPECT_EQ(result, 255);