xref: /aosp_15_r20/external/libaom/test/encodemb_test.cc (revision 77c1e3ccc04c968bd2bc212e87364f250e820521)
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 <stdint.h>
13 #include <vector>
14 
15 #include "gtest/gtest.h"
16 
17 #include "av1/encoder/block.h"
18 #include "av1/encoder/encodemb.h"
19 #include "av1/common/scan.h"
20 
21 namespace {
22 
23 // Reorders 'qcoeff_lexico', which is in lexicographic order (row by row), into
24 // scan order (zigzag) in 'qcoeff_scan'.
ToScanOrder(TX_SIZE tx_size,TX_TYPE tx_type,tran_low_t * qcoeff_lexico,tran_low_t * qcoeff_scan)25 void ToScanOrder(TX_SIZE tx_size, TX_TYPE tx_type, tran_low_t *qcoeff_lexico,
26                  tran_low_t *qcoeff_scan) {
27   const int max_eob = av1_get_max_eob(tx_size);
28   const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type);
29   for (int i = 0; i < max_eob; ++i) {
30     qcoeff_scan[i] = qcoeff_lexico[scan_order->scan[i]];
31   }
32 }
33 
34 // Reorders 'qcoeff_scan', which is in scan order (zigzag), into lexicographic
35 // order (row by row) in 'qcoeff_lexico'.
ToLexicoOrder(TX_SIZE tx_size,TX_TYPE tx_type,tran_low_t * qcoeff_scan,tran_low_t * qcoeff_lexico)36 void ToLexicoOrder(TX_SIZE tx_size, TX_TYPE tx_type, tran_low_t *qcoeff_scan,
37                    tran_low_t *qcoeff_lexico) {
38   const int max_eob = av1_get_max_eob(tx_size);
39   const SCAN_ORDER *const scan_order = get_scan(tx_size, tx_type);
40   for (int i = 0; i < max_eob; ++i) {
41     qcoeff_lexico[scan_order->scan[i]] = qcoeff_scan[i];
42   }
43 }
44 
45 // Runs coefficient dropout on 'qcoeff_scan'.
Dropout(TX_SIZE tx_size,TX_TYPE tx_type,int dropout_num_before,int dropout_num_after,tran_low_t * qcoeff_scan)46 void Dropout(TX_SIZE tx_size, TX_TYPE tx_type, int dropout_num_before,
47              int dropout_num_after, tran_low_t *qcoeff_scan) {
48   tran_low_t qcoeff[MAX_TX_SQUARE];
49   // qcoeff_scan is assumed to be in scan order, since tests are easier to
50   // understand this way, but av1_dropout_qcoeff expects coeffs in lexico order
51   // so we convert to lexico then back to scan afterwards.
52   ToLexicoOrder(tx_size, tx_type, qcoeff_scan, qcoeff);
53 
54   const int max_eob = av1_get_max_eob(tx_size);
55   const int kDequantFactor = 10;
56   tran_low_t dqcoeff[MAX_TX_SQUARE];
57   for (int i = 0; i < max_eob; ++i) {
58     dqcoeff[i] = qcoeff[i] * kDequantFactor;
59   }
60 
61   uint16_t eob = max_eob;
62   while (eob > 0 && qcoeff_scan[eob - 1] == 0) --eob;
63 
64   MACROBLOCK mb;
65   const int kPlane = 0;
66   const int kBlock = 0;
67   memset(&mb, 0, sizeof(mb));
68   uint16_t eobs[] = { eob };
69   mb.plane[kPlane].eobs = eobs;
70   mb.plane[kPlane].qcoeff = qcoeff;
71   mb.plane[kPlane].dqcoeff = dqcoeff;
72   uint8_t txb_entropy_ctx[1];
73   mb.plane[kPlane].txb_entropy_ctx = txb_entropy_ctx;
74 
75   av1_dropout_qcoeff_num(&mb, kPlane, kBlock, tx_size, tx_type,
76                          dropout_num_before, dropout_num_after);
77 
78   ToScanOrder(tx_size, tx_type, qcoeff, qcoeff_scan);
79 
80   // Check updated eob value is valid.
81   uint16_t new_eob = max_eob;
82   while (new_eob > 0 && qcoeff_scan[new_eob - 1] == 0) --new_eob;
83   EXPECT_EQ(new_eob, mb.plane[kPlane].eobs[0]);
84 
85   // Check dqcoeff is still valid.
86   for (int i = 0; i < max_eob; ++i) {
87     EXPECT_EQ(qcoeff[i] * kDequantFactor, dqcoeff[i]);
88   }
89 }
90 
ExpectArrayEq(tran_low_t * actual,std::vector<tran_low_t> expected)91 void ExpectArrayEq(tran_low_t *actual, std::vector<tran_low_t> expected) {
92   for (size_t i = 0; i < expected.size(); ++i) {
93     EXPECT_EQ(expected[i], actual[i]) << "Arrays differ at index " << i;
94   }
95 }
96 
97 static constexpr TX_TYPE kTxType = DCT_DCT;
98 
TEST(DropoutTest,KeepsLargeCoeffs)99 TEST(DropoutTest, KeepsLargeCoeffs) {
100   const TX_SIZE tx_size = TX_8X4;
101   const uint32_t dropout_num_before = 4;
102   const uint32_t dropout_num_after = 6;
103   // Large isolated coeffs should be preserved.
104   tran_low_t qcoeff_scan[] = { 0, 0, 0, 0, 0, 0, 42, 0,    // should be kept
105                                0, 0, 0, 0, 0, 0, 0,  0,    //
106                                0, 0, 0, 0, 0, 0, 0,  -30,  // should be kept
107                                0, 0, 0, 0, 0, 0, 0,  0 };
108   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after, qcoeff_scan);
109   ExpectArrayEq(qcoeff_scan, { 0, 0, 0, 0, 0, 0, 42, 0,    //
110                                0, 0, 0, 0, 0, 0, 0,  0,    //
111                                0, 0, 0, 0, 0, 0, 0,  -30,  //
112                                0, 0, 0, 0, 0, 0, 0,  0 });
113 }
114 
TEST(DropoutTest,RemovesSmallIsolatedCoeffs)115 TEST(DropoutTest, RemovesSmallIsolatedCoeffs) {
116   const TX_SIZE tx_size = TX_8X4;
117   const uint32_t dropout_num_before = 4;
118   const uint32_t dropout_num_after = 6;
119   // Small isolated coeffs should be removed.
120   tran_low_t qcoeff_scan[] = { 0, 0, 0, 0, 1,  0, 0, 0,  // should be removed
121                                0, 0, 0, 0, 0,  0, 0, 0,  //
122                                0, 0, 0, 0, -2, 0, 0, 0,  // should be removed
123                                0, 0, 0, 0, 0,  0, 0, 0 };
124   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after, qcoeff_scan);
125   ExpectArrayEq(qcoeff_scan, { 0, 0, 0, 0, 0, 0, 0, 0,  //
126                                0, 0, 0, 0, 0, 0, 0, 0,  //
127                                0, 0, 0, 0, 0, 0, 0, 0,  //
128                                0, 0, 0, 0, 0, 0, 0, 0 });
129 }
130 
TEST(DropoutTest,KeepsSmallCoeffsAmongLargeOnes)131 TEST(DropoutTest, KeepsSmallCoeffsAmongLargeOnes) {
132   const TX_SIZE tx_size = TX_8X4;
133   const uint32_t dropout_num_before = 4;
134   const uint32_t dropout_num_after = 6;
135   // Small coeffs that are not isolated (not enough zeros before/after should be
136   // kept).
137   tran_low_t qcoeff_scan[] = {
138     1, 0,  0, 0,  -5, 0, 0, -1,  // should be kept
139     0, 0,  0, 10, 0,  0, 2, 0,   // should be kept
140     0, 0,  0, 0,  0,  0, 0, 0,   //
141     0, -2, 0, 0,  0,  0, 0, 0    // should be removed
142   };                             // should be removed
143   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after, qcoeff_scan);
144   ExpectArrayEq(qcoeff_scan, { 1, 0, 0, 0,  -5, 0, 0, -1,  //
145                                0, 0, 0, 10, 0,  0, 2, 0,   //
146                                0, 0, 0, 0,  0,  0, 0, 0,   //
147                                0, 0, 0, 0,  0,  0, 0, 0 });
148 }
149 
TEST(DropoutTest,KeepsSmallCoeffsCloseToStartOrEnd)150 TEST(DropoutTest, KeepsSmallCoeffsCloseToStartOrEnd) {
151   const TX_SIZE tx_size = TX_8X4;
152   const uint32_t dropout_num_before = 4;
153   const uint32_t dropout_num_after = 6;
154   // Small coeffs that are too close to the beginning or end of the block
155   // should also be kept (not enough zeroes before/after).
156   tran_low_t qcoeff_scan[] = { 0, 0, -1, 0,  0, 0, 0,  0,  // should be kept
157                                0, 0, 0,  10, 0, 0, 0,  0,  // should be kept
158                                0, 0, 0,  2,  0, 0, 0,  0,  // should be removed
159                                0, 0, 0,  0,  0, 0, -1, 0 };  // should be kept
160   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after, qcoeff_scan);
161   ExpectArrayEq(qcoeff_scan, { 0, 0, -1, 0,  0, 0, 0,  0,  //
162                                0, 0, 0,  10, 0, 0, 0,  0,  //
163                                0, 0, 0,  0,  0, 0, 0,  0,  //
164                                0, 0, 0,  0,  0, 0, -1, 0 });
165 }
166 
TEST(DropoutTest,RemovesSmallClusterOfCoeffs)167 TEST(DropoutTest, RemovesSmallClusterOfCoeffs) {
168   const TX_SIZE tx_size = TX_8X4;
169   const uint32_t dropout_num_before = 4;
170   const uint32_t dropout_num_after = 6;
171   // Small clusters (<= kDropoutContinuityMax) of small coeffs should be
172   // removed.
173   tran_low_t qcoeff_scan_two[] = {
174     0, 0, 0, 0, 1, 0, 0, -1,  // should be removed
175     0, 0, 0, 0, 0, 0, 0, 0,   //
176     0, 0, 0, 0, 0, 0, 1, 0,   // should be removed
177     0, 0, 0, 0, 0, 0, 0, 0
178   };
179   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after,
180           qcoeff_scan_two);
181   ExpectArrayEq(qcoeff_scan_two, { 0, 0, 0, 0, 0, 0, 0, 0,  //
182                                    0, 0, 0, 0, 0, 0, 0, 0,  //
183                                    0, 0, 0, 0, 0, 0, 0, 0,  //
184                                    0, 0, 0, 0, 0, 0, 0, 0 });
185 }
186 
TEST(DropoutTest,KeepsLargeClusterOfCoeffs)187 TEST(DropoutTest, KeepsLargeClusterOfCoeffs) {
188   const TX_SIZE tx_size = TX_8X4;
189   const uint32_t dropout_num_before = 4;
190   const uint32_t dropout_num_after = 6;
191   // Large clusters (> kDropoutContinuityMax) of small coeffs should be kept.
192   tran_low_t qcoeff_scan[] = { 0, 0, 0, 0, 1, 0,  1, -1,  // should be kept
193                                0, 0, 0, 0, 0, 0,  0, 0,   //
194                                0, 0, 0, 0, 0, -2, 0, 0,   // should be removed
195                                0, 0, 0, 0, 0, 0,  0, 0 };
196   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after, qcoeff_scan);
197   ExpectArrayEq(qcoeff_scan, { 0, 0, 0, 0, 1, 0, 1, -1,  //
198                                0, 0, 0, 0, 0, 0, 0, 0,   //
199                                0, 0, 0, 0, 0, 0, 0, 0,   //
200                                0, 0, 0, 0, 0, 0, 0, 0 });
201 }
202 
TEST(DropoutTest,NumBeforeLargerThanNumAfter)203 TEST(DropoutTest, NumBeforeLargerThanNumAfter) {
204   const TX_SIZE tx_size = TX_8X4;
205   const uint32_t dropout_num_before = 4;
206   const uint32_t dropout_num_after = 2;
207   // The second coeff (-2) doesn't seem to meet the dropout_num_before
208   // criteria. But since the first coeff (1) will be dropped, it will meet
209   // the criteria and should be dropped too.
210   tran_low_t qcoeff_scan[] = { 0,  0, 0, 0, 1, 0, 0, 0,  // should be removed
211                                -2, 0, 0, 0, 0, 0, 0, 0,  // should be removed
212                                0,  0, 0, 0, 0, 0, 0, 0,  //
213                                0,  0, 0, 0, 0, 0, 0, 0 };
214   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after, qcoeff_scan);
215   ExpectArrayEq(qcoeff_scan, { 0, 0, 0, 0, 0, 0, 0, 0,  //
216                                0, 0, 0, 0, 0, 0, 0, 0,  //
217                                0, 0, 0, 0, 0, 0, 0, 0,  //
218                                0, 0, 0, 0, 0, 0, 0, 0 });
219 }
220 
221 // More complex test combining other test cases.
TEST(DropoutTest,ComplexTest)222 TEST(DropoutTest, ComplexTest) {
223   const TX_SIZE tx_size = TX_8X8;
224   const uint32_t dropout_num_before = 4;
225   const uint32_t dropout_num_after = 2;
226   tran_low_t qcoeff_scan[] = { 1, 12, 0,  0,   0, 0, 1,  0,   //
227                                0, 0,  0,  -12, 0, 0, 0,  1,   //
228                                0, 0,  -2, 0,   1, 0, 0,  1,   //
229                                0, 0,  0,  0,   5, 0, -1, 0,   //
230                                0, 0,  0,  1,   0, 0, 0,  -1,  //
231                                0, 0,  0,  0,   2, 0, 0,  0,   //
232                                0, 1,  0,  0,   0, 5, 0,  0,   //
233                                0, 0,  1,  1,   0, 0, 0,  -2 };
234   Dropout(tx_size, kTxType, dropout_num_before, dropout_num_after, qcoeff_scan);
235   ExpectArrayEq(qcoeff_scan, { 1, 12, 0,  0,   0, 0, 0,  0,  //
236                                0, 0,  0,  -12, 0, 0, 0,  1,  //
237                                0, 0,  -2, 0,   1, 0, 0,  1,  //
238                                0, 0,  0,  0,   5, 0, -1, 0,  //
239                                0, 0,  0,  0,   0, 0, 0,  0,  //
240                                0, 0,  0,  0,   0, 0, 0,  0,  //
241                                0, 0,  0,  0,   0, 5, 0,  0,  //
242                                0, 0,  0,  0,   0, 0, 0,  -2 });
243 }
244 
245 }  // namespace
246