Fix scale_factor bug and refactor BITRATE_ACCURACY

1) Make the usage of scale_factor follow the design. One scale
   factor per update_type.
   Before this change, we only use first frame's scale factor in
   the GOP as the scale factor for every frame in the GOP.
2) Several miscellaneous changes.
   a) Remove unused keyframe_bitrate
   b) Merge stats_valid into tpl_txfm_stats
   c) Update abs_coeff_mean after tpl_stats are computed
   d) Simplify the parameters of av1_q_mode_estimate_base_q
      Rename it to av1_vbr_rc_info_estimate_base_q
   e) Add unit test for av1_vbr_rc_set_gop_bit_budgeta()
   f) Write unit test for av1_vbr_rc_info_estimate_gop_bitrate
      Test scale_factors properly

BUG=aomedia:3018

Change-Id: Iec495e26d1d04d7781ea352f65d4f33d6162eb89
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index a907860..73e32a5 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2782,11 +2782,6 @@
       cpi->vbr_rc_info.actual_mv_bitrate_byframe[cpi->gf_frame_index] =
           rc->projected_frame_size -
           cpi->vbr_rc_info.actual_coeff_bitrate_byframe[cpi->gf_frame_index];
-      if (cpi->ppi->gf_group.update_type[cpi->gf_frame_index] == KF_UPDATE) {
-        vbr_rc_set_keyframe_bitrate(&cpi->vbr_rc_info,
-                                    rc->projected_frame_size);
-      }
-
 #if 0
       vbr_rc_info_log(&cpi->vbr_rc_info, cpi->gf_frame_index,
                       cpi->ppi->gf_group.size, cpi->ppi->gf_group.update_type);
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index c76ac65..8eb9afa 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2388,7 +2388,8 @@
   }
 #if CONFIG_BITRATE_ACCURACY
   if (is_final_pass) {
-    vbr_rc_set_gop_bit_budget(&cpi->vbr_rc_info, p_rc->baseline_gf_interval);
+    av1_vbr_rc_set_gop_bit_budget(&cpi->vbr_rc_info,
+                                  p_rc->baseline_gf_interval);
   }
 #endif
 }
@@ -3882,8 +3883,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,
-              (int)round(stats->count));
+  av1_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/tpl_model.c b/av1/encoder/tpl_model.c
index cae79cb..7d05a8d 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -47,10 +47,13 @@
 }
 
 void av1_init_tpl_txfm_stats(TplTxfmStats *tpl_txfm_stats) {
+  tpl_txfm_stats->ready = 0;
   tpl_txfm_stats->coeff_num = 256;
   tpl_txfm_stats->txfm_block_count = 0;
   memset(tpl_txfm_stats->abs_coeff_sum, 0,
          sizeof(tpl_txfm_stats->abs_coeff_sum[0]) * tpl_txfm_stats->coeff_num);
+  memset(tpl_txfm_stats->abs_coeff_mean, 0,
+         sizeof(tpl_txfm_stats->abs_coeff_mean[0]) * tpl_txfm_stats->coeff_num);
 }
 
 void av1_accumulate_tpl_txfm_stats(const TplTxfmStats *sub_stats,
@@ -72,6 +75,18 @@
   ++tpl_txfm_stats->txfm_block_count;
 }
 
+void av1_tpl_txfm_stats_update_abs_coeff_mean(TplTxfmStats *txfm_stats) {
+  if (txfm_stats->txfm_block_count > 0) {
+    for (int j = 0; j < txfm_stats->coeff_num; j++) {
+      txfm_stats->abs_coeff_mean[j] =
+          txfm_stats->abs_coeff_sum[j] / txfm_stats->txfm_block_count;
+    }
+    txfm_stats->ready = 1;
+  } else {
+    txfm_stats->ready = 0;
+  }
+}
+
 static AOM_INLINE void av1_tpl_store_txfm_stats(
     TplParams *tpl_data, const TplTxfmStats *tpl_txfm_stats,
     const int frame_index) {
@@ -1616,6 +1631,7 @@
     } else {
       mc_flow_dispenser(cpi);
     }
+    av1_tpl_txfm_stats_update_abs_coeff_mean(&cpi->td.tpl_txfm_stats);
     av1_tpl_store_txfm_stats(tpl_data, &cpi->td.tpl_txfm_stats, frame_idx);
 
     aom_extend_frame_borders(tpl_data->tpl_frame[frame_idx].rec_picture,
@@ -1818,35 +1834,6 @@
   return est_rate;
 }
 
