Update q_index_list only when gf_frame_index = 0

This will make the q indices for the entire gop more consistent.
Therefore largely reduce the performance hit.

We also store the q indices to vbr_rc_info->q_index_list to
avoid conflicts with the existing code.

Change-Id: Ibbb08dd3a1f9c540d8f0e20be221060747a191f9
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 3da9959..0891c70 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -924,7 +924,7 @@
 #endif
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
   AV1_COMMON *const cm = &cpi->common;
-  const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
+  GF_GROUP *const gf_group = &cpi->ppi->gf_group;
   FRAME_UPDATE_TYPE update_type =
       get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
 
@@ -1034,19 +1034,9 @@
       av1_tpl_preload_rc_estimate(cpi, frame_params);
       av1_tpl_setup_stats(cpi, 0, frame_params, frame_input);
 #if CONFIG_BITRATE_ACCURACY
-      if (gf_group->update_type[cpi->gf_frame_index] == ARF_UPDATE) {
-        double gop_bit_budget = cpi->vbr_rc_info.gop_bit_budget;
-        if (gf_group->update_type[0] == KF_UPDATE && cpi->gf_frame_index != 0) {
-          gop_bit_budget -= cpi->vbr_rc_info.keyframe_bitrate;
-        }
-        // Use the gop_bit_budget to determine gf_group->q_val.
-        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_qstep_ratio,
-            cm->seq_params->bit_depth, cpi->vbr_rc_info.scale_factor);
-      }
+      av1_vbr_rc_update_q_index_list(&cpi->vbr_rc_info, &cpi->ppi->tpl_data,
+                                     gf_group, cpi->gf_frame_index,
+                                     cm->seq_params->bit_depth);
 #endif
     }
   }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index d3df7590..e78c85a 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2574,7 +2574,7 @@
 #endif  // CONFIG_RD_COMMAND
 
 #if CONFIG_BITRATE_ACCURACY
-    q = (int)cpi->ppi->gf_group.q_val[cpi->gf_frame_index];
+    q = cpi->vbr_rc_info.q_index_list[cpi->gf_frame_index];
 #endif
     av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, q,
                       q_cfg->enable_chroma_deltaq);
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index 31ee7fc..7adb91e 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -189,7 +189,7 @@
   int max_layer_depth;
   int max_layer_depth_allowed;
   // This is currently only populated for AOM_Q mode
-  unsigned char q_val[MAX_STATIC_GF_GROUP_LENGTH];
+  int q_val[MAX_STATIC_GF_GROUP_LENGTH];
   int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH];
   // The frame coding type - inter/intra frame
   FRAME_TYPE frame_type[MAX_STATIC_GF_GROUP_LENGTH];
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index c32830b..a96b292 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -1062,20 +1062,9 @@
       if (is_temporal_filter_enabled && !shorten_gf_interval) {
         cpi->skip_tpl_setup_stats = 1;
 #if CONFIG_BITRATE_ACCURACY
-        if (gf_group->update_type[cpi->gf_frame_index] == ARF_UPDATE) {
-          double gop_bit_budget = cpi->vbr_rc_info.gop_bit_budget;
-          if (gf_group->update_type[0] == KF_UPDATE &&
-              cpi->gf_frame_index != 0) {
-            gop_bit_budget -= cpi->vbr_rc_info.keyframe_bitrate;
-          }
-          // Use the gop_bit_budget to determine gf_group->q_val.
-          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_qstep_ratio,
-              cpi->common.seq_params->bit_depth, cpi->vbr_rc_info.scale_factor);
-        }
+        av1_vbr_rc_update_q_index_list(&cpi->vbr_rc_info, &cpi->ppi->tpl_data,
+                                       gf_group, cpi->gf_frame_index,
+                                       cpi->common.seq_params->bit_depth);
 #endif  // CONFIG_BITRATE_ACCURACY
       }
     }
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index ac82abe..667c0bd 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -3072,12 +3072,13 @@
 void av1_q_mode_compute_gop_q_indices(int gf_frame_index, int base_q_index,
                                       double arf_qstep_ratio,
                                       aom_bit_depth_t bit_depth,
-                                      struct GF_GROUP *gf_group) {
+                                      const struct GF_GROUP *gf_group,
+                                      int *q_index_list) {
   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) {
     const int height = gf_group_pyramid_level(gf_group, gf_index);
-    gf_group->q_val[gf_index] = av1_q_mode_get_q_index(
+    q_index_list[gf_index] = av1_q_mode_get_q_index(
         base_q_index, gf_group->update_type[gf_index], height, arf_q);
   }
 }
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 583bdf2..4474a75 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -710,18 +710,21 @@
 #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]       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
