encodemb_test.cc (10754B)
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'. 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'. 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'. 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 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 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 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 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 }; 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 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 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 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 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. 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