-double av1_estimate_gop_bitrate(const int *q_index_list, const int frame_count,
-                                const TplTxfmStats *stats_list,
-                                const int *stats_valid_list,
-                                double *bitrate_byframe_list) {
-  double gop_bitrate = 0;
-  for (int frame_index = 0; frame_index < frame_count; frame_index++) {
-    if (stats_valid_list[frame_index]) {
-      int q_index = q_index_list[frame_index];
-      TplTxfmStats frame_stats = stats_list[frame_index];
-
-      /* Convert to mean absolute deviation */
-      double abs_coeff_mean[256] = { 0 };
-      for (int i = 0; i < 256; i++) {
-        abs_coeff_mean[i] =
-            frame_stats.abs_coeff_sum[i] / frame_stats.txfm_block_count;
-      }
-
-      double frame_bitrate = av1_laplace_estimate_frame_rate(
-          q_index, frame_stats.txfm_block_count, abs_coeff_mean, 256);
-      gop_bitrate += frame_bitrate;
-
-      if (bitrate_byframe_list != NULL) {
-        bitrate_byframe_list[frame_index] = frame_bitrate;
-      }
-    }
-  }
-  return gop_bitrate;
-}
-
 double av1_estimate_coeff_entropy(double q_step, double b,
                                   double zero_bin_ratio, int qcoeff) {
   b = AOMMAX(b, TPL_EPSILON);
@@ -1900,75 +1887,6 @@
 }
 #endif  // CONFIG_RD_COMMAND
 
-void get_tpl_stats_valid_list(const TplParams *tpl_data, int gop_size,
-                              int *stats_valid_list) {
-  for (int i = 0; i < gop_size; ++i) {
-    stats_valid_list[i] = av1_tpl_stats_ready(tpl_data, i);
-  }
-}
-
-/*
- * Estimate the optimal base q index for a GOP.
- */
-int av1_q_mode_estimate_base_q(const GF_GROUP *gf_group,
-                               const TplTxfmStats *txfm_stats_list,
-                               const int *stats_valid_list, double bit_budget,
-                               aom_bit_depth_t bit_depth, double scale_factor,
-                               const double *qstep_ratio_list,
-                               int *q_index_list,
-                               double *estimated_bitrate_byframe) {
-  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(q_max, qstep_ratio_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, stats_valid_list, NULL);
-  av1_q_mode_compute_gop_q_indices(q_min, qstep_ratio_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, stats_valid_list, NULL);
-
-  while (true) {
-    av1_q_mode_compute_gop_q_indices(q, qstep_ratio_list, bit_depth, gf_group,
-                                     q_index_list);
-
-    double estimate = av1_estimate_gop_bitrate(
-        q_index_list, gf_group->size, txfm_stats_list, stats_valid_list, NULL);
-
-    estimate *= scale_factor;
-
-    // We want to find the lowest q that satisfies the bit budget constraint.
-    // A binary search narrows the result down to two values: q_min and q_max.
-    if (q_max <= q_min + 1 || estimate == bit_budget) {
-      // Pick the estimate that lands closest to the budget.
-      if (fabs(q_max_estimate - bit_budget) <
-          fabs(q_min_estimate - bit_budget)) {
-        q = q_max;
-      } else {
-        q = q_min;
-      }
-      break;
-    } else if (estimate > bit_budget) {
-      q_min = q;
-      q_min_estimate = estimate;
-      q = (q_max + q_min) / 2;
-    } else if (estimate < bit_budget) {
-      q_max = q;
-      q_max_estimate = estimate;
-      q = (q_max + q_min) / 2;
-    }
-  }
-
-  // Update q_index_list and vbr_rc_info.
-  av1_q_mode_compute_gop_q_indices(q, qstep_ratio_list, bit_depth, gf_group,
-                                   q_index_list);
-  av1_estimate_gop_bitrate(q_index_list, gf_group->size, txfm_stats_list,
-                           stats_valid_list, estimated_bitrate_byframe);
-  return q;
-}
-
 double av1_tpl_get_frame_importance(const TplParams *tpl_data,
                                     int gf_frame_index) {
   const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_frame_index];
@@ -2021,6 +1939,113 @@
 }
 
 #if CONFIG_BITRATE_ACCURACY
