2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
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.
17 #include "./av1_rtcd.h"
18 #include "test/acm_random.h"
19 #include "test/util.h"
20 #include "test/av1_txfm_test.h"
21 #include "av1/common/av1_inv_txfm1d_cfg.h"
23 using libaom_test::ACMRandom
;
24 using libaom_test::input_base
;
25 using libaom_test::bd
;
26 using libaom_test::compute_avg_abs_error
;
27 using libaom_test::Fwd_Txfm2d_Func
;
28 using libaom_test::Inv_Txfm2d_Func
;
34 // AV1InvTxfm2dParam argument list:
35 // tx_type_, tx_size_, max_error_, max_avg_error_
36 typedef std::tr1::tuple
<TX_TYPE
, TX_SIZE
, int, double> AV1InvTxfm2dParam
;
38 class AV1InvTxfm2d
: public ::testing::TestWithParam
<AV1InvTxfm2dParam
> {
40 virtual void SetUp() {
41 tx_type_
= GET_PARAM(0);
42 tx_size_
= GET_PARAM(1);
43 max_error_
= GET_PARAM(2);
44 max_avg_error_
= GET_PARAM(3);
47 void RunRoundtripCheck() {
48 int tx_w
= tx_size_wide
[tx_size_
];
49 int tx_h
= tx_size_high
[tx_size_
];
50 int txfm2d_size
= tx_w
* tx_h
;
51 const Fwd_Txfm2d_Func fwd_txfm_func
=
52 libaom_test::fwd_txfm_func_ls
[tx_size_
];
53 const Inv_Txfm2d_Func inv_txfm_func
=
54 libaom_test::inv_txfm_func_ls
[tx_size_
];
55 double avg_abs_error
= 0;
56 ACMRandom
rnd(ACMRandom::DeterministicSeed());
58 const int count
= 500;
60 for (int ci
= 0; ci
< count
; ci
++) {
61 DECLARE_ALIGNED(16, int16_t, input
[64 * 64]) = { 0 };
62 ASSERT_LE(txfm2d_size
, NELEMENTS(input
));
64 for (int ni
= 0; ni
< txfm2d_size
; ++ni
) {
66 int extreme_input
= input_base
- 1;
67 input
[ni
] = extreme_input
; // extreme case
69 input
[ni
] = rnd
.Rand16() % input_base
;
73 DECLARE_ALIGNED(16, uint16_t, expected
[64 * 64]) = { 0 };
74 ASSERT_LE(txfm2d_size
, NELEMENTS(expected
));
75 if (TxfmUsesApproximation()) {
76 // Compare reference forward HT + inverse HT vs forward HT + inverse HT.
77 double ref_input
[64 * 64];
78 ASSERT_LE(txfm2d_size
, NELEMENTS(ref_input
));
79 for (int ni
= 0; ni
< txfm2d_size
; ++ni
) {
80 ref_input
[ni
] = input
[ni
];
82 double ref_coeffs
[64 * 64] = { 0 };
83 ASSERT_LE(txfm2d_size
, NELEMENTS(ref_coeffs
));
84 ASSERT_EQ(tx_type_
, DCT_DCT
);
85 libaom_test::reference_hybrid_2d(ref_input
, ref_coeffs
, tx_type_
,
87 DECLARE_ALIGNED(16, int32_t, ref_coeffs_int
[64 * 64]) = { 0 };
88 ASSERT_LE(txfm2d_size
, NELEMENTS(ref_coeffs_int
));
89 for (int ni
= 0; ni
< txfm2d_size
; ++ni
) {
90 ref_coeffs_int
[ni
] = (int32_t)round(ref_coeffs
[ni
]);
92 inv_txfm_func(ref_coeffs_int
, expected
, tx_w
, tx_type_
, bd
);
94 // Compare original input vs forward HT + inverse HT.
95 for (int ni
= 0; ni
< txfm2d_size
; ++ni
) {
96 expected
[ni
] = input
[ni
];
100 DECLARE_ALIGNED(16, int32_t, coeffs
[64 * 64]) = { 0 };
101 ASSERT_LE(txfm2d_size
, NELEMENTS(coeffs
));
102 fwd_txfm_func(input
, coeffs
, tx_w
, tx_type_
, bd
);
104 DECLARE_ALIGNED(16, uint16_t, actual
[64 * 64]) = { 0 };
105 ASSERT_LE(txfm2d_size
, NELEMENTS(actual
));
106 inv_txfm_func(coeffs
, actual
, tx_w
, tx_type_
, bd
);
108 double actual_max_error
= 0;
109 for (int ni
= 0; ni
< txfm2d_size
; ++ni
) {
110 const double this_error
= abs(expected
[ni
] - actual
[ni
]);
111 actual_max_error
= AOMMAX(actual_max_error
, this_error
);
113 EXPECT_GE(max_error_
, actual_max_error
)
114 << " tx_w: " << tx_w
<< " tx_h " << tx_h
<< " tx_type: " << tx_type_
;
115 if (actual_max_error
> max_error_
) { // exit early.
118 avg_abs_error
+= compute_avg_abs_error
<uint16_t, uint16_t>(
119 expected
, actual
, txfm2d_size
);
122 avg_abs_error
/= count
;
123 EXPECT_GE(max_avg_error_
, avg_abs_error
)
124 << " tx_w: " << tx_w
<< " tx_h " << tx_h
<< " tx_type: " << tx_type_
;
128 bool TxfmUsesApproximation() {
130 if (tx_size_wide
[tx_size_
] == 64 || tx_size_high
[tx_size_
] == 64) {
133 #endif // CONFIG_TX64X64
138 double max_avg_error_
;
143 vector
<AV1InvTxfm2dParam
> GetInvTxfm2dParamList() {
144 vector
<AV1InvTxfm2dParam
> param_list
;
145 for (int t
= 0; t
<= FLIPADST_ADST
; ++t
) {
146 const TX_TYPE tx_type
= static_cast<TX_TYPE
>(t
);
147 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_4X4
, 2, 0.002));
148 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_8X8
, 2, 0.025));
149 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_16X16
, 2, 0.04));
150 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_32X32
, 4, 0.4));
152 if (tx_type
== DCT_DCT
) { // Other types not supported by these tx sizes.
153 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_64X64
, 3, 0.2));
155 #endif // CONFIG_TX64X64
157 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_4X8
, 2, 0.016));
158 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_8X4
, 2, 0.016));
159 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_8X16
, 2, 0.2));
160 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_16X8
, 2, 0.2));
161 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_16X32
, 3, 0.4));
162 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_32X16
, 3, 0.4));
164 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_4X16
, 2, 0.2));
165 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_16X4
, 2, 0.2));
166 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_8X32
, 2, 0.2));
167 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_32X8
, 2, 0.2));
170 if (tx_type
== DCT_DCT
) { // Other types not supported by these tx sizes.
171 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_32X64
, 5, 0.38));
172 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_64X32
, 5, 0.38));
173 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_16X64
, 3, 0.38));
174 param_list
.push_back(AV1InvTxfm2dParam(tx_type
, TX_64X16
, 3, 0.38));
176 #endif // CONFIG_TX64X64
181 INSTANTIATE_TEST_CASE_P(C
, AV1InvTxfm2d
,
182 ::testing::ValuesIn(GetInvTxfm2dParamList()));
184 TEST_P(AV1InvTxfm2d
, RunRoundtripCheck
) { RunRoundtripCheck(); }
186 TEST(AV1InvTxfm2d
, CfgTest
) {
187 for (int bd_idx
= 0; bd_idx
< BD_NUM
; ++bd_idx
) {
188 int bd
= libaom_test::bd_arr
[bd_idx
];
189 int8_t low_range
= libaom_test::low_range_arr
[bd_idx
];
190 int8_t high_range
= libaom_test::high_range_arr
[bd_idx
];
191 for (int tx_size
= 0; tx_size
< TX_SIZES_ALL
; ++tx_size
) {
192 for (int tx_type
= 0; tx_type
< TX_TYPES
; ++tx_type
) {
194 if ((tx_size_wide
[tx_size
] == 64 || tx_size_high
[tx_size
] == 64) &&
195 tx_type
!= DCT_DCT
) {
198 #endif // CONFIG_TX64X64
199 TXFM_2D_FLIP_CFG cfg
;
200 av1_get_inv_txfm_cfg(static_cast<TX_TYPE
>(tx_type
),
201 static_cast<TX_SIZE
>(tx_size
), &cfg
);
202 int8_t stage_range_col
[MAX_TXFM_STAGE_NUM
];
203 int8_t stage_range_row
[MAX_TXFM_STAGE_NUM
];
204 av1_gen_inv_stage_range(stage_range_col
, stage_range_row
, &cfg
,
205 (TX_SIZE
)tx_size
, bd
);
206 const TXFM_1D_CFG
*col_cfg
= cfg
.col_cfg
;
207 const TXFM_1D_CFG
*row_cfg
= cfg
.row_cfg
;
208 libaom_test::txfm_stage_range_check(stage_range_col
, col_cfg
->stage_num
,
209 col_cfg
->cos_bit
, low_range
,
211 libaom_test::txfm_stage_range_check(stage_range_row
, row_cfg
->stage_num
,
212 row_cfg
->cos_bit
, low_range
,