xref: /aosp_15_r20/external/libaom/test/tpl_model_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker  * Copyright (c) 2021, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker  *
4*77c1e3ccSAndroid Build Coastguard Worker  * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker  * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker  * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker  */
11*77c1e3ccSAndroid Build Coastguard Worker 
12*77c1e3ccSAndroid Build Coastguard Worker #include <cstdlib>
13*77c1e3ccSAndroid Build Coastguard Worker #include <memory>
14*77c1e3ccSAndroid Build Coastguard Worker #include <new>
15*77c1e3ccSAndroid Build Coastguard Worker #include <vector>
16*77c1e3ccSAndroid Build Coastguard Worker 
17*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/cost.h"
18*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/tpl_model.h"
19*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encoder.h"
20*77c1e3ccSAndroid Build Coastguard Worker #include "gtest/gtest.h"
21*77c1e3ccSAndroid Build Coastguard Worker 
22*77c1e3ccSAndroid Build Coastguard Worker namespace {
23*77c1e3ccSAndroid Build Coastguard Worker 
24*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_BITRATE_ACCURACY
25*77c1e3ccSAndroid Build Coastguard Worker constexpr double epsilon = 0.0000001;
26*77c1e3ccSAndroid Build Coastguard Worker #endif
27*77c1e3ccSAndroid Build Coastguard Worker 
laplace_prob(double q_step,double b,double zero_bin_ratio,int qcoeff)28*77c1e3ccSAndroid Build Coastguard Worker double laplace_prob(double q_step, double b, double zero_bin_ratio,
29*77c1e3ccSAndroid Build Coastguard Worker                     int qcoeff) {
30*77c1e3ccSAndroid Build Coastguard Worker   int abs_qcoeff = abs(qcoeff);
31*77c1e3ccSAndroid Build Coastguard Worker   double z0 = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON);
32*77c1e3ccSAndroid Build Coastguard Worker   if (abs_qcoeff == 0) {
33*77c1e3ccSAndroid Build Coastguard Worker     double p0 = 1 - z0;
34*77c1e3ccSAndroid Build Coastguard Worker     return p0;
35*77c1e3ccSAndroid Build Coastguard Worker   } else {
36*77c1e3ccSAndroid Build Coastguard Worker     assert(abs_qcoeff > 0);
37*77c1e3ccSAndroid Build Coastguard Worker     double z = fmax(exp(-q_step / b), TPL_EPSILON);
38*77c1e3ccSAndroid Build Coastguard Worker     double p = z0 / 2 * (1 - z) * pow(z, abs_qcoeff - 1);
39*77c1e3ccSAndroid Build Coastguard Worker     return p;
40*77c1e3ccSAndroid Build Coastguard Worker   }
41*77c1e3ccSAndroid Build Coastguard Worker }
TEST(TplModelTest,ExponentialEntropyBoundaryTest1)42*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, ExponentialEntropyBoundaryTest1) {
43*77c1e3ccSAndroid Build Coastguard Worker   double b = 0;
44*77c1e3ccSAndroid Build Coastguard Worker   double q_step = 1;
45*77c1e3ccSAndroid Build Coastguard Worker   double entropy = av1_exponential_entropy(q_step, b);
46*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(entropy, 0, 0.00001);
47*77c1e3ccSAndroid Build Coastguard Worker }
48*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,TransformCoeffEntropyTest1)49*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, TransformCoeffEntropyTest1) {
50*77c1e3ccSAndroid Build Coastguard Worker   // Check the consistency between av1_estimate_coeff_entropy() and
51*77c1e3ccSAndroid Build Coastguard Worker   // laplace_prob()
52*77c1e3ccSAndroid Build Coastguard Worker   double b = 1;
53*77c1e3ccSAndroid Build Coastguard Worker   double q_step = 1;
54*77c1e3ccSAndroid Build Coastguard Worker   double zero_bin_ratio = 2;
55*77c1e3ccSAndroid Build Coastguard Worker   for (int qcoeff = -256; qcoeff < 256; ++qcoeff) {
56*77c1e3ccSAndroid Build Coastguard Worker     double rate = av1_estimate_coeff_entropy(q_step, b, zero_bin_ratio, qcoeff);
57*77c1e3ccSAndroid Build Coastguard Worker     double prob = laplace_prob(q_step, b, zero_bin_ratio, qcoeff);
58*77c1e3ccSAndroid Build Coastguard Worker     double ref_rate = -log2(prob);
59*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_DOUBLE_EQ(rate, ref_rate);
60*77c1e3ccSAndroid Build Coastguard Worker   }
61*77c1e3ccSAndroid Build Coastguard Worker }
62*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,TransformCoeffEntropyTest2)63*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, TransformCoeffEntropyTest2) {
64*77c1e3ccSAndroid Build Coastguard Worker   // Check the consistency between av1_estimate_coeff_entropy(), laplace_prob()
65*77c1e3ccSAndroid Build Coastguard Worker   // and av1_laplace_entropy()
66*77c1e3ccSAndroid Build Coastguard Worker   double b = 1;
67*77c1e3ccSAndroid Build Coastguard Worker   double q_step = 1;
68*77c1e3ccSAndroid Build Coastguard Worker   double zero_bin_ratio = 2;
69*77c1e3ccSAndroid Build Coastguard Worker   double est_expected_rate = 0;
70*77c1e3ccSAndroid Build Coastguard Worker   for (int qcoeff = -20; qcoeff < 20; ++qcoeff) {
71*77c1e3ccSAndroid Build Coastguard Worker     double rate = av1_estimate_coeff_entropy(q_step, b, zero_bin_ratio, qcoeff);
72*77c1e3ccSAndroid Build Coastguard Worker     double prob = laplace_prob(q_step, b, zero_bin_ratio, qcoeff);
73*77c1e3ccSAndroid Build Coastguard Worker     est_expected_rate += prob * rate;
74*77c1e3ccSAndroid Build Coastguard Worker   }
75*77c1e3ccSAndroid Build Coastguard Worker   double expected_rate = av1_laplace_entropy(q_step, b, zero_bin_ratio);
76*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(expected_rate, est_expected_rate, 0.001);
77*77c1e3ccSAndroid Build Coastguard Worker }
78*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,InitTplStats1)79*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, InitTplStats1) {
80*77c1e3ccSAndroid Build Coastguard Worker   // We use heap allocation instead of stack allocation here to avoid
81*77c1e3ccSAndroid Build Coastguard Worker   // -Wstack-usage warning.
82*77c1e3ccSAndroid Build Coastguard Worker   std::unique_ptr<TplParams> tpl_data(new (std::nothrow) TplParams);
83*77c1e3ccSAndroid Build Coastguard Worker   ASSERT_NE(tpl_data, nullptr);
84*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(*tpl_data);
85*77c1e3ccSAndroid Build Coastguard Worker   tpl_data->ready = 1;
86*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(sizeof(tpl_data->tpl_stats_buffer),
87*77c1e3ccSAndroid Build Coastguard Worker             MAX_LENGTH_TPL_FRAME_STATS * sizeof(tpl_data->tpl_stats_buffer[0]));
88*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < MAX_LENGTH_TPL_FRAME_STATS; ++i) {
89*77c1e3ccSAndroid Build Coastguard Worker     // Set it to a random non-zero number
90*77c1e3ccSAndroid Build Coastguard Worker     tpl_data->tpl_stats_buffer[i].is_valid = i + 1;
91*77c1e3ccSAndroid Build Coastguard Worker   }
92*77c1e3ccSAndroid Build Coastguard Worker   av1_init_tpl_stats(tpl_data.get());
93*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(tpl_data->ready, 0);
94*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < MAX_LENGTH_TPL_FRAME_STATS; ++i) {
95*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_EQ(tpl_data->tpl_stats_buffer[i].is_valid, 0);
96*77c1e3ccSAndroid Build Coastguard Worker   }
97*77c1e3ccSAndroid Build Coastguard Worker }
98*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,DeltaRateCostZeroFlow)99*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, DeltaRateCostZeroFlow) {
100*77c1e3ccSAndroid Build Coastguard Worker   // When srcrf_dist equal to recrf_dist, av1_delta_rate_cost should return 0
101*77c1e3ccSAndroid Build Coastguard Worker   int64_t srcrf_dist = 256;
102*77c1e3ccSAndroid Build Coastguard Worker   int64_t recrf_dist = 256;
103*77c1e3ccSAndroid Build Coastguard Worker   int64_t delta_rate = 512;
104*77c1e3ccSAndroid Build Coastguard Worker   int pixel_num = 256;
105*77c1e3ccSAndroid Build Coastguard Worker   int64_t rate_cost =
106*77c1e3ccSAndroid Build Coastguard Worker       av1_delta_rate_cost(delta_rate, recrf_dist, srcrf_dist, pixel_num);
107*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(rate_cost, 0);
108*77c1e3ccSAndroid Build Coastguard Worker }
109*77c1e3ccSAndroid Build Coastguard Worker 
110*77c1e3ccSAndroid Build Coastguard Worker // a reference function of av1_delta_rate_cost() with delta_rate using bit as
111*77c1e3ccSAndroid Build Coastguard Worker // basic unit
ref_delta_rate_cost(int64_t delta_rate,double src_rec_ratio,int pixel_count)112*77c1e3ccSAndroid Build Coastguard Worker double ref_delta_rate_cost(int64_t delta_rate, double src_rec_ratio,
113*77c1e3ccSAndroid Build Coastguard Worker                            int pixel_count) {
114*77c1e3ccSAndroid Build Coastguard Worker   assert(src_rec_ratio <= 1 && src_rec_ratio >= 0);
115*77c1e3ccSAndroid Build Coastguard Worker   double bits_per_pixel = (double)delta_rate / pixel_count;
116*77c1e3ccSAndroid Build Coastguard Worker   double p = pow(2, bits_per_pixel);
117*77c1e3ccSAndroid Build Coastguard Worker   double flow_rate_per_pixel =
118*77c1e3ccSAndroid Build Coastguard Worker       sqrt(p * p / (src_rec_ratio * p * p + (1 - src_rec_ratio)));
119*77c1e3ccSAndroid Build Coastguard Worker   double rate_cost = pixel_count * log2(flow_rate_per_pixel);
120*77c1e3ccSAndroid Build Coastguard Worker   return rate_cost;
121*77c1e3ccSAndroid Build Coastguard Worker }
122*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,DeltaRateCostReference)123*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, DeltaRateCostReference) {
124*77c1e3ccSAndroid Build Coastguard Worker   const int64_t scale = TPL_DEP_COST_SCALE_LOG2 + AV1_PROB_COST_SHIFT;
125*77c1e3ccSAndroid Build Coastguard Worker   std::vector<int64_t> srcrf_dist_arr = { 256, 257, 312 };
126*77c1e3ccSAndroid Build Coastguard Worker   std::vector<int64_t> recrf_dist_arr = { 512, 288, 620 };
127*77c1e3ccSAndroid Build Coastguard Worker   std::vector<int64_t> delta_rate_arr = { 10, 278, 100 };
128*77c1e3ccSAndroid Build Coastguard Worker   for (size_t t = 0; t < srcrf_dist_arr.size(); ++t) {
129*77c1e3ccSAndroid Build Coastguard Worker     int64_t srcrf_dist = srcrf_dist_arr[t];
130*77c1e3ccSAndroid Build Coastguard Worker     int64_t recrf_dist = recrf_dist_arr[t];
131*77c1e3ccSAndroid Build Coastguard Worker     int64_t delta_rate = delta_rate_arr[t];
132*77c1e3ccSAndroid Build Coastguard Worker     int64_t scaled_delta_rate = delta_rate << scale;
133*77c1e3ccSAndroid Build Coastguard Worker     int pixel_count = 256;
134*77c1e3ccSAndroid Build Coastguard Worker     int64_t rate_cost = av1_delta_rate_cost(scaled_delta_rate, recrf_dist,
135*77c1e3ccSAndroid Build Coastguard Worker                                             srcrf_dist, pixel_count);
136*77c1e3ccSAndroid Build Coastguard Worker     rate_cost >>= scale;
137*77c1e3ccSAndroid Build Coastguard Worker     double src_rec_ratio = (double)srcrf_dist / recrf_dist;
138*77c1e3ccSAndroid Build Coastguard Worker     double ref_rate_cost =
139*77c1e3ccSAndroid Build Coastguard Worker         ref_delta_rate_cost(delta_rate, src_rec_ratio, pixel_count);
140*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_NEAR((double)rate_cost, ref_rate_cost, 1);
141*77c1e3ccSAndroid Build Coastguard Worker   }
142*77c1e3ccSAndroid Build Coastguard Worker }
143*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,GetOverlapAreaHasOverlap)144*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, GetOverlapAreaHasOverlap) {
145*77c1e3ccSAndroid Build Coastguard Worker   // The block a's area is [10, 17) x [18, 24).
146*77c1e3ccSAndroid Build Coastguard Worker   // The block b's area is [8, 15) x [17, 23).
147*77c1e3ccSAndroid Build Coastguard Worker   // The overlapping area between block a and block b is [10, 15) x [18, 23).
148*77c1e3ccSAndroid Build Coastguard Worker   // Therefore, the size of the area is (15 - 10) * (23 - 18) = 25.
149*77c1e3ccSAndroid Build Coastguard Worker   int row_a = 10;
150*77c1e3ccSAndroid Build Coastguard Worker   int col_a = 18;
151*77c1e3ccSAndroid Build Coastguard Worker   int row_b = 8;
152*77c1e3ccSAndroid Build Coastguard Worker   int col_b = 17;
153*77c1e3ccSAndroid Build Coastguard Worker   int height = 7;
154*77c1e3ccSAndroid Build Coastguard Worker   int width = 6;
155*77c1e3ccSAndroid Build Coastguard Worker   int overlap_area =
156*77c1e3ccSAndroid Build Coastguard Worker       av1_get_overlap_area(row_a, col_a, row_b, col_b, width, height);
157*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(overlap_area, 25);
158*77c1e3ccSAndroid Build Coastguard Worker }
159*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,GetOverlapAreaNoOverlap)160*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, GetOverlapAreaNoOverlap) {
161*77c1e3ccSAndroid Build Coastguard Worker   // The block a's area is [10, 14) x [18, 22).
162*77c1e3ccSAndroid Build Coastguard Worker   // The block b's area is [5, 9) x [5, 9).
163*77c1e3ccSAndroid Build Coastguard Worker   // Threre is no overlapping area between block a and block b.
164*77c1e3ccSAndroid Build Coastguard Worker   // Therefore, the return value should be zero.
165*77c1e3ccSAndroid Build Coastguard Worker   int row_a = 10;
166*77c1e3ccSAndroid Build Coastguard Worker   int col_a = 18;
167*77c1e3ccSAndroid Build Coastguard Worker   int row_b = 5;
168*77c1e3ccSAndroid Build Coastguard Worker   int col_b = 5;
169*77c1e3ccSAndroid Build Coastguard Worker   int height = 4;
170*77c1e3ccSAndroid Build Coastguard Worker   int width = 4;
171*77c1e3ccSAndroid Build Coastguard Worker   int overlap_area =
172*77c1e3ccSAndroid Build Coastguard Worker       av1_get_overlap_area(row_a, col_a, row_b, col_b, width, height);
173*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(overlap_area, 0);
174*77c1e3ccSAndroid Build Coastguard Worker }
175*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,GetQIndexFromQstepRatio)176*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, GetQIndexFromQstepRatio) {
177*77c1e3ccSAndroid Build Coastguard Worker   const aom_bit_depth_t bit_depth = AOM_BITS_8;
178*77c1e3ccSAndroid Build Coastguard Worker   // When qstep_ratio is 1, the output q_index should be equal to leaf_qindex.
179*77c1e3ccSAndroid Build Coastguard Worker   double qstep_ratio = 1.0;
180*77c1e3ccSAndroid Build Coastguard Worker   for (int leaf_qindex = 1; leaf_qindex <= 255; ++leaf_qindex) {
181*77c1e3ccSAndroid Build Coastguard Worker     const int q_index =
182*77c1e3ccSAndroid Build Coastguard Worker         av1_get_q_index_from_qstep_ratio(leaf_qindex, qstep_ratio, bit_depth);
183*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_EQ(q_index, leaf_qindex);
184*77c1e3ccSAndroid Build Coastguard Worker   }
185*77c1e3ccSAndroid Build Coastguard Worker 
186*77c1e3ccSAndroid Build Coastguard Worker   // When qstep_ratio is very low, the output q_index should be 1.
187*77c1e3ccSAndroid Build Coastguard Worker   qstep_ratio = 0.0001;
188*77c1e3ccSAndroid Build Coastguard Worker   for (int leaf_qindex = 1; leaf_qindex <= 255; ++leaf_qindex) {
189*77c1e3ccSAndroid Build Coastguard Worker     const int q_index =
190*77c1e3ccSAndroid Build Coastguard Worker         av1_get_q_index_from_qstep_ratio(leaf_qindex, qstep_ratio, bit_depth);
191*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_EQ(q_index, 0);
192*77c1e3ccSAndroid Build Coastguard Worker   }
193*77c1e3ccSAndroid Build Coastguard Worker }
194*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,TxfmStatsInitTest)195*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, TxfmStatsInitTest) {
196*77c1e3ccSAndroid Build Coastguard Worker   TplTxfmStats tpl_txfm_stats;
197*77c1e3ccSAndroid Build Coastguard Worker   av1_init_tpl_txfm_stats(&tpl_txfm_stats);
198*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(tpl_txfm_stats.coeff_num, 256);
199*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(tpl_txfm_stats.txfm_block_count, 0);
200*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < tpl_txfm_stats.coeff_num; ++i) {
201*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_DOUBLE_EQ(tpl_txfm_stats.abs_coeff_sum[i], 0);
202*77c1e3ccSAndroid Build Coastguard Worker   }
203*77c1e3ccSAndroid Build Coastguard Worker }
204*77c1e3ccSAndroid Build Coastguard Worker 
205*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_BITRATE_ACCURACY
TEST(TplModelTest,TxfmStatsAccumulateTest)206*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, TxfmStatsAccumulateTest) {
207*77c1e3ccSAndroid Build Coastguard Worker   TplTxfmStats sub_stats;
208*77c1e3ccSAndroid Build Coastguard Worker   av1_init_tpl_txfm_stats(&sub_stats);
209*77c1e3ccSAndroid Build Coastguard Worker   sub_stats.txfm_block_count = 17;
210*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < sub_stats.coeff_num; ++i) {
211*77c1e3ccSAndroid Build Coastguard Worker     sub_stats.abs_coeff_sum[i] = i;
212*77c1e3ccSAndroid Build Coastguard Worker   }
213*77c1e3ccSAndroid Build Coastguard Worker 
214*77c1e3ccSAndroid Build Coastguard Worker   TplTxfmStats accumulated_stats;
215*77c1e3ccSAndroid Build Coastguard Worker   av1_init_tpl_txfm_stats(&accumulated_stats);
216*77c1e3ccSAndroid Build Coastguard Worker   accumulated_stats.txfm_block_count = 13;
217*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < accumulated_stats.coeff_num; ++i) {
218*77c1e3ccSAndroid Build Coastguard Worker     accumulated_stats.abs_coeff_sum[i] = 5 * i;
219*77c1e3ccSAndroid Build Coastguard Worker   }
220*77c1e3ccSAndroid Build Coastguard Worker 
221*77c1e3ccSAndroid Build Coastguard Worker   av1_accumulate_tpl_txfm_stats(&sub_stats, &accumulated_stats);
222*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_DOUBLE_EQ(accumulated_stats.txfm_block_count, 30);
223*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < accumulated_stats.coeff_num; ++i) {
224*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_DOUBLE_EQ(accumulated_stats.abs_coeff_sum[i], 6 * i);
225*77c1e3ccSAndroid Build Coastguard Worker   }
226*77c1e3ccSAndroid Build Coastguard Worker }
227*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,TxfmStatsRecordTest)228*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, TxfmStatsRecordTest) {
229*77c1e3ccSAndroid Build Coastguard Worker   TplTxfmStats stats1;
230*77c1e3ccSAndroid Build Coastguard Worker   TplTxfmStats stats2;
231*77c1e3ccSAndroid Build Coastguard Worker   av1_init_tpl_txfm_stats(&stats1);
232*77c1e3ccSAndroid Build Coastguard Worker   av1_init_tpl_txfm_stats(&stats2);
233*77c1e3ccSAndroid Build Coastguard Worker 
234*77c1e3ccSAndroid Build Coastguard Worker   tran_low_t coeff[256];
235*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 256; ++i) {
236*77c1e3ccSAndroid Build Coastguard Worker     coeff[i] = i;
237*77c1e3ccSAndroid Build Coastguard Worker   }
238*77c1e3ccSAndroid Build Coastguard Worker   av1_record_tpl_txfm_block(&stats1, coeff);
239*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(stats1.txfm_block_count, 1);
240*77c1e3ccSAndroid Build Coastguard Worker 
241*77c1e3ccSAndroid Build Coastguard Worker   // we record the same transform block twice for testing purpose
242*77c1e3ccSAndroid Build Coastguard Worker   av1_record_tpl_txfm_block(&stats2, coeff);
243*77c1e3ccSAndroid Build Coastguard Worker   av1_record_tpl_txfm_block(&stats2, coeff);
244*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(stats2.txfm_block_count, 2);
245*77c1e3ccSAndroid Build Coastguard Worker 
246*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(stats1.coeff_num, 256);
247*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(stats2.coeff_num, 256);
248*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < 256; ++i) {
249*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_DOUBLE_EQ(stats2.abs_coeff_sum[i], 2 * stats1.abs_coeff_sum[i]);
250*77c1e3ccSAndroid Build Coastguard Worker   }
251*77c1e3ccSAndroid Build Coastguard Worker }
252*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_BITRATE_ACCURACY
253*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,ComputeMVDifferenceTest)254*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, ComputeMVDifferenceTest) {
255*77c1e3ccSAndroid Build Coastguard Worker   TplDepFrame tpl_frame_small;
256*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame_small.is_valid = true;
257*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame_small.mi_rows = 4;
258*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame_small.mi_cols = 4;
259*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame_small.stride = 1;
260*77c1e3ccSAndroid Build Coastguard Worker   uint8_t right_shift_small = 1;
261*77c1e3ccSAndroid Build Coastguard Worker   int step_small = 1 << right_shift_small;
262*77c1e3ccSAndroid Build Coastguard Worker 
263*77c1e3ccSAndroid Build Coastguard Worker   // Test values for motion vectors.
264*77c1e3ccSAndroid Build Coastguard Worker   int mv_vals_small[4] = { 1, 2, 3, 4 };
265*77c1e3ccSAndroid Build Coastguard Worker   int index = 0;
266*77c1e3ccSAndroid Build Coastguard Worker 
267*77c1e3ccSAndroid Build Coastguard Worker   // 4x4 blocks means we need to allocate a 4 size array.
268*77c1e3ccSAndroid Build Coastguard Worker   // According to av1_tpl_ptr_pos:
269*77c1e3ccSAndroid Build Coastguard Worker   // (row >> right_shift) * stride + (col >> right_shift)
270*77c1e3ccSAndroid Build Coastguard Worker   // (4 >> 1) * 1 + (4 >> 1) = 4
271*77c1e3ccSAndroid Build Coastguard Worker   TplDepStats stats_buf_small[4];
272*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame_small.tpl_stats_ptr = stats_buf_small;
273*77c1e3ccSAndroid Build Coastguard Worker 
274*77c1e3ccSAndroid Build Coastguard Worker   for (int row = 0; row < tpl_frame_small.mi_rows; row += step_small) {
275*77c1e3ccSAndroid Build Coastguard Worker     for (int col = 0; col < tpl_frame_small.mi_cols; col += step_small) {
276*77c1e3ccSAndroid Build Coastguard Worker       TplDepStats tpl_stats;
277*77c1e3ccSAndroid Build Coastguard Worker       tpl_stats.ref_frame_index[0] = 0;
278*77c1e3ccSAndroid Build Coastguard Worker       int_mv mv;
279*77c1e3ccSAndroid Build Coastguard Worker       mv.as_mv.row = mv_vals_small[index];
280*77c1e3ccSAndroid Build Coastguard Worker       mv.as_mv.col = mv_vals_small[index];
281*77c1e3ccSAndroid Build Coastguard Worker       index++;
282*77c1e3ccSAndroid Build Coastguard Worker       tpl_stats.mv[0] = mv;
283*77c1e3ccSAndroid Build Coastguard Worker       tpl_frame_small.tpl_stats_ptr[av1_tpl_ptr_pos(
284*77c1e3ccSAndroid Build Coastguard Worker           row, col, tpl_frame_small.stride, right_shift_small)] = tpl_stats;
285*77c1e3ccSAndroid Build Coastguard Worker     }
286*77c1e3ccSAndroid Build Coastguard Worker   }
287*77c1e3ccSAndroid Build Coastguard Worker 
288*77c1e3ccSAndroid Build Coastguard Worker   int_mv result_mv =
289*77c1e3ccSAndroid Build Coastguard Worker       av1_compute_mv_difference(&tpl_frame_small, 1, 1, step_small,
290*77c1e3ccSAndroid Build Coastguard Worker                                 tpl_frame_small.stride, right_shift_small);
291*77c1e3ccSAndroid Build Coastguard Worker 
292*77c1e3ccSAndroid Build Coastguard Worker   // Expect the result to be exactly equal to 1 because this is the difference
293*77c1e3ccSAndroid Build Coastguard Worker   // between neighboring motion vectors in this instance.
294*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(result_mv.as_mv.row, 1);
295*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_EQ(result_mv.as_mv.col, 1);
296*77c1e3ccSAndroid Build Coastguard Worker }
297*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,ComputeMVBitsTest)298*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, ComputeMVBitsTest) {
299*77c1e3ccSAndroid Build Coastguard Worker   TplDepFrame tpl_frame;
300*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame.is_valid = true;
301*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame.mi_rows = 16;
302*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame.mi_cols = 16;
303*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame.stride = 24;
304*77c1e3ccSAndroid Build Coastguard Worker   uint8_t right_shift = 2;
305*77c1e3ccSAndroid Build Coastguard Worker   int step = 1 << right_shift;
306*77c1e3ccSAndroid Build Coastguard Worker   // Test values for motion vectors.
307*77c1e3ccSAndroid Build Coastguard Worker   int mv_vals_ordered[16] = { 1, 2,  3,  4,  5,  6,  7,  8,
308*77c1e3ccSAndroid Build Coastguard Worker                               9, 10, 11, 12, 13, 14, 15, 16 };
309*77c1e3ccSAndroid Build Coastguard Worker   int mv_vals[16] = { 1, 16, 2, 15, 3, 14, 4, 13, 5, 12, 6, 11, 7, 10, 8, 9 };
310*77c1e3ccSAndroid Build Coastguard Worker   int index = 0;
311*77c1e3ccSAndroid Build Coastguard Worker 
312*77c1e3ccSAndroid Build Coastguard Worker   // 16x16 blocks means we need to allocate a 100 size array.
313*77c1e3ccSAndroid Build Coastguard Worker   // According to av1_tpl_ptr_pos:
314*77c1e3ccSAndroid Build Coastguard Worker   // (row >> right_shift) * stride + (col >> right_shift)
315*77c1e3ccSAndroid Build Coastguard Worker   // (16 >> 2) * 24 + (16 >> 2) = 100
316*77c1e3ccSAndroid Build Coastguard Worker   TplDepStats stats_buf[100];
317*77c1e3ccSAndroid Build Coastguard Worker   tpl_frame.tpl_stats_ptr = stats_buf;
318*77c1e3ccSAndroid Build Coastguard Worker 
319*77c1e3ccSAndroid Build Coastguard Worker   for (int row = 0; row < tpl_frame.mi_rows; row += step) {
320*77c1e3ccSAndroid Build Coastguard Worker     for (int col = 0; col < tpl_frame.mi_cols; col += step) {
321*77c1e3ccSAndroid Build Coastguard Worker       TplDepStats tpl_stats;
322*77c1e3ccSAndroid Build Coastguard Worker       tpl_stats.ref_frame_index[0] = 0;
323*77c1e3ccSAndroid Build Coastguard Worker       int_mv mv;
324*77c1e3ccSAndroid Build Coastguard Worker       mv.as_mv.row = mv_vals_ordered[index];
325*77c1e3ccSAndroid Build Coastguard Worker       mv.as_mv.col = mv_vals_ordered[index];
326*77c1e3ccSAndroid Build Coastguard Worker       index++;
327*77c1e3ccSAndroid Build Coastguard Worker       tpl_stats.mv[0] = mv;
328*77c1e3ccSAndroid Build Coastguard Worker       tpl_frame.tpl_stats_ptr[av1_tpl_ptr_pos(row, col, tpl_frame.stride,
329*77c1e3ccSAndroid Build Coastguard Worker                                               right_shift)] = tpl_stats;
330*77c1e3ccSAndroid Build Coastguard Worker     }
331*77c1e3ccSAndroid Build Coastguard Worker   }
332*77c1e3ccSAndroid Build Coastguard Worker 
333*77c1e3ccSAndroid Build Coastguard Worker   double result = av1_tpl_compute_frame_mv_entropy(&tpl_frame, right_shift);
334*77c1e3ccSAndroid Build Coastguard Worker 
335*77c1e3ccSAndroid Build Coastguard Worker   // Expect the result to be low because the motion vectors are ordered.
336*77c1e3ccSAndroid Build Coastguard Worker   // The estimation algorithm takes this into account and reduces the cost.
337*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(result, 20, 5);
338*77c1e3ccSAndroid Build Coastguard Worker 
339*77c1e3ccSAndroid Build Coastguard Worker   index = 0;
340*77c1e3ccSAndroid Build Coastguard Worker   for (int row = 0; row < tpl_frame.mi_rows; row += step) {
341*77c1e3ccSAndroid Build Coastguard Worker     for (int col = 0; col < tpl_frame.mi_cols; col += step) {
342*77c1e3ccSAndroid Build Coastguard Worker       TplDepStats tpl_stats;
343*77c1e3ccSAndroid Build Coastguard Worker       tpl_stats.ref_frame_index[0] = 0;
344*77c1e3ccSAndroid Build Coastguard Worker       int_mv mv;
345*77c1e3ccSAndroid Build Coastguard Worker       mv.as_mv.row = mv_vals[index];
346*77c1e3ccSAndroid Build Coastguard Worker       mv.as_mv.col = mv_vals[index];
347*77c1e3ccSAndroid Build Coastguard Worker       index++;
348*77c1e3ccSAndroid Build Coastguard Worker       tpl_stats.mv[0] = mv;
349*77c1e3ccSAndroid Build Coastguard Worker       tpl_frame.tpl_stats_ptr[av1_tpl_ptr_pos(row, col, tpl_frame.stride,
350*77c1e3ccSAndroid Build Coastguard Worker                                               right_shift)] = tpl_stats;
351*77c1e3ccSAndroid Build Coastguard Worker     }
352*77c1e3ccSAndroid Build Coastguard Worker   }
353*77c1e3ccSAndroid Build Coastguard Worker 
354*77c1e3ccSAndroid Build Coastguard Worker   result = av1_tpl_compute_frame_mv_entropy(&tpl_frame, right_shift);
355*77c1e3ccSAndroid Build Coastguard Worker 
356*77c1e3ccSAndroid Build Coastguard Worker   // Expect the result to be higher because the vectors are not ordered.
357*77c1e3ccSAndroid Build Coastguard Worker   // Neighboring vectors will have different values, increasing the cost.
358*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(result, 70, 5);
359*77c1e3ccSAndroid Build Coastguard Worker }
360*77c1e3ccSAndroid Build Coastguard Worker #if CONFIG_BITRATE_ACCURACY
361*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,VbrRcInfoSetGopBitBudget)362*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, VbrRcInfoSetGopBitBudget) {
363*77c1e3ccSAndroid Build Coastguard Worker   VBR_RATECTRL_INFO vbr_rc_info;
364*77c1e3ccSAndroid Build Coastguard Worker   const double total_bit_budget = 2000;
365*77c1e3ccSAndroid Build Coastguard Worker   const int show_frame_count = 8;
366*77c1e3ccSAndroid Build Coastguard Worker   const int gop_show_frame_count = 4;
367*77c1e3ccSAndroid Build Coastguard Worker   av1_vbr_rc_init(&vbr_rc_info, total_bit_budget, show_frame_count);
368*77c1e3ccSAndroid Build Coastguard Worker   av1_vbr_rc_set_gop_bit_budget(&vbr_rc_info, gop_show_frame_count);
369*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(vbr_rc_info.gop_bit_budget, 1000, epsilon);
370*77c1e3ccSAndroid Build Coastguard Worker }
371*77c1e3ccSAndroid Build Coastguard Worker 
init_toy_gf_group(GF_GROUP * gf_group)372*77c1e3ccSAndroid Build Coastguard Worker void init_toy_gf_group(GF_GROUP *gf_group) {
373*77c1e3ccSAndroid Build Coastguard Worker   av1_zero(*gf_group);
374*77c1e3ccSAndroid Build Coastguard Worker   gf_group->size = 4;
375*77c1e3ccSAndroid Build Coastguard Worker   const FRAME_UPDATE_TYPE update_type[4] = { KF_UPDATE, ARF_UPDATE,
376*77c1e3ccSAndroid Build Coastguard Worker                                              INTNL_ARF_UPDATE, LF_UPDATE };
377*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < gf_group->size; ++i) {
378*77c1e3ccSAndroid Build Coastguard Worker     gf_group->update_type[i] = update_type[i];
379*77c1e3ccSAndroid Build Coastguard Worker   }
380*77c1e3ccSAndroid Build Coastguard Worker }
381*77c1e3ccSAndroid Build Coastguard Worker 
init_toy_vbr_rc_info(VBR_RATECTRL_INFO * vbr_rc_info,int gop_size)382*77c1e3ccSAndroid Build Coastguard Worker void init_toy_vbr_rc_info(VBR_RATECTRL_INFO *vbr_rc_info, int gop_size) {
383*77c1e3ccSAndroid Build Coastguard Worker   int total_bit_budget = 2000;
384*77c1e3ccSAndroid Build Coastguard Worker   int show_frame_count = 8;
385*77c1e3ccSAndroid Build Coastguard Worker   av1_vbr_rc_init(vbr_rc_info, total_bit_budget, show_frame_count);
386*77c1e3ccSAndroid Build Coastguard Worker 
387*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < gop_size; ++i) {
388*77c1e3ccSAndroid Build Coastguard Worker     vbr_rc_info->qstep_ratio_list[i] = 1;
389*77c1e3ccSAndroid Build Coastguard Worker   }
390*77c1e3ccSAndroid Build Coastguard Worker }
391*77c1e3ccSAndroid Build Coastguard Worker 
init_toy_tpl_txfm_stats(std::vector<TplTxfmStats> * stats_list)392*77c1e3ccSAndroid Build Coastguard Worker void init_toy_tpl_txfm_stats(std::vector<TplTxfmStats> *stats_list) {
393*77c1e3ccSAndroid Build Coastguard Worker   for (size_t i = 0; i < stats_list->size(); i++) {
394*77c1e3ccSAndroid Build Coastguard Worker     TplTxfmStats *txfm_stats = &stats_list->at(i);
395*77c1e3ccSAndroid Build Coastguard Worker     av1_init_tpl_txfm_stats(txfm_stats);
396*77c1e3ccSAndroid Build Coastguard Worker     txfm_stats->txfm_block_count = 8;
397*77c1e3ccSAndroid Build Coastguard Worker     for (int j = 0; j < txfm_stats->coeff_num; j++) {
398*77c1e3ccSAndroid Build Coastguard Worker       txfm_stats->abs_coeff_sum[j] = 1000 + j;
399*77c1e3ccSAndroid Build Coastguard Worker     }
400*77c1e3ccSAndroid Build Coastguard Worker     av1_tpl_txfm_stats_update_abs_coeff_mean(txfm_stats);
401*77c1e3ccSAndroid Build Coastguard Worker   }
402*77c1e3ccSAndroid Build Coastguard Worker }
403*77c1e3ccSAndroid Build Coastguard Worker 
404*77c1e3ccSAndroid Build Coastguard Worker /*
405*77c1e3ccSAndroid Build Coastguard Worker  * Helper method to brute-force search for the closest q_index
406*77c1e3ccSAndroid Build Coastguard Worker  * that achieves the specified bit budget.
407*77c1e3ccSAndroid Build Coastguard Worker  */
find_gop_q_iterative(double bit_budget,aom_bit_depth_t bit_depth,const double * update_type_scale_factors,int frame_count,const FRAME_UPDATE_TYPE * update_type_list,const double * qstep_ratio_list,const TplTxfmStats * stats_list,int * q_index_list,double * estimated_bitrate_byframe)408*77c1e3ccSAndroid Build Coastguard Worker int find_gop_q_iterative(double bit_budget, aom_bit_depth_t bit_depth,
409*77c1e3ccSAndroid Build Coastguard Worker                          const double *update_type_scale_factors,
410*77c1e3ccSAndroid Build Coastguard Worker                          int frame_count,
411*77c1e3ccSAndroid Build Coastguard Worker                          const FRAME_UPDATE_TYPE *update_type_list,
412*77c1e3ccSAndroid Build Coastguard Worker                          const double *qstep_ratio_list,
413*77c1e3ccSAndroid Build Coastguard Worker                          const TplTxfmStats *stats_list, int *q_index_list,
414*77c1e3ccSAndroid Build Coastguard Worker                          double *estimated_bitrate_byframe) {
415*77c1e3ccSAndroid Build Coastguard Worker   int best_q = 255;
416*77c1e3ccSAndroid Build Coastguard Worker   double curr_estimate = av1_vbr_rc_info_estimate_gop_bitrate(
417*77c1e3ccSAndroid Build Coastguard Worker       best_q, bit_depth, update_type_scale_factors, frame_count,
418*77c1e3ccSAndroid Build Coastguard Worker       update_type_list, qstep_ratio_list, stats_list, q_index_list,
419*77c1e3ccSAndroid Build Coastguard Worker       estimated_bitrate_byframe);
420*77c1e3ccSAndroid Build Coastguard Worker   double min_bits_diff = fabs(curr_estimate - bit_budget);
421*77c1e3ccSAndroid Build Coastguard Worker   // Start at q = 254 because we already have an estimate for q = 255.
422*77c1e3ccSAndroid Build Coastguard Worker   for (int q = 254; q >= 0; q--) {
423*77c1e3ccSAndroid Build Coastguard Worker     curr_estimate = av1_vbr_rc_info_estimate_gop_bitrate(
424*77c1e3ccSAndroid Build Coastguard Worker         q, bit_depth, update_type_scale_factors, frame_count, update_type_list,
425*77c1e3ccSAndroid Build Coastguard Worker         qstep_ratio_list, stats_list, q_index_list, estimated_bitrate_byframe);
426*77c1e3ccSAndroid Build Coastguard Worker     double bits_diff = fabs(curr_estimate - bit_budget);
427*77c1e3ccSAndroid Build Coastguard Worker     if (bits_diff <= min_bits_diff) {
428*77c1e3ccSAndroid Build Coastguard Worker       min_bits_diff = bits_diff;
429*77c1e3ccSAndroid Build Coastguard Worker       best_q = q;
430*77c1e3ccSAndroid Build Coastguard Worker     }
431*77c1e3ccSAndroid Build Coastguard Worker   }
432*77c1e3ccSAndroid Build Coastguard Worker   return best_q;
433*77c1e3ccSAndroid Build Coastguard Worker }
434*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,EstimateFrameRateTest)435*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, EstimateFrameRateTest) {
436*77c1e3ccSAndroid Build Coastguard Worker   GF_GROUP gf_group;
437*77c1e3ccSAndroid Build Coastguard Worker   init_toy_gf_group(&gf_group);
438*77c1e3ccSAndroid Build Coastguard Worker 
439*77c1e3ccSAndroid Build Coastguard Worker   VBR_RATECTRL_INFO vbr_rc_info;
440*77c1e3ccSAndroid Build Coastguard Worker   init_toy_vbr_rc_info(&vbr_rc_info, gf_group.size);
441*77c1e3ccSAndroid Build Coastguard Worker 
442*77c1e3ccSAndroid Build Coastguard Worker   std::vector<TplTxfmStats> stats_list(gf_group.size);
443*77c1e3ccSAndroid Build Coastguard Worker   init_toy_tpl_txfm_stats(&stats_list);
444*77c1e3ccSAndroid Build Coastguard Worker 
445*77c1e3ccSAndroid Build Coastguard Worker   std::vector<double> est_bitrate_list(gf_group.size);
446*77c1e3ccSAndroid Build Coastguard Worker   init_toy_tpl_txfm_stats(&stats_list);
447*77c1e3ccSAndroid Build Coastguard Worker   const aom_bit_depth_t bit_depth = AOM_BITS_8;
448*77c1e3ccSAndroid Build Coastguard Worker 
449*77c1e3ccSAndroid Build Coastguard Worker   const int q = 125;
450*77c1e3ccSAndroid Build Coastguard Worker 
451*77c1e3ccSAndroid Build Coastguard Worker   // Case1: all scale factors are 0
452*77c1e3ccSAndroid Build Coastguard Worker   double scale_factors[FRAME_UPDATE_TYPES] = { 0 };
453*77c1e3ccSAndroid Build Coastguard Worker   double estimate = av1_vbr_rc_info_estimate_gop_bitrate(
454*77c1e3ccSAndroid Build Coastguard Worker       q, bit_depth, scale_factors, gf_group.size, gf_group.update_type,
455*77c1e3ccSAndroid Build Coastguard Worker       vbr_rc_info.qstep_ratio_list, stats_list.data(), vbr_rc_info.q_index_list,
456*77c1e3ccSAndroid Build Coastguard Worker       est_bitrate_list.data());
457*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(estimate, 0, epsilon);
458*77c1e3ccSAndroid Build Coastguard Worker 
459*77c1e3ccSAndroid Build Coastguard Worker   // Case2: all scale factors are 1
460*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < FRAME_UPDATE_TYPES; i++) {
461*77c1e3ccSAndroid Build Coastguard Worker     scale_factors[i] = 1;
462*77c1e3ccSAndroid Build Coastguard Worker   }
463*77c1e3ccSAndroid Build Coastguard Worker   estimate = av1_vbr_rc_info_estimate_gop_bitrate(
464*77c1e3ccSAndroid Build Coastguard Worker       q, bit_depth, scale_factors, gf_group.size, gf_group.update_type,
465*77c1e3ccSAndroid Build Coastguard Worker       vbr_rc_info.qstep_ratio_list, stats_list.data(), vbr_rc_info.q_index_list,
466*77c1e3ccSAndroid Build Coastguard Worker       est_bitrate_list.data());
467*77c1e3ccSAndroid Build Coastguard Worker   double ref_estimate = 0;
468*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < gf_group.size; i++) {
469*77c1e3ccSAndroid Build Coastguard Worker     ref_estimate += est_bitrate_list[i];
470*77c1e3ccSAndroid Build Coastguard Worker   }
471*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(estimate, ref_estimate, epsilon);
472*77c1e3ccSAndroid Build Coastguard Worker 
473*77c1e3ccSAndroid Build Coastguard Worker   // Case3: Key frame scale factor is 0 and others are 1
474*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < FRAME_UPDATE_TYPES; i++) {
475*77c1e3ccSAndroid Build Coastguard Worker     if (i == KF_UPDATE) {
476*77c1e3ccSAndroid Build Coastguard Worker       scale_factors[i] = 0;
477*77c1e3ccSAndroid Build Coastguard Worker     } else {
478*77c1e3ccSAndroid Build Coastguard Worker       scale_factors[i] = 1;
479*77c1e3ccSAndroid Build Coastguard Worker     }
480*77c1e3ccSAndroid Build Coastguard Worker   }
481*77c1e3ccSAndroid Build Coastguard Worker   estimate = av1_vbr_rc_info_estimate_gop_bitrate(
482*77c1e3ccSAndroid Build Coastguard Worker       q, bit_depth, scale_factors, gf_group.size, gf_group.update_type,
483*77c1e3ccSAndroid Build Coastguard Worker       vbr_rc_info.qstep_ratio_list, stats_list.data(), vbr_rc_info.q_index_list,
484*77c1e3ccSAndroid Build Coastguard Worker       est_bitrate_list.data());
485*77c1e3ccSAndroid Build Coastguard Worker   ref_estimate = 0;
486*77c1e3ccSAndroid Build Coastguard Worker   for (int i = 0; i < gf_group.size; i++) {
487*77c1e3ccSAndroid Build Coastguard Worker     if (gf_group.update_type[i] != KF_UPDATE) {
488*77c1e3ccSAndroid Build Coastguard Worker       ref_estimate += est_bitrate_list[i];
489*77c1e3ccSAndroid Build Coastguard Worker     }
490*77c1e3ccSAndroid Build Coastguard Worker   }
491*77c1e3ccSAndroid Build Coastguard Worker   EXPECT_NEAR(estimate, ref_estimate, epsilon);
492*77c1e3ccSAndroid Build Coastguard Worker }
493*77c1e3ccSAndroid Build Coastguard Worker 
TEST(TplModelTest,VbrRcInfoEstimateBaseQTest)494*77c1e3ccSAndroid Build Coastguard Worker TEST(TplModelTest, VbrRcInfoEstimateBaseQTest) {
495*77c1e3ccSAndroid Build Coastguard Worker   GF_GROUP gf_group;
496*77c1e3ccSAndroid Build Coastguard Worker   init_toy_gf_group(&gf_group);
497*77c1e3ccSAndroid Build Coastguard Worker 
498*77c1e3ccSAndroid Build Coastguard Worker   VBR_RATECTRL_INFO vbr_rc_info;
499*77c1e3ccSAndroid Build Coastguard Worker   init_toy_vbr_rc_info(&vbr_rc_info, gf_group.size);
500*77c1e3ccSAndroid Build Coastguard Worker 
501*77c1e3ccSAndroid Build Coastguard Worker   std::vector<TplTxfmStats> stats_list(gf_group.size);
502*77c1e3ccSAndroid Build Coastguard Worker   init_toy_tpl_txfm_stats(&stats_list);
503*77c1e3ccSAndroid Build Coastguard Worker   const aom_bit_depth_t bit_depth = AOM_BITS_8;
504*77c1e3ccSAndroid Build Coastguard Worker 
505*77c1e3ccSAndroid Build Coastguard Worker   // Test multiple bit budgets.
506*77c1e3ccSAndroid Build Coastguard Worker   const std::vector<double> bit_budgets = { 0,     2470,  19200,  30750,
507*77c1e3ccSAndroid Build Coastguard Worker                                             41315, 65017, DBL_MAX };
508*77c1e3ccSAndroid Build Coastguard Worker 
509*77c1e3ccSAndroid Build Coastguard Worker   for (double bit_budget : bit_budgets) {
510*77c1e3ccSAndroid Build Coastguard Worker     // Binary search method to find the optimal q.
511*77c1e3ccSAndroid Build Coastguard Worker     const int base_q = av1_vbr_rc_info_estimate_base_q(
512*77c1e3ccSAndroid Build Coastguard Worker         bit_budget, bit_depth, vbr_rc_info.scale_factors, gf_group.size,
513*77c1e3ccSAndroid Build Coastguard Worker         gf_group.update_type, vbr_rc_info.qstep_ratio_list, stats_list.data(),
514*77c1e3ccSAndroid Build Coastguard Worker         vbr_rc_info.q_index_list, nullptr);
515*77c1e3ccSAndroid Build Coastguard Worker     const int ref_base_q = find_gop_q_iterative(
516*77c1e3ccSAndroid Build Coastguard Worker         bit_budget, bit_depth, vbr_rc_info.scale_factors, gf_group.size,
517*77c1e3ccSAndroid Build Coastguard Worker         gf_group.update_type, vbr_rc_info.qstep_ratio_list, stats_list.data(),
518*77c1e3ccSAndroid Build Coastguard Worker         vbr_rc_info.q_index_list, nullptr);
519*77c1e3ccSAndroid Build Coastguard Worker     if (bit_budget == 0) {
520*77c1e3ccSAndroid Build Coastguard Worker       EXPECT_EQ(base_q, 255);
521*77c1e3ccSAndroid Build Coastguard Worker     } else if (bit_budget == DBL_MAX) {
522*77c1e3ccSAndroid Build Coastguard Worker       EXPECT_EQ(base_q, 0);
523*77c1e3ccSAndroid Build Coastguard Worker     }
524*77c1e3ccSAndroid Build Coastguard Worker     EXPECT_EQ(base_q, ref_base_q);
525*77c1e3ccSAndroid Build Coastguard Worker   }
526*77c1e3ccSAndroid Build Coastguard Worker }
527*77c1e3ccSAndroid Build Coastguard Worker #endif  // CONFIG_BITRATE_ACCURACY
528*77c1e3ccSAndroid Build Coastguard Worker 
529*77c1e3ccSAndroid Build Coastguard Worker }  // namespace
530