+void av1_vbr_rc_init(VBR_RATECTRL_INFO *vbr_rc_info, double total_bit_budget,
+                     int show_frame_count) {
+  vbr_rc_info->total_bit_budget = total_bit_budget;
+  vbr_rc_info->show_frame_count = show_frame_count;
+  const double scale_factors[FRAME_UPDATE_TYPES] = { 0.94559, 0.94559, 1,
+                                                     0.94559, 1,       1,
+                                                     0.94559 };
+
+  // TODO(angiebird): Based on the previous code, only the scale factor 0.94559
+  // will be used in most of the cases with --limi=17. Figure out if the
+  // following scale factors works better.
+  // const double scale_factors[FRAME_UPDATE_TYPES] = { 0.94559, 0.12040, 1,
+  //                                                    1.10199, 1,       1,
+  //                                                    0.16393 };
+
+  const double mv_scale_factors[FRAME_UPDATE_TYPES] = { 3, 3, 3, 3, 3, 3, 3 };
+  memcpy(vbr_rc_info->scale_factors, scale_factors,
+         sizeof(scale_factors[0]) * FRAME_UPDATE_TYPES);
+  memcpy(vbr_rc_info->mv_scale_factors, mv_scale_factors,
+         sizeof(mv_scale_factors[0]) * FRAME_UPDATE_TYPES);
+
+  vbr_rc_reset_gop_data(vbr_rc_info);
+}
+
+void av1_vbr_rc_set_gop_bit_budget(VBR_RATECTRL_INFO *vbr_rc_info,
+                                   int gop_showframe_count) {
+  vbr_rc_info->gop_showframe_count = gop_showframe_count;
+  vbr_rc_info->gop_bit_budget = vbr_rc_info->total_bit_budget *
+                                gop_showframe_count /
+                                vbr_rc_info->show_frame_count;
+}
+
+double av1_vbr_rc_info_estimate_gop_bitrate(
+    const VBR_RATECTRL_INFO *vbr_rc_info, const GF_GROUP *gf_group,
+    int base_q_index, const TplTxfmStats *stats_list, aom_bit_depth_t bit_depth,
+    int *q_index_list, double *estimated_bitrate_byframe) {
+  av1_q_mode_compute_gop_q_indices(base_q_index, vbr_rc_info->qstep_ratio_list,
+                                   bit_depth, gf_group, q_index_list);
+  double gop_bitrate = 0;
+  for (int frame_index = 0; frame_index < gf_group->size; frame_index++) {
+    const TplTxfmStats *frame_stats = &stats_list[frame_index];
+    if (frame_stats->ready) {
+      int q_index = q_index_list[frame_index];
+
+      double frame_bitrate = av1_laplace_estimate_frame_rate(
+          q_index, frame_stats->txfm_block_count, frame_stats->abs_coeff_mean,
+          frame_stats->coeff_num);
+      gop_bitrate += frame_bitrate;
+
+      estimated_bitrate_byframe[frame_index] = frame_bitrate;
+    } else {
+      estimated_bitrate_byframe[frame_index] = 0;
+    }
+  }
+  double estimated_gop_bitrate = 0;
+  for (int i = 0; i < gf_group->size; ++i) {
+    FRAME_UPDATE_TYPE update_type = gf_group->update_type[i];
+    estimated_gop_bitrate +=
+        estimated_bitrate_byframe[i] * vbr_rc_info->scale_factors[update_type];
+  }
+  return estimated_gop_bitrate;
+}
+
+int av1_vbr_rc_info_estimate_base_q(const VBR_RATECTRL_INFO *vbr_rc_info,
+                                    const GF_GROUP *gf_group,
+                                    const TplTxfmStats *txfm_stats_list,
+                                    double bit_budget,
+                                    aom_bit_depth_t bit_depth,
+                                    int *q_index_list,
+                                    double *estimated_bitrate_byframe) {
+  int q_max = 255;  // Maximum q value.
+  int q_min = 0;    // Minimum q value.
+  int q = (q_max + q_min) / 2;
+
+  double q_max_estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+      vbr_rc_info, gf_group, q_max, txfm_stats_list, bit_depth, q_index_list,
+      estimated_bitrate_byframe);
+
+  double q_min_estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+      vbr_rc_info, gf_group, q_min, txfm_stats_list, bit_depth, q_index_list,
+      estimated_bitrate_byframe);
+
+  while (q_min + 1 < q_max) {
+    double estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+        vbr_rc_info, gf_group, q, txfm_stats_list, bit_depth, q_index_list,
+        estimated_bitrate_byframe);
+    if (estimate > bit_budget) {
+      q_min = q;
+      q_min_estimate = estimate;
+    } else {
+      q_max = q;
+      q_max_estimate = estimate;
+    }
+    q = (q_max + q_min) / 2;
+  }
+  // Pick the estimate that lands closest to the budget.
+  if (fabs(q_max_estimate - bit_budget) < fabs(q_min_estimate - bit_budget)) {
+    q = q_max;
+  } else {
+    q = q_min;
+  }
+  // Update q_index_list and vbr_rc_info.
+  av1_vbr_rc_info_estimate_gop_bitrate(vbr_rc_info, gf_group, q,
+                                       txfm_stats_list, bit_depth, q_index_list,
+                                       estimated_bitrate_byframe);
+  return q;
+}
 void av1_vbr_rc_update_q_index_list(VBR_RATECTRL_INFO *vbr_rc_info,
                                     const TplParams *tpl_data,
                                     const GF_GROUP *gf_group,
@@ -2032,26 +2057,15 @@
     vbr_rc_info->qstep_ratio_list[i] = av1_tpl_get_qstep_ratio(tpl_data, i);
   }
 
-  // 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.
-  int stats_valid_list[MAX_LENGTH_TPL_FRAME_STATS] = { 0 };
-  get_tpl_stats_valid_list(tpl_data, gf_group->size, stats_valid_list);
-
   double mv_bits = av1_tpl_compute_mv_bits(tpl_data, gf_group, vbr_rc_info);
 
   mv_bits = AOMMIN(mv_bits, 0.6 * gop_bit_budget);
   gop_bit_budget -= mv_bits;
 
