1 /*
2 * Copyright (c) 2017, 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 #ifndef AOM_AV1_COMMON_TXB_COMMON_H_
13 #define AOM_AV1_COMMON_TXB_COMMON_H_
14
15 extern const int16_t k_eob_group_start[12];
16 extern const int16_t k_eob_offset_bits[12];
17
18 extern const int8_t av1_coeff_band_4x4[16];
19
20 extern const int8_t av1_coeff_band_8x8[64];
21
22 extern const int8_t av1_coeff_band_16x16[256];
23
24 extern const int8_t av1_coeff_band_32x32[1024];
25
26 extern const int8_t *av1_nz_map_ctx_offset[TX_SIZES_ALL];
27
28 typedef struct txb_ctx {
29 int txb_skip_ctx;
30 int dc_sign_ctx;
31 } TXB_CTX;
32
33 static const int base_level_count_to_index[13] = {
34 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
35 };
36
37 static const TX_CLASS tx_type_to_class[TX_TYPES] = {
38 TX_CLASS_2D, // DCT_DCT
39 TX_CLASS_2D, // ADST_DCT
40 TX_CLASS_2D, // DCT_ADST
41 TX_CLASS_2D, // ADST_ADST
42 TX_CLASS_2D, // FLIPADST_DCT
43 TX_CLASS_2D, // DCT_FLIPADST
44 TX_CLASS_2D, // FLIPADST_FLIPADST
45 TX_CLASS_2D, // ADST_FLIPADST
46 TX_CLASS_2D, // FLIPADST_ADST
47 TX_CLASS_2D, // IDTX
48 TX_CLASS_VERT, // V_DCT
49 TX_CLASS_HORIZ, // H_DCT
50 TX_CLASS_VERT, // V_ADST
51 TX_CLASS_HORIZ, // H_ADST
52 TX_CLASS_VERT, // V_FLIPADST
53 TX_CLASS_HORIZ, // H_FLIPADST
54 };
55
get_txb_bwl(TX_SIZE tx_size)56 static INLINE int get_txb_bwl(TX_SIZE tx_size) {
57 tx_size = av1_get_adjusted_tx_size(tx_size);
58 return tx_size_wide_log2[tx_size];
59 }
60
get_txb_wide(TX_SIZE tx_size)61 static INLINE int get_txb_wide(TX_SIZE tx_size) {
62 tx_size = av1_get_adjusted_tx_size(tx_size);
63 return tx_size_wide[tx_size];
64 }
65
get_txb_high(TX_SIZE tx_size)66 static INLINE int get_txb_high(TX_SIZE tx_size) {
67 tx_size = av1_get_adjusted_tx_size(tx_size);
68 return tx_size_high[tx_size];
69 }
70
set_levels(uint8_t * const levels_buf,const int width)71 static INLINE uint8_t *set_levels(uint8_t *const levels_buf, const int width) {
72 return levels_buf + TX_PAD_TOP * (width + TX_PAD_HOR);
73 }
74
get_padded_idx(const int idx,const int bwl)75 static INLINE int get_padded_idx(const int idx, const int bwl) {
76 return idx + ((idx >> bwl) << TX_PAD_HOR_LOG2);
77 }
78
get_base_ctx_from_count_mag(int row,int col,int count,int sig_mag)79 static INLINE int get_base_ctx_from_count_mag(int row, int col, int count,
80 int sig_mag) {
81 const int ctx = base_level_count_to_index[count];
82 int ctx_idx = -1;
83
84 if (row == 0 && col == 0) {
85 if (sig_mag >= 2) return ctx_idx = 0;
86 if (sig_mag == 1) {
87 if (count >= 2)
88 ctx_idx = 1;
89 else
90 ctx_idx = 2;
91
92 return ctx_idx;
93 }
94
95 ctx_idx = 3 + ctx;
96 assert(ctx_idx <= 6);
97 return ctx_idx;
98 } else if (row == 0) {
99 if (sig_mag >= 2) return ctx_idx = 6;
100 if (sig_mag == 1) {
101 if (count >= 2)
102 ctx_idx = 7;
103 else
104 ctx_idx = 8;
105 return ctx_idx;
106 }
107
108 ctx_idx = 9 + ctx;
109 assert(ctx_idx <= 11);
110 return ctx_idx;
111 } else if (col == 0) {
112 if (sig_mag >= 2) return ctx_idx = 12;
113 if (sig_mag == 1) {
114 if (count >= 2)
115 ctx_idx = 13;
116 else
117 ctx_idx = 14;
118
119 return ctx_idx;
120 }
121
122 ctx_idx = 15 + ctx;
123 assert(ctx_idx <= 17);
124 // TODO(angiebird): turn this on once the optimization is finalized
125 // assert(ctx_idx < 28);
126 } else {
127 if (sig_mag >= 2) return ctx_idx = 18;
128 if (sig_mag == 1) {
129 if (count >= 2)
130 ctx_idx = 19;
131 else
132 ctx_idx = 20;
133 return ctx_idx;
134 }
135
136 ctx_idx = 21 + ctx;
137
138 assert(ctx_idx <= 24);
139 }
140 return ctx_idx;
141 }
142
get_br_ctx_2d(const uint8_t * const levels,const int c,const int bwl)143 static INLINE int get_br_ctx_2d(const uint8_t *const levels,
144 const int c, // raster order
145 const int bwl) {
146 assert(c > 0);
147 const int row = c >> bwl;
148 const int col = c - (row << bwl);
149 const int stride = (1 << bwl) + TX_PAD_HOR;
150 const int pos = row * stride + col;
151 int mag = AOMMIN(levels[pos + 1], MAX_BASE_BR_RANGE) +
152 AOMMIN(levels[pos + stride], MAX_BASE_BR_RANGE) +
153 AOMMIN(levels[pos + 1 + stride], MAX_BASE_BR_RANGE);
154 mag = AOMMIN((mag + 1) >> 1, 6);
155 //((row | col) < 2) is equivalent to ((row < 2) && (col < 2))
156 if ((row | col) < 2) return mag + 7;
157 return mag + 14;
158 }
159
get_br_ctx(const uint8_t * const levels,const int c,const int bwl,const TX_CLASS tx_class)160 static AOM_FORCE_INLINE int get_br_ctx(const uint8_t *const levels,
161 const int c, // raster order
162 const int bwl, const TX_CLASS tx_class) {
163 const int row = c >> bwl;
164 const int col = c - (row << bwl);
165 const int stride = (1 << bwl) + TX_PAD_HOR;
166 const int pos = row * stride + col;
167 int mag = levels[pos + 1];
168 mag += levels[pos + stride];
169 switch (tx_class) {
170 case TX_CLASS_2D:
171 mag += levels[pos + stride + 1];
172 mag = AOMMIN((mag + 1) >> 1, 6);
173 if (c == 0) return mag;
174 if ((row < 2) && (col < 2)) return mag + 7;
175 break;
176 case TX_CLASS_HORIZ:
177 mag += levels[pos + 2];
178 mag = AOMMIN((mag + 1) >> 1, 6);
179 if (c == 0) return mag;
180 if (col == 0) return mag + 7;
181 break;
182 case TX_CLASS_VERT:
183 mag += levels[pos + (stride << 1)];
184 mag = AOMMIN((mag + 1) >> 1, 6);
185 if (c == 0) return mag;
186 if (row == 0) return mag + 7;
187 break;
188 default: break;
189 }
190
191 return mag + 14;
192 }
193
194 static const uint8_t clip_max3[256] = {
195 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
196 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
197 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
198 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
199 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
200 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
201 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
202 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
203 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
204 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
205 };
206
get_nz_mag(const uint8_t * const levels,const int bwl,const TX_CLASS tx_class)207 static AOM_FORCE_INLINE int get_nz_mag(const uint8_t *const levels,
208 const int bwl, const TX_CLASS tx_class) {
209 int mag;
210
211 // Note: AOMMIN(level, 3) is useless for decoder since level < 3.
212 mag = clip_max3[levels[1]]; // { 0, 1 }
213 mag += clip_max3[levels[(1 << bwl) + TX_PAD_HOR]]; // { 1, 0 }
214
215 if (tx_class == TX_CLASS_2D) {
216 mag += clip_max3[levels[(1 << bwl) + TX_PAD_HOR + 1]]; // { 1, 1 }
217 mag += clip_max3[levels[2]]; // { 0, 2 }
218 mag += clip_max3[levels[(2 << bwl) + (2 << TX_PAD_HOR_LOG2)]]; // { 2, 0 }
219 } else if (tx_class == TX_CLASS_VERT) {
220 mag += clip_max3[levels[(2 << bwl) + (2 << TX_PAD_HOR_LOG2)]]; // { 2, 0 }
221 mag += clip_max3[levels[(3 << bwl) + (3 << TX_PAD_HOR_LOG2)]]; // { 3, 0 }
222 mag += clip_max3[levels[(4 << bwl) + (4 << TX_PAD_HOR_LOG2)]]; // { 4, 0 }
223 } else {
224 mag += clip_max3[levels[2]]; // { 0, 2 }
225 mag += clip_max3[levels[3]]; // { 0, 3 }
226 mag += clip_max3[levels[4]]; // { 0, 4 }
227 }
228
229 return mag;
230 }
231
232 #define NZ_MAP_CTX_0 SIG_COEF_CONTEXTS_2D
233 #define NZ_MAP_CTX_5 (NZ_MAP_CTX_0 + 5)
234 #define NZ_MAP_CTX_10 (NZ_MAP_CTX_0 + 10)
235
236 static const int nz_map_ctx_offset_1d[32] = {
237 NZ_MAP_CTX_0, NZ_MAP_CTX_5, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10,
238 NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10,
239 NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10,
240 NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10,
241 NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10,
242 NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10, NZ_MAP_CTX_10,
243 NZ_MAP_CTX_10, NZ_MAP_CTX_10,
244 };
245
get_nz_map_ctx_from_stats(const int stats,const int coeff_idx,const int bwl,const TX_SIZE tx_size,const TX_CLASS tx_class)246 static AOM_FORCE_INLINE int get_nz_map_ctx_from_stats(
247 const int stats,
248 const int coeff_idx, // raster order
249 const int bwl, const TX_SIZE tx_size, const TX_CLASS tx_class) {
250 // tx_class == 0(TX_CLASS_2D)
251 if ((tx_class | coeff_idx) == 0) return 0;
252 int ctx = (stats + 1) >> 1;
253 ctx = AOMMIN(ctx, 4);
254 switch (tx_class) {
255 case TX_CLASS_2D: {
256 // This is the algorithm to generate av1_nz_map_ctx_offset[][]
257 // const int width = tx_size_wide[tx_size];
258 // const int height = tx_size_high[tx_size];
259 // if (width < height) {
260 // if (row < 2) return 11 + ctx;
261 // } else if (width > height) {
262 // if (col < 2) return 16 + ctx;
263 // }
264 // if (row + col < 2) return ctx + 1;
265 // if (row + col < 4) return 5 + ctx + 1;
266 // return 21 + ctx;
267 return ctx + av1_nz_map_ctx_offset[tx_size][coeff_idx];
268 }
269 case TX_CLASS_HORIZ: {
270 const int row = coeff_idx >> bwl;
271 const int col = coeff_idx - (row << bwl);
272 return ctx + nz_map_ctx_offset_1d[col];
273 break;
274 }
275 case TX_CLASS_VERT: {
276 const int row = coeff_idx >> bwl;
277 return ctx + nz_map_ctx_offset_1d[row];
278 break;
279 }
280 default: break;
281 }
282 return 0;
283 }
284
285 typedef aom_cdf_prob (*base_cdf_arr)[CDF_SIZE(4)];
286 typedef aom_cdf_prob (*br_cdf_arr)[CDF_SIZE(BR_CDF_SIZE)];
287
get_lower_levels_ctx_eob(int bwl,int height,int scan_idx)288 static INLINE int get_lower_levels_ctx_eob(int bwl, int height, int scan_idx) {
289 if (scan_idx == 0) return 0;
290 if (scan_idx <= (height << bwl) / 8) return 1;
291 if (scan_idx <= (height << bwl) / 4) return 2;
292 return 3;
293 }
294
get_lower_levels_ctx_2d(const uint8_t * levels,int coeff_idx,int bwl,TX_SIZE tx_size)295 static INLINE int get_lower_levels_ctx_2d(const uint8_t *levels, int coeff_idx,
296 int bwl, TX_SIZE tx_size) {
297 assert(coeff_idx > 0);
298 int mag;
299 // Note: AOMMIN(level, 3) is useless for decoder since level < 3.
300 levels = levels + get_padded_idx(coeff_idx, bwl);
301 mag = AOMMIN(levels[1], 3); // { 0, 1 }
302 mag += AOMMIN(levels[(1 << bwl) + TX_PAD_HOR], 3); // { 1, 0 }
303 mag += AOMMIN(levels[(1 << bwl) + TX_PAD_HOR + 1], 3); // { 1, 1 }
304 mag += AOMMIN(levels[2], 3); // { 0, 2 }
305 mag += AOMMIN(levels[(2 << bwl) + (2 << TX_PAD_HOR_LOG2)], 3); // { 2, 0 }
306
307 const int ctx = AOMMIN((mag + 1) >> 1, 4);
308 return ctx + av1_nz_map_ctx_offset[tx_size][coeff_idx];
309 }
get_lower_levels_ctx(const uint8_t * levels,int coeff_idx,int bwl,TX_SIZE tx_size,TX_CLASS tx_class)310 static AOM_FORCE_INLINE int get_lower_levels_ctx(const uint8_t *levels,
311 int coeff_idx, int bwl,
312 TX_SIZE tx_size,
313 TX_CLASS tx_class) {
314 const int stats =
315 get_nz_mag(levels + get_padded_idx(coeff_idx, bwl), bwl, tx_class);
316 return get_nz_map_ctx_from_stats(stats, coeff_idx, bwl, tx_size, tx_class);
317 }
318
get_lower_levels_ctx_general(int is_last,int scan_idx,int bwl,int height,const uint8_t * levels,int coeff_idx,TX_SIZE tx_size,TX_CLASS tx_class)319 static INLINE int get_lower_levels_ctx_general(int is_last, int scan_idx,
320 int bwl, int height,
321 const uint8_t *levels,
322 int coeff_idx, TX_SIZE tx_size,
323 TX_CLASS tx_class) {
324 if (is_last) {
325 if (scan_idx == 0) return 0;
326 if (scan_idx <= (height << bwl) >> 3) return 1;
327 if (scan_idx <= (height << bwl) >> 2) return 2;
328 return 3;
329 }
330 return get_lower_levels_ctx(levels, coeff_idx, bwl, tx_size, tx_class);
331 }
332
set_dc_sign(int * cul_level,int dc_val)333 static INLINE void set_dc_sign(int *cul_level, int dc_val) {
334 if (dc_val < 0)
335 *cul_level |= 1 << COEFF_CONTEXT_BITS;
336 else if (dc_val > 0)
337 *cul_level += 2 << COEFF_CONTEXT_BITS;
338 }
339
get_txb_ctx(const BLOCK_SIZE plane_bsize,const TX_SIZE tx_size,const int plane,const ENTROPY_CONTEXT * const a,const ENTROPY_CONTEXT * const l,TXB_CTX * const txb_ctx)340 static INLINE void get_txb_ctx(const BLOCK_SIZE plane_bsize,
341 const TX_SIZE tx_size, const int plane,
342 const ENTROPY_CONTEXT *const a,
343 const ENTROPY_CONTEXT *const l,
344 TXB_CTX *const txb_ctx) {
345 #define MAX_TX_SIZE_UNIT 16
346 static const int8_t signs[3] = { 0, -1, 1 };
347 static const int8_t dc_sign_contexts[4 * MAX_TX_SIZE_UNIT + 1] = {
348 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
349 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
350 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
351 };
352 const int txb_w_unit = tx_size_wide_unit[tx_size];
353 const int txb_h_unit = tx_size_high_unit[tx_size];
354 int dc_sign = 0;
355 int k = 0;
356
357 do {
358 const unsigned int sign = ((uint8_t)a[k]) >> COEFF_CONTEXT_BITS;
359 assert(sign <= 2);
360 dc_sign += signs[sign];
361 } while (++k < txb_w_unit);
362
363 k = 0;
364 do {
365 const unsigned int sign = ((uint8_t)l[k]) >> COEFF_CONTEXT_BITS;
366 assert(sign <= 2);
367 dc_sign += signs[sign];
368 } while (++k < txb_h_unit);
369
370 txb_ctx->dc_sign_ctx = dc_sign_contexts[dc_sign + 2 * MAX_TX_SIZE_UNIT];
371
372 if (plane == 0) {
373 if (plane_bsize == txsize_to_bsize[tx_size]) {
374 txb_ctx->txb_skip_ctx = 0;
375 } else {
376 // This is the algorithm to generate table skip_contexts[min][max].
377 // if (!max)
378 // txb_skip_ctx = 1;
379 // else if (!min)
380 // txb_skip_ctx = 2 + (max > 3);
381 // else if (max <= 3)
382 // txb_skip_ctx = 4;
383 // else if (min <= 3)
384 // txb_skip_ctx = 5;
385 // else
386 // txb_skip_ctx = 6;
387 static const uint8_t skip_contexts[5][5] = { { 1, 2, 2, 2, 3 },
388 { 1, 4, 4, 4, 5 },
389 { 1, 4, 4, 4, 5 },
390 { 1, 4, 4, 4, 5 },
391 { 1, 4, 4, 4, 6 } };
392 int top = 0;
393 int left = 0;
394
395 k = 0;
396 do {
397 top |= a[k];
398 } while (++k < txb_w_unit);
399 top &= COEFF_CONTEXT_MASK;
400
401 k = 0;
402 do {
403 left |= l[k];
404 } while (++k < txb_h_unit);
405 left &= COEFF_CONTEXT_MASK;
406 const int max = AOMMIN(top | left, 4);
407 const int min = AOMMIN(AOMMIN(top, left), 4);
408
409 txb_ctx->txb_skip_ctx = skip_contexts[min][max];
410 }
411 } else {
412 const int ctx_base = get_entropy_context(tx_size, a, l);
413 const int ctx_offset = (num_pels_log2_lookup[plane_bsize] >
414 num_pels_log2_lookup[txsize_to_bsize[tx_size]])
415 ? 10
416 : 7;
417 txb_ctx->txb_skip_ctx = ctx_base + ctx_offset;
418 }
419 #undef MAX_TX_SIZE_UNIT
420 }
421
422 void av1_init_lv_map(AV1_COMMON *cm);
423
424 #endif // AOM_AV1_COMMON_TXB_COMMON_H_
425