/src/aom/av1/encoder/hybrid_fwd_txfm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016, 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 "config/aom_config.h" |
13 | | #include "config/av1_rtcd.h" |
14 | | #include "config/aom_dsp_rtcd.h" |
15 | | |
16 | | #include "av1/common/idct.h" |
17 | | #include "av1/common/blockd.h" |
18 | | #include "av1/encoder/hybrid_fwd_txfm.h" |
19 | | |
20 | | /* 4-point reversible, orthonormal Walsh-Hadamard in 3.5 adds, 0.5 shifts per |
21 | | pixel. |
22 | | Shared for both high and low bit depth. |
23 | | */ |
24 | 0 | void av1_fwht4x4_c(const int16_t *input, tran_low_t *output, int stride) { |
25 | 0 | int i; |
26 | 0 | tran_high_t a1, b1, c1, d1, e1; |
27 | 0 | const int16_t *ip_pass0 = input; |
28 | 0 | const tran_low_t *ip = NULL; |
29 | 0 | tran_low_t *op = output; |
30 | |
|
31 | 0 | for (i = 0; i < 4; i++) { |
32 | 0 | a1 = ip_pass0[0 * stride]; |
33 | 0 | b1 = ip_pass0[1 * stride]; |
34 | 0 | c1 = ip_pass0[2 * stride]; |
35 | 0 | d1 = ip_pass0[3 * stride]; |
36 | |
|
37 | 0 | a1 += b1; |
38 | 0 | d1 = d1 - c1; |
39 | 0 | e1 = (a1 - d1) >> 1; |
40 | 0 | b1 = e1 - b1; |
41 | 0 | c1 = e1 - c1; |
42 | 0 | a1 -= c1; |
43 | 0 | d1 += b1; |
44 | 0 | op[0] = (tran_low_t)a1; |
45 | 0 | op[1] = (tran_low_t)c1; |
46 | 0 | op[2] = (tran_low_t)d1; |
47 | 0 | op[3] = (tran_low_t)b1; |
48 | |
|
49 | 0 | ip_pass0++; |
50 | 0 | op += 4; |
51 | 0 | } |
52 | 0 | ip = output; |
53 | 0 | op = output; |
54 | |
|
55 | 0 | for (i = 0; i < 4; i++) { |
56 | 0 | a1 = ip[4 * 0]; |
57 | 0 | b1 = ip[4 * 1]; |
58 | 0 | c1 = ip[4 * 2]; |
59 | 0 | d1 = ip[4 * 3]; |
60 | |
|
61 | 0 | a1 += b1; |
62 | 0 | d1 -= c1; |
63 | 0 | e1 = (a1 - d1) >> 1; |
64 | 0 | b1 = e1 - b1; |
65 | 0 | c1 = e1 - c1; |
66 | 0 | a1 -= c1; |
67 | 0 | d1 += b1; |
68 | 0 | op[4 * 0] = (tran_low_t)(a1 * UNIT_QUANT_FACTOR); |
69 | 0 | op[4 * 1] = (tran_low_t)(c1 * UNIT_QUANT_FACTOR); |
70 | 0 | op[4 * 2] = (tran_low_t)(d1 * UNIT_QUANT_FACTOR); |
71 | 0 | op[4 * 3] = (tran_low_t)(b1 * UNIT_QUANT_FACTOR); |
72 | |
|
73 | 0 | ip++; |
74 | 0 | op++; |
75 | 0 | } |
76 | 0 | } |
77 | | |
78 | | static void highbd_fwd_txfm_4x4(const int16_t *src_diff, tran_low_t *coeff, |
79 | 0 | int diff_stride, TxfmParam *txfm_param) { |
80 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
81 | 0 | const TX_TYPE tx_type = txfm_param->tx_type; |
82 | 0 | const int bd = txfm_param->bd; |
83 | 0 | if (txfm_param->lossless) { |
84 | 0 | assert(tx_type == DCT_DCT); |
85 | 0 | av1_fwht4x4(src_diff, coeff, diff_stride); |
86 | 0 | return; |
87 | 0 | } |
88 | 0 | av1_fwd_txfm2d_4x4(src_diff, dst_coeff, diff_stride, tx_type, bd); |
89 | 0 | } |
90 | | |
91 | | static void highbd_fwd_txfm_4x8(const int16_t *src_diff, tran_low_t *coeff, |
92 | 0 | int diff_stride, TxfmParam *txfm_param) { |
93 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
94 | 0 | av1_fwd_txfm2d_4x8(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
95 | 0 | txfm_param->bd); |
96 | 0 | } |
97 | | |
98 | | static void highbd_fwd_txfm_8x4(const int16_t *src_diff, tran_low_t *coeff, |
99 | 0 | int diff_stride, TxfmParam *txfm_param) { |
100 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
101 | 0 | av1_fwd_txfm2d_8x4(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
102 | 0 | txfm_param->bd); |
103 | 0 | } |
104 | | |
105 | | static void highbd_fwd_txfm_8x16(const int16_t *src_diff, tran_low_t *coeff, |
106 | 0 | int diff_stride, TxfmParam *txfm_param) { |
107 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
108 | 0 | const TX_TYPE tx_type = txfm_param->tx_type; |
109 | 0 | const int bd = txfm_param->bd; |
110 | 0 | av1_fwd_txfm2d_8x16(src_diff, dst_coeff, diff_stride, tx_type, bd); |
111 | 0 | } |
112 | | |
113 | | static void highbd_fwd_txfm_16x8(const int16_t *src_diff, tran_low_t *coeff, |
114 | 0 | int diff_stride, TxfmParam *txfm_param) { |
115 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
116 | 0 | const TX_TYPE tx_type = txfm_param->tx_type; |
117 | 0 | const int bd = txfm_param->bd; |
118 | 0 | av1_fwd_txfm2d_16x8(src_diff, dst_coeff, diff_stride, tx_type, bd); |
119 | 0 | } |
120 | | |
121 | | static void highbd_fwd_txfm_16x32(const int16_t *src_diff, tran_low_t *coeff, |
122 | 0 | int diff_stride, TxfmParam *txfm_param) { |
123 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
124 | 0 | av1_fwd_txfm2d_16x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
125 | 0 | txfm_param->bd); |
126 | 0 | } |
127 | | |
128 | | static void highbd_fwd_txfm_32x16(const int16_t *src_diff, tran_low_t *coeff, |
129 | 0 | int diff_stride, TxfmParam *txfm_param) { |
130 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
131 | 0 | av1_fwd_txfm2d_32x16(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
132 | 0 | txfm_param->bd); |
133 | 0 | } |
134 | | |
135 | | #if !CONFIG_REALTIME_ONLY |
136 | | static void highbd_fwd_txfm_16x4(const int16_t *src_diff, tran_low_t *coeff, |
137 | 0 | int diff_stride, TxfmParam *txfm_param) { |
138 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
139 | 0 | av1_fwd_txfm2d_16x4(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
140 | 0 | txfm_param->bd); |
141 | 0 | } |
142 | | |
143 | | static void highbd_fwd_txfm_4x16(const int16_t *src_diff, tran_low_t *coeff, |
144 | 0 | int diff_stride, TxfmParam *txfm_param) { |
145 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
146 | 0 | av1_fwd_txfm2d_4x16(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
147 | 0 | txfm_param->bd); |
148 | 0 | } |
149 | | |
150 | | static void highbd_fwd_txfm_32x8(const int16_t *src_diff, tran_low_t *coeff, |
151 | 0 | int diff_stride, TxfmParam *txfm_param) { |
152 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
153 | 0 | av1_fwd_txfm2d_32x8(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
154 | 0 | txfm_param->bd); |
155 | 0 | } |
156 | | |
157 | | static void highbd_fwd_txfm_8x32(const int16_t *src_diff, tran_low_t *coeff, |
158 | 0 | int diff_stride, TxfmParam *txfm_param) { |
159 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
160 | 0 | av1_fwd_txfm2d_8x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
161 | 0 | txfm_param->bd); |
162 | 0 | } |
163 | | #endif |
164 | | |
165 | | static void highbd_fwd_txfm_8x8(const int16_t *src_diff, tran_low_t *coeff, |
166 | 0 | int diff_stride, TxfmParam *txfm_param) { |
167 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
168 | 0 | const TX_TYPE tx_type = txfm_param->tx_type; |
169 | 0 | const int bd = txfm_param->bd; |
170 | 0 | av1_fwd_txfm2d_8x8(src_diff, dst_coeff, diff_stride, tx_type, bd); |
171 | 0 | } |
172 | | |
173 | | static void highbd_fwd_txfm_16x16(const int16_t *src_diff, tran_low_t *coeff, |
174 | 0 | int diff_stride, TxfmParam *txfm_param) { |
175 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
176 | 0 | const TX_TYPE tx_type = txfm_param->tx_type; |
177 | 0 | const int bd = txfm_param->bd; |
178 | 0 | av1_fwd_txfm2d_16x16(src_diff, dst_coeff, diff_stride, tx_type, bd); |
179 | 0 | } |
180 | | |
181 | | static void highbd_fwd_txfm_32x32(const int16_t *src_diff, tran_low_t *coeff, |
182 | 0 | int diff_stride, TxfmParam *txfm_param) { |
183 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
184 | 0 | const TX_TYPE tx_type = txfm_param->tx_type; |
185 | 0 | const int bd = txfm_param->bd; |
186 | 0 | av1_fwd_txfm2d_32x32(src_diff, dst_coeff, diff_stride, tx_type, bd); |
187 | 0 | } |
188 | | |
189 | | static void highbd_fwd_txfm_32x64(const int16_t *src_diff, tran_low_t *coeff, |
190 | 0 | int diff_stride, TxfmParam *txfm_param) { |
191 | 0 | assert(txfm_param->tx_type == DCT_DCT); |
192 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
193 | 0 | const int bd = txfm_param->bd; |
194 | 0 | av1_fwd_txfm2d_32x64(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
195 | 0 | bd); |
196 | 0 | } |
197 | | |
198 | | static void highbd_fwd_txfm_64x32(const int16_t *src_diff, tran_low_t *coeff, |
199 | 0 | int diff_stride, TxfmParam *txfm_param) { |
200 | 0 | assert(txfm_param->tx_type == DCT_DCT); |
201 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
202 | 0 | const int bd = txfm_param->bd; |
203 | 0 | av1_fwd_txfm2d_64x32(src_diff, dst_coeff, diff_stride, txfm_param->tx_type, |
204 | 0 | bd); |
205 | 0 | } |
206 | | |
207 | | #if !CONFIG_REALTIME_ONLY |
208 | | static void highbd_fwd_txfm_16x64(const int16_t *src_diff, tran_low_t *coeff, |
209 | 0 | int diff_stride, TxfmParam *txfm_param) { |
210 | 0 | assert(txfm_param->tx_type == DCT_DCT); |
211 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
212 | 0 | const int bd = txfm_param->bd; |
213 | 0 | av1_fwd_txfm2d_16x64(src_diff, dst_coeff, diff_stride, DCT_DCT, bd); |
214 | 0 | } |
215 | | |
216 | | static void highbd_fwd_txfm_64x16(const int16_t *src_diff, tran_low_t *coeff, |
217 | 0 | int diff_stride, TxfmParam *txfm_param) { |
218 | 0 | assert(txfm_param->tx_type == DCT_DCT); |
219 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
220 | 0 | const int bd = txfm_param->bd; |
221 | 0 | av1_fwd_txfm2d_64x16(src_diff, dst_coeff, diff_stride, DCT_DCT, bd); |
222 | 0 | } |
223 | | #endif |
224 | | |
225 | | static void highbd_fwd_txfm_64x64(const int16_t *src_diff, tran_low_t *coeff, |
226 | 0 | int diff_stride, TxfmParam *txfm_param) { |
227 | 0 | assert(txfm_param->tx_type == DCT_DCT); |
228 | 0 | int32_t *dst_coeff = (int32_t *)coeff; |
229 | 0 | const int bd = txfm_param->bd; |
230 | 0 | av1_fwd_txfm2d_64x64(src_diff, dst_coeff, diff_stride, DCT_DCT, bd); |
231 | 0 | } |
232 | | |
233 | | void av1_fwd_txfm(const int16_t *src_diff, tran_low_t *coeff, int diff_stride, |
234 | 0 | TxfmParam *txfm_param) { |
235 | 0 | if (txfm_param->bd == 8) |
236 | 0 | av1_lowbd_fwd_txfm(src_diff, coeff, diff_stride, txfm_param); |
237 | 0 | else |
238 | 0 | av1_highbd_fwd_txfm(src_diff, coeff, diff_stride, txfm_param); |
239 | 0 | } |
240 | | |
241 | | void av1_lowbd_fwd_txfm_c(const int16_t *src_diff, tran_low_t *coeff, |
242 | 0 | int diff_stride, TxfmParam *txfm_param) { |
243 | 0 | av1_highbd_fwd_txfm(src_diff, coeff, diff_stride, txfm_param); |
244 | 0 | } |
245 | | |
246 | | void av1_highbd_fwd_txfm(const int16_t *src_diff, tran_low_t *coeff, |
247 | 0 | int diff_stride, TxfmParam *txfm_param) { |
248 | 0 | assert(av1_ext_tx_used[txfm_param->tx_set_type][txfm_param->tx_type]); |
249 | 0 | const TX_SIZE tx_size = txfm_param->tx_size; |
250 | 0 | switch (tx_size) { |
251 | 0 | case TX_64X64: |
252 | 0 | highbd_fwd_txfm_64x64(src_diff, coeff, diff_stride, txfm_param); |
253 | 0 | break; |
254 | 0 | case TX_32X64: |
255 | 0 | highbd_fwd_txfm_32x64(src_diff, coeff, diff_stride, txfm_param); |
256 | 0 | break; |
257 | 0 | case TX_64X32: |
258 | 0 | highbd_fwd_txfm_64x32(src_diff, coeff, diff_stride, txfm_param); |
259 | 0 | break; |
260 | | |
261 | 0 | case TX_32X32: |
262 | 0 | highbd_fwd_txfm_32x32(src_diff, coeff, diff_stride, txfm_param); |
263 | 0 | break; |
264 | 0 | case TX_16X16: |
265 | 0 | highbd_fwd_txfm_16x16(src_diff, coeff, diff_stride, txfm_param); |
266 | 0 | break; |
267 | 0 | case TX_8X8: |
268 | 0 | highbd_fwd_txfm_8x8(src_diff, coeff, diff_stride, txfm_param); |
269 | 0 | break; |
270 | 0 | case TX_4X8: |
271 | 0 | highbd_fwd_txfm_4x8(src_diff, coeff, diff_stride, txfm_param); |
272 | 0 | break; |
273 | 0 | case TX_8X4: |
274 | 0 | highbd_fwd_txfm_8x4(src_diff, coeff, diff_stride, txfm_param); |
275 | 0 | break; |
276 | 0 | case TX_8X16: |
277 | 0 | highbd_fwd_txfm_8x16(src_diff, coeff, diff_stride, txfm_param); |
278 | 0 | break; |
279 | 0 | case TX_16X8: |
280 | 0 | highbd_fwd_txfm_16x8(src_diff, coeff, diff_stride, txfm_param); |
281 | 0 | break; |
282 | 0 | case TX_16X32: |
283 | 0 | highbd_fwd_txfm_16x32(src_diff, coeff, diff_stride, txfm_param); |
284 | 0 | break; |
285 | 0 | case TX_32X16: |
286 | 0 | highbd_fwd_txfm_32x16(src_diff, coeff, diff_stride, txfm_param); |
287 | 0 | break; |
288 | 0 | case TX_4X4: |
289 | 0 | highbd_fwd_txfm_4x4(src_diff, coeff, diff_stride, txfm_param); |
290 | 0 | break; |
291 | 0 | #if !CONFIG_REALTIME_ONLY |
292 | 0 | case TX_4X16: |
293 | 0 | highbd_fwd_txfm_4x16(src_diff, coeff, diff_stride, txfm_param); |
294 | 0 | break; |
295 | 0 | case TX_16X4: |
296 | 0 | highbd_fwd_txfm_16x4(src_diff, coeff, diff_stride, txfm_param); |
297 | 0 | break; |
298 | 0 | case TX_8X32: |
299 | 0 | highbd_fwd_txfm_8x32(src_diff, coeff, diff_stride, txfm_param); |
300 | 0 | break; |
301 | 0 | case TX_32X8: |
302 | 0 | highbd_fwd_txfm_32x8(src_diff, coeff, diff_stride, txfm_param); |
303 | 0 | break; |
304 | 0 | case TX_16X64: |
305 | 0 | highbd_fwd_txfm_16x64(src_diff, coeff, diff_stride, txfm_param); |
306 | 0 | break; |
307 | 0 | case TX_64X16: |
308 | 0 | highbd_fwd_txfm_64x16(src_diff, coeff, diff_stride, txfm_param); |
309 | 0 | break; |
310 | 0 | #endif |
311 | 0 | default: assert(0); break; |
312 | 0 | } |
313 | 0 | } |
314 | | |
315 | | #if CONFIG_AV1_HIGHBITDEPTH |
316 | | static inline void highbd_wht_fwd_txfm(TX_SIZE tx_size, const int16_t *src_diff, |
317 | | ptrdiff_t src_stride, |
318 | 0 | tran_low_t *coeff) { |
319 | 0 | switch (tx_size) { |
320 | | // As the output transform co-efficients of 4x4 Hadamard transform can be |
321 | | // represented using 15 bits (for 12-bit clip) use lowbd variant of |
322 | | // hadamard_4x4. |
323 | 0 | case TX_4X4: aom_hadamard_4x4(src_diff, src_stride, coeff); break; |
324 | 0 | case TX_8X8: aom_highbd_hadamard_8x8(src_diff, src_stride, coeff); break; |
325 | 0 | case TX_16X16: |
326 | 0 | aom_highbd_hadamard_16x16(src_diff, src_stride, coeff); |
327 | 0 | break; |
328 | 0 | case TX_32X32: |
329 | 0 | aom_highbd_hadamard_32x32(src_diff, src_stride, coeff); |
330 | 0 | break; |
331 | 0 | default: assert(0); |
332 | 0 | } |
333 | 0 | } |
334 | | #endif // CONFIG_AV1_HIGHBITDEPTH |
335 | | |
336 | | static inline void wht_fwd_txfm(TX_SIZE tx_size, const int16_t *src_diff, |
337 | 0 | ptrdiff_t src_stride, tran_low_t *coeff) { |
338 | 0 | switch (tx_size) { |
339 | 0 | case TX_4X4: aom_hadamard_4x4(src_diff, src_stride, coeff); break; |
340 | 0 | case TX_8X8: aom_hadamard_8x8(src_diff, src_stride, coeff); break; |
341 | 0 | case TX_16X16: aom_hadamard_16x16(src_diff, src_stride, coeff); break; |
342 | 0 | case TX_32X32: aom_hadamard_32x32(src_diff, src_stride, coeff); break; |
343 | 0 | default: assert(0); |
344 | 0 | } |
345 | 0 | } |
346 | | |
347 | | void av1_quick_txfm(int use_hadamard, TX_SIZE tx_size, BitDepthInfo bd_info, |
348 | | const int16_t *src_diff, int src_stride, |
349 | 0 | tran_low_t *coeff) { |
350 | 0 | if (use_hadamard) { |
351 | 0 | #if CONFIG_AV1_HIGHBITDEPTH |
352 | 0 | if (bd_info.use_highbitdepth_buf) { |
353 | 0 | highbd_wht_fwd_txfm(tx_size, src_diff, src_stride, coeff); |
354 | 0 | } else { |
355 | 0 | wht_fwd_txfm(tx_size, src_diff, src_stride, coeff); |
356 | 0 | } |
357 | | #else |
358 | | wht_fwd_txfm(tx_size, src_diff, src_stride, coeff); |
359 | | #endif // CONFIG_AV1_HIGHBITDEPTH |
360 | 0 | } else { |
361 | 0 | TxfmParam txfm_param; |
362 | 0 | txfm_param.tx_type = DCT_DCT; |
363 | 0 | txfm_param.tx_size = tx_size; |
364 | 0 | txfm_param.lossless = 0; |
365 | 0 | txfm_param.bd = bd_info.bit_depth; |
366 | 0 | txfm_param.is_hbd = bd_info.use_highbitdepth_buf; |
367 | 0 | txfm_param.tx_set_type = EXT_TX_SET_ALL16; |
368 | 0 | av1_fwd_txfm(src_diff, coeff, src_stride, &txfm_param); |
369 | 0 | } |
370 | 0 | } |