-  int gf_frame_index = 0;
-  // TODO(angiebird): This part seems like a bug. We only use scale_factor
-  // for gf_frame_index == 0. Fix this part in a follow-up CL
-  double scale_factor =
-      vbr_rc_info->scale_factors[gf_group->update_type[gf_frame_index]];
-
-  vbr_rc_info->base_q_index = av1_q_mode_estimate_base_q(
-      gf_group, tpl_data->txfm_stats_list, stats_valid_list, gop_bit_budget,
-      bit_depth, scale_factor, vbr_rc_info->qstep_ratio_list,
-      vbr_rc_info->q_index_list, vbr_rc_info->estimated_bitrate_byframe);
+  vbr_rc_info->base_q_index = av1_vbr_rc_info_estimate_base_q(
+      vbr_rc_info, gf_group, tpl_data->txfm_stats_list, gop_bit_budget,
+      bit_depth, vbr_rc_info->q_index_list,
+      vbr_rc_info->estimated_bitrate_byframe);
 }
 
 /* For a GOP, calculate the bits used by motion vectors. */
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index 34565cf..98e76bc 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -95,7 +95,9 @@
 #define TPL_EPSILON 0.0000001
 
 typedef struct TplTxfmStats {
+  int ready;                  // Whether abs_coeff_mean is ready
   double abs_coeff_sum[256];  // Assume we are using 16x16 transform block
+  double abs_coeff_mean[256];
   int txfm_block_count;
   int coeff_num;
 } TplTxfmStats;
@@ -226,7 +228,6 @@
  * experiment.
  */
 typedef struct {
-  double keyframe_bitrate;
   double total_bit_budget;  // The total bit budget of the entire video
   int show_frame_count;     // Number of show frames in the entire video
 
@@ -263,35 +264,10 @@
   av1_zero(vbr_rc_info->actual_coeff_bitrate_byframe);
 }
 
-static INLINE void vbr_rc_init(VBR_RATECTRL_INFO *vbr_rc_info,
-                               double total_bit_budget, int show_frame_count) {
-  vbr_rc_info->total_bit_budget = total_bit_budget;
-  vbr_rc_info->show_frame_count = show_frame_count;
-  vbr_rc_info->keyframe_bitrate = 0;
-  const double scale_factors[FRAME_UPDATE_TYPES] = { 0.94559, 0.12040, 1,
-                                                     1.10199, 1,       1,
-                                                     0.16393 };
-  const double mv_scale_factors[FRAME_UPDATE_TYPES] = { 3, 3, 3, 3, 3, 3, 3 };
-  memcpy(vbr_rc_info->scale_factors, scale_factors,
-         sizeof(scale_factors[0]) * FRAME_UPDATE_TYPES);
-  memcpy(vbr_rc_info->mv_scale_factors, mv_scale_factors,
-         sizeof(mv_scale_factors[0]) * FRAME_UPDATE_TYPES);
-
-  vbr_rc_reset_gop_data(vbr_rc_info);
-}
-
-static INLINE void vbr_rc_set_gop_bit_budget(VBR_RATECTRL_INFO *vbr_rc_info,
-                                             int gop_showframe_count) {
-  vbr_rc_info->gop_showframe_count = gop_showframe_count;
-  vbr_rc_info->gop_bit_budget = vbr_rc_info->total_bit_budget *
-                                gop_showframe_count /
-                                vbr_rc_info->show_frame_count;
-}
-
-static INLINE void vbr_rc_set_keyframe_bitrate(VBR_RATECTRL_INFO *vbr_rc_info,
-                                               double keyframe_bitrate) {
-  vbr_rc_info->keyframe_bitrate = keyframe_bitrate;
-}
+void av1_vbr_rc_init(VBR_RATECTRL_INFO *vbr_rc_info, double total_bit_budget,
+                     int show_frame_count);
+void av1_vbr_rc_set_gop_bit_budget(VBR_RATECTRL_INFO *vbr_rc_info,
+                                   int gop_showframe_count);
 
 static INLINE void vbr_rc_info_log(const VBR_RATECTRL_INFO *vbr_rc_info,
                                    int gf_frame_index, int gf_group_size,
@@ -313,6 +289,74 @@
   }
 }
 
