blob: 4c725c7dea8862295613137483273f5428f0efd8 [file] [log] [blame]
Maryla3f6ddeb2021-05-07 10:40:36 +02001/*
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 "third_party/googletest/src/googletest/include/gtest/gtest.h"
16
17#include "av1/encoder/block.h"
18#include "av1/encoder/encodemb.h"
19#include "av1/common/scan.h"
20
21namespace {
22
23// Reorders 'qcoeff_lexico', which is in lexicographic order (row by row), into
24// scan order (zigzag) in 'qcoeff_scan'.
25void 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'.
36void 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'.
46void 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 qqcoeff is still valid.
86 for (int i = 0; i < max_eob; ++i) {
87 EXPECT_EQ(qcoeff[i] * kDequantFactor, dqcoeff[i]);
88 }
89}
90
91void 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
97static constexpr TX_TYPE kTxType = DCT_DCT;
98
99TEST(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
115TEST(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
131TEST(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
150TEST(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
167TEST(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
187TEST(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
203TEST(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.
222TEST(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