+ *                                    index and base q index
+ * \param[in]       bit_depth         Bit depth
+ * \param[in]       gf_group          Pointer to the GOP
+ * \param[out]      q_index_list      An array to store output gop q indices.
+ *                                    the array size should be equal or
+ *                                    greater than gf_group.size()
  */
 void av1_q_mode_compute_gop_q_indices(int gf_frame_index, int base_q_index,
                                       double arf_qstep_ratio,
                                       aom_bit_depth_t bit_depth,
-                                      struct GF_GROUP *gf_group);
+                                      const struct GF_GROUP *gf_group,
+                                      int *q_index_list);
 #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 0ca74ac..31bfc77 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1883,8 +1883,7 @@
   return est_rate;
 }
 
-double av1_estimate_gop_bitrate(const unsigned char *q_index_list,
-                                const int frame_count,
+double av1_estimate_gop_bitrate(const int *q_index_list, const int frame_count,
                                 const TplTxfmStats *stats_list) {
   double gop_bitrate = 0;
   for (int frame_index = 0; frame_index < frame_count; frame_index++) {
@@ -1961,30 +1960,31 @@
 /*
  * Estimate the optimal base q index for a GOP.
  */
-int av1_q_mode_estimate_base_q(GF_GROUP *gf_group,
+int av1_q_mode_estimate_base_q(const GF_GROUP *gf_group,
                                const TplTxfmStats *txfm_stats_list,
                                double bit_budget, int gf_frame_index,
                                double arf_qstep_ratio,
-                               aom_bit_depth_t bit_depth, double scale_factor) {
+                               aom_bit_depth_t bit_depth, double scale_factor,
+                               int *q_index_list) {
   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_qstep_ratio,
-                                   bit_depth, gf_group);
-  double q_max_estimate = av1_estimate_gop_bitrate(
-      gf_group->q_val, gf_group->size, txfm_stats_list);
+                                   bit_depth, gf_group, q_index_list);
+  double q_max_estimate =
+      av1_estimate_gop_bitrate(q_index_list, gf_group->size, txfm_stats_list);
   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);
+                                   bit_depth, gf_group, q_index_list);
+  double q_min_estimate =
+      av1_estimate_gop_bitrate(q_index_list, gf_group->size, txfm_stats_list);
 
   while (true) {
     av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
-                                     bit_depth, gf_group);
+                                     bit_depth, gf_group, q_index_list);
 
-    double estimate = av1_estimate_gop_bitrate(gf_group->q_val, gf_group->size,
-                                               txfm_stats_list);
+    double estimate =
+        av1_estimate_gop_bitrate(q_index_list, gf_group->size, txfm_stats_list);
 
     estimate *= scale_factor;
 
@@ -2010,9 +2010,9 @@
     }
   }
 
-  // Before returning, update the gop q_val.
+  // Before returning, update the q_index_list.
   av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
-                                   bit_depth, gf_group);
+                                   bit_depth, gf_group, q_index_list);
   return q;
 }
 
@@ -2061,3 +2061,26 @@
   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);
 }
+
+#if CONFIG_BITRATE_ACCURACY
+void av1_vbr_rc_update_q_index_list(VBR_RATECTRL_INFO *vbr_rc_info,
+                                    const TplParams *tpl_data,
+                                    const GF_GROUP *gf_group,
+                                    int gf_frame_index,
+                                    aom_bit_depth_t bit_depth) {
+  // We always update q_index_list when gf_frame_index is zero.
+  // This will make the q indices for the entire gop more consistent
+  if (gf_frame_index == 0) {
+    double gop_bit_budget = vbr_rc_info->gop_bit_budget;
+    // Use the gop_bit_budget to determine q_index_list.
+    const double arf_qstep_ratio =
+        av1_tpl_get_qstep_ratio(tpl_data, gf_frame_index);
+    // We update the q indices in vbr_rc_info in vbr_rc_info->q_index_list
+    // rather than gf_group->q_val to avoid conflicts with the existing code.
+    av1_q_mode_estimate_base_q(gf_group, tpl_data->txfm_stats_list,
+                               gop_bit_budget, gf_frame_index, arf_qstep_ratio,
+                               bit_depth, vbr_rc_info->scale_factor,
+                               vbr_rc_info->q_index_list);
+  }
+}
+#endif  // CONFIG_BITRATE_ACCURACY
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index fec81cf..bc319b8 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -239,6 +239,8 @@
   int gop_showframe_count;  // The number of show frames in the current gop
   double gop_bit_budget;    // The bitbudget for the current gop
   double scale_factor;      // Scale factor to improve the budget estimation