+/*!\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]       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,
+                                    aom_bit_depth_t bit_depth);
+/*
+ *!\brief Compute the number of bits needed to encode a GOP
+ *
+ * \param[out]   vbr_rc_info       Rate control info for BITRATE_ACCURACY
+ *                                 experiment
+ * \param[in]    gf_group          GOP struct
+ * \param[in]    base_q_index      base layer q_index
+ * \param[in]    stats_list        array of transform stats, one per frame
+ * \param[in]    bit_depth         bit depth
+ * \param[out]   q_index_list      array of q_index, one per frame
+ * \param[out]   estimated_bitrate_byframe Array to keep track of frame bitrate
+ *
+ * \return The estimated GOP bitrate.
+ *
+ */
+double av1_vbr_rc_info_estimate_gop_bitrate(
+    const VBR_RATECTRL_INFO *vbr_rc_info, const GF_GROUP *gf_group,
+    int base_q_index, const TplTxfmStats *stats_list, aom_bit_depth_t bit_depth,
+    int *q_index_list, double *estimated_bitrate_byframe);
+
+/*!\brief Estimate the optimal base q index for a GOP.
+ *
+ * This function uses a binary search to find base layer q index to
+ * achieve the specified bit budget.
+ *
+ * \param[out]  vbr_rc_info       Rate control info for BITRATE_ACCURACY
+ *                                experiment
+ * \param[in]   gf_group          GOP structure
+ * \param[in]   txfm_stats_list   Transform stats struct
+ * \param[in]   bit_budget        The specified bit budget to achieve
+ * \param[in]   bit_depth         bit depth
+ * \param[out]  q_index_list      array of q indices for the GOP inferred from
+ * base q index using qstep_ratio_list. \param[out]  estimated_bitrate_byframe
+ * bits usage per frame in the GOP
+ *
+ * \return Returns the optimal base q index to use.
+ */
+int av1_vbr_rc_info_estimate_base_q(const VBR_RATECTRL_INFO *vbr_rc_info,
+                                    const GF_GROUP *gf_group,
+                                    const TplTxfmStats *txfm_stats_list,
+                                    double bit_budget,
+                                    aom_bit_depth_t bit_depth,
+                                    int *q_index_list,
+                                    double *estimated_bitrate_byframe);
+
+/*!\brief For a GOP, calculate the bits used by motion vectors.
+ *
+ * \param[in]       tpl_data          TPL struct
+ * \param[in]       gf_group          GOP struct
+ * \param[in]       vbr_rc_info       Rate control info struct
+ *
+ * \return Bits used by the motion vectors for the GOP.
+ */
+double av1_tpl_compute_mv_bits(const TplParams *tpl_data,
+                               const GF_GROUP *gf_group,
+                               VBR_RATECTRL_INFO *vbr_rc_info);
 #endif  // CONFIG_BITRATE_ACCURACY
 
 #if CONFIG_RD_COMMAND
