Add av1_estimate_gop_bitrate to tpl_model.

Change-Id: Ic0f2ea5809b027c80fad5510c9739cd5926947a0
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index f46e4f1..f019946 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1747,6 +1747,7 @@
 double av1_laplace_entropy(double q_step, double b, double zero_bin_ratio) {
   // zero bin's size is zero_bin_ratio * q_step
   // non-zero bin's size is q_step
+  b = AOMMAX(b, TPL_EPSILON);
   double z = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON);
   double h = av1_exponential_entropy(q_step, b);
   double r = -(1 - z) * log2(1 - z) - z * log2(z) + z * (h + 1);
@@ -1771,6 +1772,28 @@
   return est_rate;
 }
 
+double av1_estimate_gop_bitrate(const unsigned char *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++) {
+    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;
+  }
+  return gop_bitrate;
+}
+
 double av1_estimate_coeff_entropy(double q_step, double b,
                                   double zero_bin_ratio, int qcoeff) {
   int abs_qcoeff = abs(qcoeff);
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index 7c60b1b..0286c16 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -306,6 +306,18 @@
                                        const double *abs_coeff_mean,
                                        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
+ *
+ */
+double av1_estimate_gop_bitrate(const unsigned char *q_index_list,
+                                const int frame_count,
+                                const TplTxfmStats *stats);
+
 /*!\brief  Init data structure storing transform stats
  *
  *\ingroup tpl_modelling
diff --git a/test/tpl_model_test.cc b/test/tpl_model_test.cc
index 8d5edcd..a29d29c 100644
--- a/test/tpl_model_test.cc
+++ b/test/tpl_model_test.cc
@@ -14,6 +14,7 @@
 
 #include "av1/encoder/cost.h"
 #include "av1/encoder/tpl_model.h"
+#include "av1/encoder/encoder.h"
 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
 
 namespace {
@@ -140,4 +141,29 @@
   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;
+  unsigned char q_index_list[16];
+  TplTxfmStats stats_list[16];
+
+  for (int i = 0; i < frame_count; i++) {
+    q_index_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);
+  EXPECT_NEAR(result, 0, 0.1);
+}
+
 }  // namespace