• 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 <vector>
14 
15 #include "av1/encoder/cost.h"
16 #include "av1/encoder/tpl_model.h"
17 #include "av1/encoder/encoder.h"
18 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
19 
20 namespace {
21 
laplace_prob(double q_step,double b,double zero_bin_ratio,int qcoeff)22 double laplace_prob(double q_step, double b, double zero_bin_ratio,
23                     int qcoeff) {
24   int abs_qcoeff = abs(qcoeff);
25   double z0 = fmax(exp(-zero_bin_ratio / 2 * q_step / b), TPL_EPSILON);
26   if (abs_qcoeff == 0) {
27     double p0 = 1 - z0;
28     return p0;
29   } else {
30     assert(abs_qcoeff > 0);
31     double z = fmax(exp(-q_step / b), TPL_EPSILON);
32     double p = z0 / 2 * (1 - z) * pow(z, abs_qcoeff - 1);
33     return p;
34   }
35 }
TEST(TplModelTest,ExponentialEntropyBoundaryTest1)36 TEST(TplModelTest, ExponentialEntropyBoundaryTest1) {
37   double b = 0;
38   double q_step = 1;
39   double entropy = av1_exponential_entropy(q_step, b);
40   EXPECT_NEAR(entropy, 0, 0.00001);
41 }
42 
TEST(TplModelTest,TransformCoeffEntropyTest1)43 TEST(TplModelTest, TransformCoeffEntropyTest1) {
44   // Check the consistency between av1_estimate_coeff_entropy() and
45   // laplace_prob()
46   double b = 1;
47   double q_step = 1;
48   double zero_bin_ratio = 2;
49   for (int qcoeff = -256; qcoeff < 256; ++qcoeff) {
50     double rate = av1_estimate_coeff_entropy(q_step, b, zero_bin_ratio, qcoeff);
51     double prob = laplace_prob(q_step, b, zero_bin_ratio, qcoeff);
52     double ref_rate = -log2(prob);
53     EXPECT_DOUBLE_EQ(rate, ref_rate);
54   }
55 }
56 
TEST(TplModelTest,TransformCoeffEntropyTest2)57 TEST(TplModelTest, TransformCoeffEntropyTest2) {
58   // Check the consistency between av1_estimate_coeff_entropy(), laplace_prob()
59   // and av1_laplace_entropy()
60   double b = 1;
61   double q_step = 1;
62   double zero_bin_ratio = 2;
63   double est_expected_rate = 0;
64   for (int qcoeff = -20; qcoeff < 20; ++qcoeff) {
65     double rate = av1_estimate_coeff_entropy(q_step, b, zero_bin_ratio, qcoeff);
66     double prob = laplace_prob(q_step, b, zero_bin_ratio, qcoeff);
67     est_expected_rate += prob * rate;
68   }
69   double expected_rate = av1_laplace_entropy(q_step, b, zero_bin_ratio);
70   EXPECT_NEAR(expected_rate, est_expected_rate, 0.001);
71 }
72 
TEST(TplModelTest,DeltaRateCostZeroFlow)73 TEST(TplModelTest, DeltaRateCostZeroFlow) {
74   // When srcrf_dist equal to recrf_dist, av1_delta_rate_cost should return 0
75   int64_t srcrf_dist = 256;
76   int64_t recrf_dist = 256;
77   int64_t delta_rate = 512;
78   int pixel_num = 256;
79   int64_t rate_cost =
80       av1_delta_rate_cost(delta_rate, recrf_dist, srcrf_dist, pixel_num);
81   EXPECT_EQ(rate_cost, 0);
82 }
83 
84 // a reference function of av1_delta_rate_cost() with delta_rate using bit as
85 // basic unit
ref_delta_rate_cost(int64_t delta_rate,double src_rec_ratio,int pixel_count)86 double ref_delta_rate_cost(int64_t delta_rate, double src_rec_ratio,
87                            int pixel_count) {
88   assert(src_rec_ratio <= 1 && src_rec_ratio >= 0);
89   double bits_per_pixel = (double)delta_rate / pixel_count;
90   double p = pow(2, bits_per_pixel);
91   double flow_rate_per_pixel =
92       sqrt(p * p / (src_rec_ratio * p * p + (1 - src_rec_ratio)));
93   double rate_cost = pixel_count * log2(flow_rate_per_pixel);
94   return rate_cost;
95 }
96 
TEST(TplModelTest,DeltaRateCostReference)97 TEST(TplModelTest, DeltaRateCostReference) {
98   const int64_t scale = TPL_DEP_COST_SCALE_LOG2 + AV1_PROB_COST_SHIFT;
99   std::vector<int64_t> srcrf_dist_arr = { 256, 257, 312 };
100   std::vector<int64_t> recrf_dist_arr = { 512, 288, 620 };
101   std::vector<int64_t> delta_rate_arr = { 10, 278, 100 };
102   for (size_t t = 0; t < srcrf_dist_arr.size(); ++t) {
103     int64_t srcrf_dist = srcrf_dist_arr[t];
104     int64_t recrf_dist = recrf_dist_arr[t];
105     int64_t delta_rate = delta_rate_arr[t];
106     int64_t scaled_delta_rate = delta_rate << scale;
107     int pixel_count = 256;
108     int64_t rate_cost = av1_delta_rate_cost(scaled_delta_rate, recrf_dist,
109                                             srcrf_dist, pixel_count);
110     rate_cost >>= scale;
111     double src_rec_ratio = (double)srcrf_dist / recrf_dist;
112     double ref_rate_cost =
113         ref_delta_rate_cost(delta_rate, src_rec_ratio, pixel_count);
114     EXPECT_NEAR((double)rate_cost, ref_rate_cost, 1);
115   }
116 }
117 
TEST(TplModelTest,GetOverlapAreaHasOverlap)118 TEST(TplModelTest, GetOverlapAreaHasOverlap) {
119   // The block a's area is [10, 17) x [18, 24).
120   // The block b's area is [8, 15) x [17, 23).
121   // The overlapping area between block a and block b is [10, 15) x [18, 23).
122   // Therefore, the size of the area is (15 - 10) * (23 - 18) = 25.
123   int row_a = 10;
124   int col_a = 18;
125   int row_b = 8;
126   int col_b = 17;
127   int height = 7;
128   int width = 6;
129   int overlap_area =
130       av1_get_overlap_area(row_a, col_a, row_b, col_b, width, height);
131   EXPECT_EQ(overlap_area, 25);
132 }
133 
TEST(TplModelTest,GetOverlapAreaNoOverlap)134 TEST(TplModelTest, GetOverlapAreaNoOverlap) {
135   // The block a's area is [10, 14) x [18, 22).
136   // The block b's area is [5, 9) x [5, 9).
137   // Threre is no overlapping area between block a and block b.
138   // Therefore, the return value should be zero.
139   int row_a = 10;
140   int col_a = 18;
141   int row_b = 5;
142   int col_b = 5;
143   int height = 4;
144   int width = 4;
145   int overlap_area =
146       av1_get_overlap_area(row_a, col_a, row_b, col_b, width, height);
147   EXPECT_EQ(overlap_area, 0);
148 }
149 
TEST(TPLModelTest,EstimateFrameRateTest)150 TEST(TPLModelTest, EstimateFrameRateTest) {
151   /*
152    * Transform size: 16x16
153    * Frame count: 16
154    * Transform block count: 20
155    */
156   const int txfm_size = 256;  // 16x16
157   const int frame_count = 16;
158   int q_index_list[16];
159   int valid_list[16];
160   TplTxfmStats stats_list[16];
161 
162   for (int i = 0; i < frame_count; i++) {
163     q_index_list[i] = 1;
164     valid_list[i] = 1;
165     stats_list[i].txfm_block_count = 8;
166 
167     for (int j = 0; j < txfm_size; j++) {
168       stats_list[i].abs_coeff_sum[j] = 0;
169     }
170   }
171 
172   double result = av1_estimate_gop_bitrate(q_index_list, frame_count,
173                                            stats_list, valid_list, NULL);
174   EXPECT_NEAR(result, 0, 0.1);
175 }
176 
TEST(TPLModelTest,TxfmStatsInitTest)177 TEST(TPLModelTest, TxfmStatsInitTest) {
178   TplTxfmStats tpl_txfm_stats;
179   av1_init_tpl_txfm_stats(&tpl_txfm_stats);
180   EXPECT_EQ(tpl_txfm_stats.coeff_num, 256);
181   EXPECT_EQ(tpl_txfm_stats.txfm_block_count, 0);
182   for (int i = 0; i < tpl_txfm_stats.coeff_num; ++i) {
183     EXPECT_DOUBLE_EQ(tpl_txfm_stats.abs_coeff_sum[i], 0);
184   }
185 }
186 
TEST(TPLModelTest,TxfmStatsAccumulateTest)187 TEST(TPLModelTest, TxfmStatsAccumulateTest) {
188   TplTxfmStats sub_stats;
189   av1_init_tpl_txfm_stats(&sub_stats);
190   sub_stats.txfm_block_count = 17;
191   for (int i = 0; i < sub_stats.coeff_num; ++i) {
192     sub_stats.abs_coeff_sum[i] = i;
193   }
194 
195   TplTxfmStats accumulated_stats;
196   av1_init_tpl_txfm_stats(&accumulated_stats);
197   accumulated_stats.txfm_block_count = 13;
198   for (int i = 0; i < accumulated_stats.coeff_num; ++i) {
199     accumulated_stats.abs_coeff_sum[i] = 5 * i;
200   }
201 
202   av1_accumulate_tpl_txfm_stats(&sub_stats, &accumulated_stats);
203   EXPECT_DOUBLE_EQ(accumulated_stats.txfm_block_count, 30);
204   for (int i = 0; i < accumulated_stats.coeff_num; ++i) {
205     EXPECT_DOUBLE_EQ(accumulated_stats.abs_coeff_sum[i], 6 * i);
206   }
207 }
208 
TEST(TPLModelTest,TxfmStatsRecordTest)209 TEST(TPLModelTest, TxfmStatsRecordTest) {
210   TplTxfmStats stats1;
211   TplTxfmStats stats2;
212   av1_init_tpl_txfm_stats(&stats1);
213   av1_init_tpl_txfm_stats(&stats2);
214 
215   tran_low_t coeff[256];
216   for (int i = 0; i < 256; ++i) {
217     coeff[i] = i;
218   }
219   av1_record_tpl_txfm_block(&stats1, coeff);
220   EXPECT_EQ(stats1.txfm_block_count, 1);
221 
222   // we record the same transform block twice for testing purpose
223   av1_record_tpl_txfm_block(&stats2, coeff);
224   av1_record_tpl_txfm_block(&stats2, coeff);
225   EXPECT_EQ(stats2.txfm_block_count, 2);
226 
227   EXPECT_EQ(stats1.coeff_num, 256);
228   EXPECT_EQ(stats2.coeff_num, 256);
229   for (int i = 0; i < 256; ++i) {
230     EXPECT_DOUBLE_EQ(stats2.abs_coeff_sum[i], 2 * stats1.abs_coeff_sum[i]);
231   }
232 }
233 
234 /*
235  * Helper method to brute-force search for the closest q_index
236  * that achieves the specified bit budget.
237  */
find_gop_q_iterative(double bit_budget,double arf_qstep_ratio,GF_GROUP gf_group,const int * stats_valid_list,TplTxfmStats * stats_list,int gf_frame_index,aom_bit_depth_t bit_depth)238 int find_gop_q_iterative(double bit_budget, double arf_qstep_ratio,
239                          GF_GROUP gf_group, const int *stats_valid_list,
240                          TplTxfmStats *stats_list, int gf_frame_index,
241                          aom_bit_depth_t bit_depth) {
242   // Brute force iterative method to find the optimal q.
243   // Use the result to test against the binary search result.
244 
245   // Initial estimate when q = 255
246   av1_q_mode_compute_gop_q_indices(gf_frame_index, 255, arf_qstep_ratio,
247                                    bit_depth, &gf_group, gf_group.q_val);
248   double curr_estimate = av1_estimate_gop_bitrate(
249       gf_group.q_val, gf_group.size, stats_list, stats_valid_list, NULL);
250   double best_estimate_budget_distance = fabs(curr_estimate - bit_budget);
251   int best_q = 255;
252 
253   // Start at q = 254 because we already have an estimate for q = 255.
254   for (int q = 254; q >= 0; q--) {
255     av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
256                                      bit_depth, &gf_group, gf_group.q_val);
257     curr_estimate = av1_estimate_gop_bitrate(
258         gf_group.q_val, gf_group.size, stats_list, stats_valid_list, NULL);
259     double curr_estimate_budget_distance = fabs(curr_estimate - bit_budget);
260     if (curr_estimate_budget_distance <= best_estimate_budget_distance) {
261       best_estimate_budget_distance = curr_estimate_budget_distance;
262       best_q = q;
263     }
264   }
265   return best_q;
266 }
267 
TEST(TplModelTest,QModeEstimateBaseQTest)268 TEST(TplModelTest, QModeEstimateBaseQTest) {
269   GF_GROUP gf_group = {};
270   gf_group.size = 25;
271   TplTxfmStats stats_list[25];
272   int q_index_list[25];
273   const int gf_group_update_types[25] = { 0, 3, 6, 6, 6, 1, 5, 1, 5, 6, 1, 5, 1,
274                                           5, 6, 6, 1, 5, 1, 5, 6, 1, 5, 1, 4 };
275   int stats_valid_list[25] = { 0 };
276   const int gf_frame_index = 0;
277   const double arf_qstep_ratio = 2;
278   const aom_bit_depth_t bit_depth = AOM_BITS_8;
279   const double scale_factor = 1.0;
280 
281   for (int i = 0; i < gf_group.size; i++) {
282     stats_valid_list[i] = 1;
283     gf_group.update_type[i] = gf_group_update_types[i];
284     stats_list[i].txfm_block_count = 8;
285 
286     for (int j = 0; j < 256; j++) {
287       stats_list[i].abs_coeff_sum[j] = 1000 + j;
288     }
289   }
290 
291   // Test multiple bit budgets.
292   const std::vector<double> bit_budgets = { 0,      100,    1000,   10000,
293                                             100000, 300000, 500000, 750000,
294                                             800000, DBL_MAX };
295 
296   for (double bit_budget : bit_budgets) {
297     // Binary search method to find the optimal q.
298     const int result = av1_q_mode_estimate_base_q(
299         &gf_group, stats_list, stats_valid_list, bit_budget, gf_frame_index,
300         arf_qstep_ratio, bit_depth, scale_factor, q_index_list, NULL);
301     const int test_result = find_gop_q_iterative(
302         bit_budget, arf_qstep_ratio, gf_group, stats_valid_list, stats_list,
303         gf_frame_index, bit_depth);
304 
305     if (bit_budget == 0) {
306       EXPECT_EQ(result, 255);
307     } else if (bit_budget == DBL_MAX) {
308       EXPECT_EQ(result, 0);
309     }
310 
311     EXPECT_EQ(result, test_result);
312   }
313 }
314 
TEST(TplModelTest,ComputeMVDifferenceTest)315 TEST(TplModelTest, ComputeMVDifferenceTest) {
316   TplDepFrame tpl_frame_small;
317   tpl_frame_small.is_valid = true;
318   tpl_frame_small.mi_rows = 4;
319   tpl_frame_small.mi_cols = 4;
320   tpl_frame_small.stride = 1;
321   uint8_t right_shift_small = 1;
322   int step_small = 1 << right_shift_small;
323 
324   // Test values for motion vectors.
325   int mv_vals_small[4] = { 1, 2, 3, 4 };
326   int index = 0;
327 
328   // 4x4 blocks means we need to allocate a 4 size array.
329   // According to av1_tpl_ptr_pos:
330   // (row >> right_shift) * stride + (col >> right_shift)
331   // (4 >> 1) * 1 + (4 >> 1) = 4
332   TplDepStats stats_buf_small[4];
333   tpl_frame_small.tpl_stats_ptr = stats_buf_small;
334 
335   for (int row = 0; row < tpl_frame_small.mi_rows; row += step_small) {
336     for (int col = 0; col < tpl_frame_small.mi_cols; col += step_small) {
337       TplDepStats tpl_stats;
338       tpl_stats.ref_frame_index[0] = 0;
339       int_mv mv;
340       mv.as_mv.row = mv_vals_small[index];
341       mv.as_mv.col = mv_vals_small[index];
342       index++;
343       tpl_stats.mv[0] = mv;
344       tpl_frame_small.tpl_stats_ptr[av1_tpl_ptr_pos(
345           row, col, tpl_frame_small.stride, right_shift_small)] = tpl_stats;
346     }
347   }
348 
349   int_mv result_mv =
350       av1_compute_mv_difference(&tpl_frame_small, 1, 1, step_small,
351                                 tpl_frame_small.stride, right_shift_small);
352 
353   // Expect the result to be exactly equal to 1 because this is the difference
354   // between neighboring motion vectors in this instance.
355   EXPECT_EQ(result_mv.as_mv.row, 1);
356   EXPECT_EQ(result_mv.as_mv.col, 1);
357 }
358 
TEST(TplModelTest,ComputeMVBitsTest)359 TEST(TplModelTest, ComputeMVBitsTest) {
360   TplDepFrame tpl_frame;
361   tpl_frame.is_valid = true;
362   tpl_frame.mi_rows = 16;
363   tpl_frame.mi_cols = 16;
364   tpl_frame.stride = 24;
365   uint8_t right_shift = 2;
366   int step = 1 << right_shift;
367   // Test values for motion vectors.
368   int mv_vals_ordered[16] = { 1, 2,  3,  4,  5,  6,  7,  8,
369                               9, 10, 11, 12, 13, 14, 15, 16 };
370   int mv_vals[16] = { 1, 16, 2, 15, 3, 14, 4, 13, 5, 12, 6, 11, 7, 10, 8, 9 };
371   int index = 0;
372 
373   // 16x16 blocks means we need to allocate a 100 size array.
374   // According to av1_tpl_ptr_pos:
375   // (row >> right_shift) * stride + (col >> right_shift)
376   // (16 >> 2) * 24 + (16 >> 2) = 100
377   TplDepStats stats_buf[100];
378   tpl_frame.tpl_stats_ptr = stats_buf;
379 
380   for (int row = 0; row < tpl_frame.mi_rows; row += step) {
381     for (int col = 0; col < tpl_frame.mi_cols; col += step) {
382       TplDepStats tpl_stats;
383       tpl_stats.ref_frame_index[0] = 0;
384       int_mv mv;
385       mv.as_mv.row = mv_vals_ordered[index];
386       mv.as_mv.col = mv_vals_ordered[index];
387       index++;
388       tpl_stats.mv[0] = mv;
389       tpl_frame.tpl_stats_ptr[av1_tpl_ptr_pos(row, col, tpl_frame.stride,
390                                               right_shift)] = tpl_stats;
391     }
392   }
393 
394   double result = av1_tpl_compute_frame_mv_entropy(&tpl_frame, right_shift);
395 
396   // Expect the result to be low because the motion vectors are ordered.
397   // The estimation algorithm takes this into account and reduces the cost.
398   EXPECT_NEAR(result, 20, 5);
399 
400   index = 0;
401   for (int row = 0; row < tpl_frame.mi_rows; row += step) {
402     for (int col = 0; col < tpl_frame.mi_cols; col += step) {
403       TplDepStats tpl_stats;
404       tpl_stats.ref_frame_index[0] = 0;
405       int_mv mv;
406       mv.as_mv.row = mv_vals[index];
407       mv.as_mv.col = mv_vals[index];
408       index++;
409       tpl_stats.mv[0] = mv;
410       tpl_frame.tpl_stats_ptr[av1_tpl_ptr_pos(row, col, tpl_frame.stride,
411                                               right_shift)] = tpl_stats;
412     }
413   }
414 
415   result = av1_tpl_compute_frame_mv_entropy(&tpl_frame, right_shift);
416 
417   // Expect the result to be higher because the vectors are not ordered.
418   // Neighboring vectors will have different values, increasing the cost.
419   EXPECT_NEAR(result, 70, 5);
420 }
421 
422 }  // namespace
423