@@ -430,24 +474,6 @@
                                        int coeff_num);
 
 /*
- *!\brief Compute the number of bits needed to encode a GOP
- *
- * \param[in]    q_index_list      array of q_index, one per frame
- * \param[in]    frame_count       number of frames in the GOP
- * \param[in]    stats             array of transform stats, one per frame
- * \param[in]    stats_valid_list  List indicates whether transform stats
- *                                 exists
- * \param[out]   bitrate_byframe_list    Array to keep track of frame bitrate
- *
- * \return The estimated GOP bitrate.
- *
- */
-double av1_estimate_gop_bitrate(const int *q_index_list, const int frame_count,
-                                const TplTxfmStats *stats,
-                                const int *stats_valid_list,
-                                double *bitrate_byframe_list);
-
-/*
  *!\brief Init TplTxfmStats
  *
  * \param[in]    tpl_txfm_stats  a structure for storing transform stats
@@ -477,6 +503,16 @@
 void av1_record_tpl_txfm_block(TplTxfmStats *tpl_txfm_stats,
                                const tran_low_t *coeff);
 
+/*
+ *!\brief Update abs_coeff_mean and ready of txfm_stats
+ * If txfm_block_count > 0, this function will use abs_coeff_sum and
+ * txfm_block_count to compute abs_coeff_mean. Moreover, reday flag
+ * will be set to one.
+ *
+ * \param[in]  txfm_stats     A structure for storing transform stats
+ */
+void av1_tpl_txfm_stats_update_abs_coeff_mean(TplTxfmStats *txfm_stats);
+
 /*!\brief  Estimate coefficient entropy using Laplace dsitribution
  *
  *\ingroup tpl_modelling
@@ -533,33 +569,6 @@
 int av1_get_overlap_area(int row_a, int col_a, int row_b, int col_b, int width,
                          int height);
 
-/*!\brief Estimate the optimal base q index for a GOP.
- *
- * This function picks q based on a chosen bit rate. It
- * estimates the bit rate using the starting base q, then uses
- * a binary search to find q to achieve the specified bit rate.
- *
- * \param[in]       gf_group          GOP structure
- * \param[in]       txfm_stats_list   Transform stats struct
- * \param[in]       stats_valid_list  List indicates whether transform stats
- *                                    exists
- * \param[in]       bit_budget        The specified bit budget to achieve
- * \param[in]       bit_depth         bit depth
- * \param[in]       scale_factor      Scale factor to improve budget estimation
- * \param[in]       qstep_ratio_list  Stores the qstep_ratio for each frame
- * \param[out]      q_index_list      array of q_index, one per frame
- * \param[out]      estimated_bitrate_byframe  bits usage per frame in the GOP
- *
- * \return Returns the optimal base q index to use.
- */
-int av1_q_mode_estimate_base_q(const struct GF_GROUP *gf_group,
-                               const TplTxfmStats *txfm_stats_list,
-                               const int *stats_valid_list, double bit_budget,
-                               aom_bit_depth_t bit_depth, double scale_factor,
-                               const double *qstep_ratio_list,
-                               int *q_index_list,
-                               double *estimated_bitrate_byframe);
-
 /*!\brief Get current frame's q_index from tpl stats and leaf_qindex
  *
  * \param[in]       tpl_data          TPL struct
@@ -606,33 +615,6 @@
 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]       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,
-                                    aom_bit_depth_t bit_depth);
-
-/*!\brief For a GOP, calculate the bits used by motion vectors.
- *
- * \param[in]       tpl_data          TPL struct
- * \param[in]       gf_group          GOP struct
- * \param[in]       vbr_rc_info       Rate control info struct
- *
- * \return Bits used by the motion vectors for the GOP.
- */
-double av1_tpl_compute_mv_bits(const TplParams *tpl_data,
-                               const GF_GROUP *gf_group,
-                               VBR_RATECTRL_INFO *vbr_rc_info);
-#endif  // CONFIG_BITRATE_ACCURACY
-
 /*!\brief Improve the motion vector estimation by taking neighbors into account.
  *
  * Use the upper and left neighbor block as the reference MVs.
diff --git a/test/tpl_model_test.cc b/test/tpl_model_test.cc
index b507a8a..3d097de 100644
--- a/test/tpl_model_test.cc
+++ b/test/tpl_model_test.cc
@@ -19,6 +19,10 @@
 
 namespace {
 
+#if CONFIG_BITRATE_ACCURACY
+constexpr double epsilon = 0.0000001;
+#endif
+
 double laplace_prob(double q_step, double b, double zero_bin_ratio,
                     int qcoeff) {
   int abs_qcoeff = abs(qcoeff);
@@ -147,33 +151,6 @@
   EXPECT_EQ(overlap_area, 0);
 }
 
-TEST(TPLModelTest, EstimateFrameRateTest) {
-  /*
-   * Transform size: 16x16
-   * Frame count: 16
-   * Transform block count: 20
-   */
-  const int txfm_size = 256;  // 16x16
-  const int frame_count = 16;
-  int q_index_list[16];
-  int valid_list[16];
-  TplTxfmStats stats_list[16];
-
-  for (int i = 0; i < frame_count; i++) {
-    q_index_list[i] = 1;
-    valid_list[i] = 1;
-    stats_list[i].txfm_block_count = 8;
-
-    for (int j = 0; j < txfm_size; j++) {
-      stats_list[i].abs_coeff_sum[j] = 0;
-    }
-  }
-
-  double result = av1_estimate_gop_bitrate(q_index_list, frame_count,
-                                           stats_list, valid_list, NULL);
-  EXPECT_NEAR(result, 0, 0.1);
-}
-
 TEST(TPLModelTest, TxfmStatsInitTest) {
   TplTxfmStats tpl_txfm_stats;
   av1_init_tpl_txfm_stats(&tpl_txfm_stats);
@@ -231,89 +208,6 @@
   }
 }
 