+  int q_index_list[MAX_LENGTH_TPL_FRAME_STATS];  // q indices for the current
+                                                 // GOP
 } VBR_RATECTRL_INFO;
 
 static INLINE void vbr_rc_init(VBR_RATECTRL_INFO *vbr_rc_info,
@@ -388,8 +390,7 @@
  * \param[in]    stats           array of transform stats, one per frame
  *
  */
-double av1_estimate_gop_bitrate(const unsigned char *q_index_list,
-                                const int frame_count,
+double av1_estimate_gop_bitrate(const int *q_index_list, const int frame_count,
                                 const TplTxfmStats *stats);
 
 /*
@@ -492,14 +493,19 @@
  * \param[in]       arf_qstep_ratio   ARF q step ratio
  * \param[in]       bit_depth         bit depth
  * \param[in]       scale_factor      Used to improve budget estimation
+ * \param[out]      q_index_list      An array to store output gop
+ *                                    q indices. The array size should
+ *                                    be equal or greater than
+ *                                    gf_group.size().
  *
  * \return Returns the optimal base q index to use.
  */
-int av1_q_mode_estimate_base_q(struct GF_GROUP *gf_group,
+int av1_q_mode_estimate_base_q(const struct GF_GROUP *gf_group,
                                const TplTxfmStats *txfm_stats_list,
                                double bit_budget, int gf_frame_index,
                                double arf_qstep_ratio,
-                               aom_bit_depth_t bit_depth, double scale_factor);
+                               aom_bit_depth_t bit_depth, double scale_factor,
+                               int *q_index_list);
 
 /*!\brief Get current frame's q_index from tpl stats and leaf_qindex
  *
@@ -537,6 +543,23 @@
 int av1_get_q_index_from_qstep_ratio(int leaf_qindex, double qstep_ratio,
                                      aom_bit_depth_t bit_depth);
 
+#if CONFIG_BITRATE_ACCURACY
+/*!\brief Update q_index_list in vbr_rc_info based on tpl stats
+ *
+ * \param[out]      vbr_rc_info    Rate control info for BITRATE_ACCURACY
+ *                                 experiment
+ * \param[in]       tpl_data       TPL struct
+ * \param[in]       gf_group       GOP struct
+ * \param[in]       gf_frame_index current frame index in the GOP
+ * \param[in]       bit_depth      bit depth
+ */
+void av1_vbr_rc_update_q_index_list(VBR_RATECTRL_INFO *vbr_rc_info,
+                                    const TplParams *tpl_data,
+                                    const struct GF_GROUP *gf_group,
+                                    int gf_frame_index,
+                                    aom_bit_depth_t bit_depth);
+#endif  // CONFIG_BITRATE_ACCURACY
+
 /*!\endcond */
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/test/ratectrl_test.cc b/test/ratectrl_test.cc
index ffb6b9f..7110db6 100644
--- a/test/ratectrl_test.cc
+++ b/test/ratectrl_test.cc
@@ -63,7 +63,8 @@
       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);
+                                   arf_qstep_ratio, bit_depth, &gf_group,
+                                   gf_group.q_val);
 
   for (int i = 0; i < gf_group.size; i++) {
     if (layer_depth[i] == 1) {
diff --git a/test/tpl_model_test.cc b/test/tpl_model_test.cc
index bd6f4cc..4d70d80 100644
--- a/test/tpl_model_test.cc
+++ b/test/tpl_model_test.cc
@@ -155,7 +155,7 @@
    */
   const int txfm_size = 256;  // 16x16
   const int frame_count = 16;
-  unsigned char q_index_list[16];
+  int q_index_list[16];
   TplTxfmStats stats_list[16];
 
   for (int i = 0; i < frame_count; i++) {
@@ -241,7 +241,7 @@
 
   // Initial estimate when q = 255
   av1_q_mode_compute_gop_q_indices(gf_frame_index, 255, arf_qstep_ratio,
-                                   bit_depth, &gf_group);
+                                   bit_depth, &gf_group, gf_group.q_val);
   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);
@@ -250,7 +250,7 @@
   // 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_qstep_ratio,
-                                     bit_depth, &gf_group);
+                                     bit_depth, &gf_group, gf_group.q_val);
     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);
@@ -291,8 +291,7 @@
     // Binary search method to find the optimal q.
     const int result = av1_q_mode_estimate_base_q(
         &gf_group, stats_list, bit_budget, gf_frame_index, arf_qstep_ratio,
-        bit_depth, scale_factor);
-
+        bit_depth, scale_factor, gf_group.q_val);
     const int test_result =
         find_gop_q_iterative(bit_budget, arf_qstep_ratio, gf_group, stats_list,
                              gf_frame_index, bit_depth);