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