-/*
- * 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, const double *qstep_ratio_list,
-                         GF_GROUP gf_group, const int *stats_valid_list,
-                         TplTxfmStats *stats_list, 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(255, qstep_ratio_list, bit_depth, &gf_group,
-                                   gf_group.q_val);
-  double curr_estimate = av1_estimate_gop_bitrate(
-      gf_group.q_val, gf_group.size, stats_list, stats_valid_list, NULL);
-  double best_estimate_budget_distance = fabs(curr_estimate - bit_budget);
-  int best_q = 255;
-
-  // 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(q, qstep_ratio_list, bit_depth, &gf_group,
-                                     gf_group.q_val);
-    curr_estimate = av1_estimate_gop_bitrate(
-        gf_group.q_val, gf_group.size, stats_list, stats_valid_list, NULL);
-    double curr_estimate_budget_distance = fabs(curr_estimate - bit_budget);
-    if (curr_estimate_budget_distance <= best_estimate_budget_distance) {
-      best_estimate_budget_distance = curr_estimate_budget_distance;
-      best_q = q;
-    }
-  }
-  return best_q;
-}
-
-TEST(TplModelTest, QModeEstimateBaseQTest) {
-  GF_GROUP gf_group = {};
-  gf_group.size = 25;
-  TplTxfmStats stats_list[25];
-  int q_index_list[25];
-  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 };
-  int stats_valid_list[25] = { 0 };
-  const aom_bit_depth_t bit_depth = AOM_BITS_8;
-  const double scale_factor = 1.0;
-
-  double qstep_ratio_list[25];
-  for (int i = 0; i < 25; i++) {
-    qstep_ratio_list[i] = 1;
-  }
-
-  for (int i = 0; i < gf_group.size; i++) {
-    stats_valid_list[i] = 1;
-    gf_group.update_type[i] = gf_group_update_types[i];
-    stats_list[i].txfm_block_count = 8;
-
-    for (int j = 0; j < 256; j++) {
-      stats_list[i].abs_coeff_sum[j] = 1000 + j;
-    }
-  }
-
-  // Test multiple bit budgets.
-  const std::vector<double> bit_budgets = { 0,      100,    1000,   10000,
-                                            100000, 300000, 500000, 750000,
-                                            800000, DBL_MAX };
-
-  for (double bit_budget : bit_budgets) {
-    // Binary search method to find the optimal q.
-    const int result = av1_q_mode_estimate_base_q(
-        &gf_group, stats_list, stats_valid_list, bit_budget, bit_depth,
-        scale_factor, qstep_ratio_list, q_index_list, NULL);
-    const int test_result =
-        find_gop_q_iterative(bit_budget, qstep_ratio_list, gf_group,
-                             stats_valid_list, stats_list, bit_depth);
-
-    if (bit_budget == 0) {
-      EXPECT_EQ(result, 255);
-    } else if (bit_budget == DBL_MAX) {
-      EXPECT_EQ(result, 0);
-    }
-
-    EXPECT_EQ(result, test_result);
-  }
-}
-
 TEST(TplModelTest, ComputeMVDifferenceTest) {
   TplDepFrame tpl_frame_small;
   tpl_frame_small.is_valid = true;
@@ -420,5 +314,168 @@
   // Neighboring vectors will have different values, increasing the cost.
   EXPECT_NEAR(result, 70, 5);
 }
+#if CONFIG_BITRATE_ACCURACY
+
+TEST(TplModelTest, VbrRcInfoSetGopBitBudget) {
+  VBR_RATECTRL_INFO vbr_rc_info;
+  const double total_bit_budget = 2000;
+  const int show_frame_count = 8;
+  const int gop_show_frame_count = 4;
+  av1_vbr_rc_init(&vbr_rc_info, total_bit_budget, show_frame_count);
+  av1_vbr_rc_set_gop_bit_budget(&vbr_rc_info, gop_show_frame_count);
+  EXPECT_NEAR(vbr_rc_info.gop_bit_budget, 1000, epsilon);
+}
+
+void init_toy_gf_group(GF_GROUP *gf_group) {
+  av1_zero(*gf_group);
+  gf_group->size = 4;
+  const FRAME_UPDATE_TYPE update_type[4] = { KF_UPDATE, ARF_UPDATE,
+                                             INTNL_ARF_UPDATE, LF_UPDATE };
+  for (int i = 0; i < gf_group->size; ++i) {
+    gf_group->update_type[i] = update_type[i];
+  }
+}
+
+void init_toy_vbr_rc_info(VBR_RATECTRL_INFO *vbr_rc_info, int gop_size) {
+  int total_bit_budget = 2000;
+  int show_frame_count = 8;
+  av1_vbr_rc_init(vbr_rc_info, total_bit_budget, show_frame_count);
+
+  for (int i = 0; i < gop_size; ++i) {
+    vbr_rc_info->qstep_ratio_list[i] = 1;
+  }
+}
+
+void init_toy_tpl_txfm_stats(std::vector<TplTxfmStats> *stats_list) {
+  for (size_t i = 0; i < stats_list->size(); i++) {
+    TplTxfmStats *txfm_stats = &stats_list->at(i);
+    av1_init_tpl_txfm_stats(txfm_stats);
+    txfm_stats->txfm_block_count = 8;
+    for (int j = 0; j < txfm_stats->coeff_num; j++) {
+      txfm_stats->abs_coeff_sum[j] = 1000 + j;
+    }
+    av1_tpl_txfm_stats_update_abs_coeff_mean(txfm_stats);
+  }
+}
+
+/*
+ * Helper method to brute-force search for the closest q_index
+ * that achieves the specified bit budget.
+ */
+int find_gop_q_iterative(const VBR_RATECTRL_INFO *vbr_rc_info,
+                         const GF_GROUP *gf_group,
+                         const TplTxfmStats *txfm_stats_list, double bit_budget,
+                         aom_bit_depth_t bit_depth, int *q_index_list,
+                         double *estimated_bitrate_byframe) {
+  int best_q = 255;
+  double curr_estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+      vbr_rc_info, gf_group, best_q, txfm_stats_list, bit_depth, q_index_list,
+      estimated_bitrate_byframe);
+  double min_bits_diff = fabs(curr_estimate - bit_budget);
+  // Start at q = 254 because we already have an estimate for q = 255.
+  for (int q = 254; q >= 0; q--) {
+    double curr_estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+        vbr_rc_info, gf_group, q, txfm_stats_list, bit_depth, q_index_list,
+        estimated_bitrate_byframe);
+    double bits_diff = fabs(curr_estimate - bit_budget);
+    if (bits_diff <= min_bits_diff) {
+      min_bits_diff = bits_diff;
+      best_q = q;
+    }
+  }
+  return best_q;
+}
+
+TEST(TPLModelTest, EstimateFrameRateTest) {
+  GF_GROUP gf_group;
+  init_toy_gf_group(&gf_group);
+
+  VBR_RATECTRL_INFO vbr_rc_info;
+  init_toy_vbr_rc_info(&vbr_rc_info, gf_group.size);
+
+  std::vector<TplTxfmStats> stats_list(gf_group.size);
+  init_toy_tpl_txfm_stats(&stats_list);
+  const aom_bit_depth_t bit_depth = AOM_BITS_8;
+
+  const int q = 125;
+
+  // Case1: all scale factors are 0
+  double scale_factors[FRAME_UPDATE_TYPES] = { 0 };
+  memcpy(vbr_rc_info.scale_factors, scale_factors, sizeof(scale_factors));
+  double estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+      &vbr_rc_info, &gf_group, q, stats_list.data(), bit_depth,
+      vbr_rc_info.q_index_list, vbr_rc_info.estimated_bitrate_byframe);
+  EXPECT_NEAR(estimate, 0, epsilon);
+
+  // Case2: all scale factors are 1
+  for (int i = 0; i < FRAME_UPDATE_TYPES; i++) {
+    scale_factors[i] = 1;
+  }
+  memcpy(vbr_rc_info.scale_factors, scale_factors, sizeof(scale_factors));
+  estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+      &vbr_rc_info, &gf_group, q, stats_list.data(), bit_depth,
+      vbr_rc_info.q_index_list, vbr_rc_info.estimated_bitrate_byframe);
+  double ref_estimate = 0;
+  for (int i = 0; i < gf_group.size; i++) {
+    ref_estimate += vbr_rc_info.estimated_bitrate_byframe[i];
+  }
+  EXPECT_NEAR(estimate, ref_estimate, epsilon);
+
+  // Case3: Key frame scale factor is 0 and others are 1
+  for (int i = 0; i < FRAME_UPDATE_TYPES; i++) {
+    if (i == KF_UPDATE) {
+      scale_factors[i] = 0;
+    } else {
+      scale_factors[i] = 1;
+    }
+  }
+  memcpy(vbr_rc_info.scale_factors, scale_factors, sizeof(scale_factors));
+  estimate = av1_vbr_rc_info_estimate_gop_bitrate(
+      &vbr_rc_info, &gf_group, q, stats_list.data(), bit_depth,
+      vbr_rc_info.q_index_list, vbr_rc_info.estimated_bitrate_byframe);
+  ref_estimate = 0;
+  for (int i = 0; i < gf_group.size; i++) {
+    if (gf_group.update_type[i] != KF_UPDATE) {
+      ref_estimate += vbr_rc_info.estimated_bitrate_byframe[i];
+    }
+  }
+  EXPECT_NEAR(estimate, ref_estimate, epsilon);
+}
+
+TEST(TplModelTest, VbrRcInfoEstimateBaseQTest) {
+  GF_GROUP gf_group;
+  init_toy_gf_group(&gf_group);
+
+  VBR_RATECTRL_INFO vbr_rc_info;
+  init_toy_vbr_rc_info(&vbr_rc_info, gf_group.size);
+
+  VBR_RATECTRL_INFO ref_vbr_rc_info;
+  init_toy_vbr_rc_info(&ref_vbr_rc_info, gf_group.size);
+
+  std::vector<TplTxfmStats> stats_list(gf_group.size);
+  init_toy_tpl_txfm_stats(&stats_list);
+  const aom_bit_depth_t bit_depth = AOM_BITS_8;
+
+  // Test multiple bit budgets.
+  const std::vector<double> bit_budgets = { 0,     2470,  19200,  30750,
+                                            41315, 65017, DBL_MAX };
+
+  for (double bit_budget : bit_budgets) {
+    // Binary search method to find the optimal q.
+    const int base_q = av1_vbr_rc_info_estimate_base_q(
+        &vbr_rc_info, &gf_group, stats_list.data(), bit_budget, bit_depth,
+        vbr_rc_info.q_index_list, vbr_rc_info.estimated_bitrate_byframe);
+    const int ref_base_q = find_gop_q_iterative(
+        &ref_vbr_rc_info, &gf_group, stats_list.data(), bit_budget, bit_depth,
+        ref_vbr_rc_info.q_index_list, vbr_rc_info.estimated_bitrate_byframe);
+    if (bit_budget == 0) {
+      EXPECT_EQ(base_q, 255);
+    } else if (bit_budget == DBL_MAX) {
+      EXPECT_EQ(base_q, 0);
+    }
+    EXPECT_EQ(base_q, ref_base_q);
+  }
+}
+#endif  // CONFIG_BITRATE_ACCURACY
 
 }  // namespace