| 1 | // Copyright (c) 2017-2022, The rav1e contributors. All rights reserved |
| 2 | // |
| 3 | // This source code is subject to the terms of the BSD 2 Clause License and |
| 4 | // the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| 5 | // was not distributed with this source code in the LICENSE file, you can |
| 6 | // obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| 7 | // Media Patent License 1.0 was not distributed with this source code in the |
| 8 | // PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
| 9 | |
| 10 | use super::*; |
| 11 | use crate::predict::PredictionMode; |
| 12 | use crate::predict::PredictionMode::*; |
| 13 | use crate::transform::TxType::*; |
| 14 | use std::mem::MaybeUninit; |
| 15 | |
| 16 | pub const MAX_TX_SIZE: usize = 64; |
| 17 | |
| 18 | pub const MAX_CODED_TX_SIZE: usize = 32; |
| 19 | pub const MAX_CODED_TX_SQUARE: usize = MAX_CODED_TX_SIZE * MAX_CODED_TX_SIZE; |
| 20 | |
| 21 | pub const TX_SIZE_SQR_CONTEXTS: usize = 4; // Coded tx_size <= 32x32, so is the # of CDF contexts from tx sizes |
| 22 | |
| 23 | pub const TX_SETS: usize = 6; |
| 24 | pub const TX_SETS_INTRA: usize = 3; |
| 25 | pub const TX_SETS_INTER: usize = 4; |
| 26 | |
| 27 | pub const INTRA_MODES: usize = 13; |
| 28 | pub const UV_INTRA_MODES: usize = 14; |
| 29 | |
| 30 | const MAX_VARTX_DEPTH: usize = 2; |
| 31 | |
| 32 | pub const TXFM_PARTITION_CONTEXTS: usize = |
| 33 | (TxSize::TX_SIZES - TxSize::TX_8X8 as usize) * 6 - 3; |
| 34 | |
| 35 | // Number of transform types in each set type |
| 36 | pub static num_tx_set: [usize; TX_SETS] = [1, 2, 5, 7, 12, 16]; |
| 37 | pub static av1_tx_used: [[usize; TX_TYPES]; TX_SETS] = [ |
| 38 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], |
| 39 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], |
| 40 | [1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], |
| 41 | [1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], |
| 42 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0], |
| 43 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], |
| 44 | ]; |
| 45 | |
| 46 | // Maps set types above to the indices used for intra |
| 47 | static tx_set_index_intra: [i8; TX_SETS] = [0, -1, 2, 1, -1, -1]; |
| 48 | // Maps set types above to the indices used for inter |
| 49 | static tx_set_index_inter: [i8; TX_SETS] = [0, 3, -1, -1, 2, 1]; |
| 50 | |
| 51 | pub static av1_tx_ind: [[usize; TX_TYPES]; TX_SETS] = [ |
| 52 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], |
| 53 | [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], |
| 54 | [1, 3, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], |
| 55 | [1, 5, 6, 4, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0], |
| 56 | [3, 4, 5, 8, 6, 7, 9, 10, 11, 0, 1, 2, 0, 0, 0, 0], |
| 57 | [7, 8, 9, 12, 10, 11, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6], |
| 58 | ]; |
| 59 | |
| 60 | pub static max_txsize_rect_lookup: [TxSize; BlockSize::BLOCK_SIZES_ALL] = [ |
| 61 | TX_4X4, // 4x4 |
| 62 | TX_4X8, // 4x8 |
| 63 | TX_8X4, // 8x4 |
| 64 | TX_8X8, // 8x8 |
| 65 | TX_8X16, // 8x16 |
| 66 | TX_16X8, // 16x8 |
| 67 | TX_16X16, // 16x16 |
| 68 | TX_16X32, // 16x32 |
| 69 | TX_32X16, // 32x16 |
| 70 | TX_32X32, // 32x32 |
| 71 | TX_32X64, // 32x64 |
| 72 | TX_64X32, // 64x32 |
| 73 | TX_64X64, // 64x64 |
| 74 | TX_64X64, // 64x128 |
| 75 | TX_64X64, // 128x64 |
| 76 | TX_64X64, // 128x128 |
| 77 | TX_4X16, // 4x16 |
| 78 | TX_16X4, // 16x4 |
| 79 | TX_8X32, // 8x32 |
| 80 | TX_32X8, // 32x8 |
| 81 | TX_16X64, // 16x64 |
| 82 | TX_64X16, // 64x16 |
| 83 | ]; |
| 84 | |
| 85 | pub static sub_tx_size_map: [TxSize; TxSize::TX_SIZES_ALL] = [ |
| 86 | TX_4X4, // TX_4X4 |
| 87 | TX_4X4, // TX_8X8 |
| 88 | TX_8X8, // TX_16X16 |
| 89 | TX_16X16, // TX_32X32 |
| 90 | TX_32X32, // TX_64X64 |
| 91 | TX_4X4, // TX_4X8 |
| 92 | TX_4X4, // TX_8X4 |
| 93 | TX_8X8, // TX_8X16 |
| 94 | TX_8X8, // TX_16X8 |
| 95 | TX_16X16, // TX_16X32 |
| 96 | TX_16X16, // TX_32X16 |
| 97 | TX_32X32, // TX_32X64 |
| 98 | TX_32X32, // TX_64X32 |
| 99 | TX_4X8, // TX_4X16 |
| 100 | TX_8X4, // TX_16X4 |
| 101 | TX_8X16, // TX_8X32 |
| 102 | TX_16X8, // TX_32X8 |
| 103 | TX_16X32, // TX_16X64 |
| 104 | TX_32X16, // TX_64X16 |
| 105 | ]; |
| 106 | |
| 107 | #[inline ] |
| 108 | pub fn has_chroma( |
| 109 | bo: TileBlockOffset, bsize: BlockSize, subsampling_x: usize, |
| 110 | subsampling_y: usize, chroma_sampling: ChromaSampling, |
| 111 | ) -> bool { |
| 112 | if chroma_sampling == ChromaSampling::Cs400 { |
| 113 | return false; |
| 114 | }; |
| 115 | |
| 116 | let bw: usize = bsize.width_mi(); |
| 117 | let bh: usize = bsize.height_mi(); |
| 118 | |
| 119 | ((bo.0.x & 0x01) == 1 || (bw & 0x01) == 0 || subsampling_x == 0) |
| 120 | && ((bo.0.y & 0x01) == 1 || (bh & 0x01) == 0 || subsampling_y == 0) |
| 121 | } |
| 122 | |
| 123 | pub fn get_tx_set( |
| 124 | tx_size: TxSize, is_inter: bool, use_reduced_set: bool, |
| 125 | ) -> TxSet { |
| 126 | let tx_size_sqr_up: TxSize = tx_size.sqr_up(); |
| 127 | let tx_size_sqr: TxSize = tx_size.sqr(); |
| 128 | |
| 129 | if tx_size_sqr_up.block_size() > BlockSize::BLOCK_32X32 { |
| 130 | return TxSet::TX_SET_DCTONLY; |
| 131 | } |
| 132 | |
| 133 | if is_inter { |
| 134 | if use_reduced_set || tx_size_sqr_up == TxSize::TX_32X32 { |
| 135 | TxSet::TX_SET_INTER_3 |
| 136 | } else if tx_size_sqr == TxSize::TX_16X16 { |
| 137 | TxSet::TX_SET_INTER_2 |
| 138 | } else { |
| 139 | TxSet::TX_SET_INTER_1 |
| 140 | } |
| 141 | } else if tx_size_sqr_up == TxSize::TX_32X32 { |
| 142 | TxSet::TX_SET_DCTONLY |
| 143 | } else if use_reduced_set || tx_size_sqr == TxSize::TX_16X16 { |
| 144 | TxSet::TX_SET_INTRA_2 |
| 145 | } else { |
| 146 | TxSet::TX_SET_INTRA_1 |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | pub fn get_tx_set_index( |
| 151 | tx_size: TxSize, is_inter: bool, use_reduced_set: bool, |
| 152 | ) -> i8 { |
| 153 | let set_type: TxSet = get_tx_set(tx_size, is_inter, use_reduced_set); |
| 154 | |
| 155 | if is_inter { |
| 156 | tx_set_index_inter[set_type as usize] |
| 157 | } else { |
| 158 | tx_set_index_intra[set_type as usize] |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | static intra_mode_to_tx_type_context: [TxType; INTRA_MODES] = [ |
| 163 | DCT_DCT, // DC |
| 164 | ADST_DCT, // V |
| 165 | DCT_ADST, // H |
| 166 | DCT_DCT, // D45 |
| 167 | ADST_ADST, // D135 |
| 168 | ADST_DCT, // D113 |
| 169 | DCT_ADST, // D157 |
| 170 | DCT_ADST, // D203 |
| 171 | ADST_DCT, // D67 |
| 172 | ADST_ADST, // SMOOTH |
| 173 | ADST_DCT, // SMOOTH_V |
| 174 | DCT_ADST, // SMOOTH_H |
| 175 | ADST_ADST, // PAETH |
| 176 | ]; |
| 177 | |
| 178 | static uv2y: [PredictionMode; UV_INTRA_MODES] = [ |
| 179 | DC_PRED, // UV_DC_PRED |
| 180 | V_PRED, // UV_V_PRED |
| 181 | H_PRED, // UV_H_PRED |
| 182 | D45_PRED, // UV_D45_PRED |
| 183 | D135_PRED, // UV_D135_PRED |
| 184 | D113_PRED, // UV_D113_PRED |
| 185 | D157_PRED, // UV_D157_PRED |
| 186 | D203_PRED, // UV_D203_PRED |
| 187 | D67_PRED, // UV_D67_PRED |
| 188 | SMOOTH_PRED, // UV_SMOOTH_PRED |
| 189 | SMOOTH_V_PRED, // UV_SMOOTH_V_PRED |
| 190 | SMOOTH_H_PRED, // UV_SMOOTH_H_PRED |
| 191 | PAETH_PRED, // UV_PAETH_PRED |
| 192 | DC_PRED, // CFL_PRED |
| 193 | ]; |
| 194 | |
| 195 | pub fn uv_intra_mode_to_tx_type_context(pred: PredictionMode) -> TxType { |
| 196 | intra_mode_to_tx_type_context[uv2y[pred as usize] as usize] |
| 197 | } |
| 198 | |
| 199 | // Level Map |
| 200 | pub const TXB_SKIP_CONTEXTS: usize = 13; |
| 201 | |
| 202 | pub const EOB_COEF_CONTEXTS: usize = 9; |
| 203 | |
| 204 | const SIG_COEF_CONTEXTS_2D: usize = 26; |
| 205 | const SIG_COEF_CONTEXTS_1D: usize = 16; |
| 206 | pub const SIG_COEF_CONTEXTS_EOB: usize = 4; |
| 207 | pub const SIG_COEF_CONTEXTS: usize = |
| 208 | SIG_COEF_CONTEXTS_2D + SIG_COEF_CONTEXTS_1D; |
| 209 | |
| 210 | const COEFF_BASE_CONTEXTS: usize = SIG_COEF_CONTEXTS; |
| 211 | pub const DC_SIGN_CONTEXTS: usize = 3; |
| 212 | |
| 213 | const BR_TMP_OFFSET: usize = 12; |
| 214 | const BR_REF_CAT: usize = 4; |
| 215 | pub const LEVEL_CONTEXTS: usize = 21; |
| 216 | |
| 217 | pub const NUM_BASE_LEVELS: usize = 2; |
| 218 | |
| 219 | pub const BR_CDF_SIZE: usize = 4; |
| 220 | pub const COEFF_BASE_RANGE: usize = 4 * (BR_CDF_SIZE - 1); |
| 221 | |
| 222 | pub const COEFF_CONTEXT_BITS: usize = 6; |
| 223 | pub const COEFF_CONTEXT_MASK: usize = (1 << COEFF_CONTEXT_BITS) - 1; |
| 224 | const MAX_BASE_BR_RANGE: usize = COEFF_BASE_RANGE + NUM_BASE_LEVELS + 1; |
| 225 | |
| 226 | const BASE_CONTEXT_POSITION_NUM: usize = 12; |
| 227 | |
| 228 | // Pad 4 extra columns to remove horizontal availability check. |
| 229 | pub const TX_PAD_HOR_LOG2: usize = 2; |
| 230 | pub const TX_PAD_HOR: usize = 4; |
| 231 | // Pad 6 extra rows (2 on top and 4 on bottom) to remove vertical availability |
| 232 | // check. |
| 233 | pub const TX_PAD_TOP: usize = 2; |
| 234 | pub const TX_PAD_BOTTOM: usize = 4; |
| 235 | pub const TX_PAD_VER: usize = TX_PAD_TOP + TX_PAD_BOTTOM; |
| 236 | // Pad 16 extra bytes to avoid reading overflow in SIMD optimization. |
| 237 | const TX_PAD_END: usize = 16; |
| 238 | pub const TX_PAD_2D: usize = (MAX_CODED_TX_SIZE + TX_PAD_HOR) |
| 239 | * (MAX_CODED_TX_SIZE + TX_PAD_VER) |
| 240 | + TX_PAD_END; |
| 241 | |
| 242 | const TX_CLASSES: usize = 3; |
| 243 | |
| 244 | #[derive (Copy, Clone, PartialEq, Eq)] |
| 245 | pub enum TxClass { |
| 246 | TX_CLASS_2D = 0, |
| 247 | TX_CLASS_HORIZ = 1, |
| 248 | TX_CLASS_VERT = 2, |
| 249 | } |
| 250 | |
| 251 | #[derive (Copy, Clone, PartialEq, Eq)] |
| 252 | pub enum SegLvl { |
| 253 | SEG_LVL_ALT_Q = 0, /* Use alternate Quantizer .... */ |
| 254 | SEG_LVL_ALT_LF_Y_V = 1, /* Use alternate loop filter value on y plane vertical */ |
| 255 | SEG_LVL_ALT_LF_Y_H = 2, /* Use alternate loop filter value on y plane horizontal */ |
| 256 | SEG_LVL_ALT_LF_U = 3, /* Use alternate loop filter value on u plane */ |
| 257 | SEG_LVL_ALT_LF_V = 4, /* Use alternate loop filter value on v plane */ |
| 258 | SEG_LVL_REF_FRAME = 5, /* Optional Segment reference frame */ |
| 259 | SEG_LVL_SKIP = 6, /* Optional Segment (0,0) + skip mode */ |
| 260 | SEG_LVL_GLOBALMV = 7, |
| 261 | SEG_LVL_MAX = 8, |
| 262 | } |
| 263 | |
| 264 | pub const seg_feature_bits: [u32; SegLvl::SEG_LVL_MAX as usize] = |
| 265 | [8, 6, 6, 6, 6, 3, 0, 0]; |
| 266 | |
| 267 | pub const seg_feature_is_signed: [bool; SegLvl::SEG_LVL_MAX as usize] = |
| 268 | [true, true, true, true, true, false, false, false]; |
| 269 | |
| 270 | use crate::context::TxClass::*; |
| 271 | |
| 272 | pub static tx_type_to_class: [TxClass; TX_TYPES] = [ |
| 273 | TX_CLASS_2D, // DCT_DCT |
| 274 | TX_CLASS_2D, // ADST_DCT |
| 275 | TX_CLASS_2D, // DCT_ADST |
| 276 | TX_CLASS_2D, // ADST_ADST |
| 277 | TX_CLASS_2D, // FLIPADST_DCT |
| 278 | TX_CLASS_2D, // DCT_FLIPADST |
| 279 | TX_CLASS_2D, // FLIPADST_FLIPADST |
| 280 | TX_CLASS_2D, // ADST_FLIPADST |
| 281 | TX_CLASS_2D, // FLIPADST_ADST |
| 282 | TX_CLASS_2D, // IDTX |
| 283 | TX_CLASS_VERT, // V_DCT |
| 284 | TX_CLASS_HORIZ, // H_DCT |
| 285 | TX_CLASS_VERT, // V_ADST |
| 286 | TX_CLASS_HORIZ, // H_ADST |
| 287 | TX_CLASS_VERT, // V_FLIPADST |
| 288 | TX_CLASS_HORIZ, // H_FLIPADST |
| 289 | ]; |
| 290 | |
| 291 | pub static eob_to_pos_small: [u8; 33] = [ |
| 292 | 0, 1, 2, // 0-2 |
| 293 | 3, 3, // 3-4 |
| 294 | 4, 4, 4, 4, // 5-8 |
| 295 | 5, 5, 5, 5, 5, 5, 5, 5, // 9-16 |
| 296 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 17-32 |
| 297 | ]; |
| 298 | |
| 299 | pub static eob_to_pos_large: [u8; 17] = [ |
| 300 | 6, // place holder |
| 301 | 7, // 33-64 |
| 302 | 8, 8, // 65-128 |
| 303 | 9, 9, 9, 9, // 129-256 |
| 304 | 10, 10, 10, 10, 10, 10, 10, 10, // 257-512 |
| 305 | 11, // 513- |
| 306 | ]; |
| 307 | |
| 308 | pub static k_eob_group_start: [u16; 12] = |
| 309 | [0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513]; |
| 310 | pub static k_eob_offset_bits: [u16; 12] = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; |
| 311 | |
| 312 | // The ctx offset table when TX is TX_CLASS_2D. |
| 313 | // TX col and row indices are clamped to 4 |
| 314 | |
| 315 | #[rustfmt::skip] |
| 316 | pub static av1_nz_map_ctx_offset: [[[i8; 5]; 5]; TxSize::TX_SIZES_ALL] = [ |
| 317 | // TX_4X4 |
| 318 | [ |
| 319 | [ 0, 1, 6, 6, 0], |
| 320 | [ 1, 6, 6, 21, 0], |
| 321 | [ 6, 6, 21, 21, 0], |
| 322 | [ 6, 21, 21, 21, 0], |
| 323 | [ 0, 0, 0, 0, 0] |
| 324 | ], |
| 325 | // TX_8X8 |
| 326 | [ |
| 327 | [ 0, 1, 6, 6, 21], |
| 328 | [ 1, 6, 6, 21, 21], |
| 329 | [ 6, 6, 21, 21, 21], |
| 330 | [ 6, 21, 21, 21, 21], |
| 331 | [21, 21, 21, 21, 21] |
| 332 | ], |
| 333 | // TX_16X16 |
| 334 | [ |
| 335 | [ 0, 1, 6, 6, 21], |
| 336 | [ 1, 6, 6, 21, 21], |
| 337 | [ 6, 6, 21, 21, 21], |
| 338 | [ 6, 21, 21, 21, 21], |
| 339 | [21, 21, 21, 21, 21] |
| 340 | ], |
| 341 | // TX_32X32 |
| 342 | [ |
| 343 | [ 0, 1, 6, 6, 21], |
| 344 | [ 1, 6, 6, 21, 21], |
| 345 | [ 6, 6, 21, 21, 21], |
| 346 | [ 6, 21, 21, 21, 21], |
| 347 | [21, 21, 21, 21, 21] |
| 348 | ], |
| 349 | // TX_64X64 |
| 350 | [ |
| 351 | [ 0, 1, 6, 6, 21], |
| 352 | [ 1, 6, 6, 21, 21], |
| 353 | [ 6, 6, 21, 21, 21], |
| 354 | [ 6, 21, 21, 21, 21], |
| 355 | [21, 21, 21, 21, 21] |
| 356 | ], |
| 357 | // TX_4X8 |
| 358 | [ |
| 359 | [ 0, 11, 11, 11, 0], |
| 360 | [11, 11, 11, 11, 0], |
| 361 | [ 6, 6, 21, 21, 0], |
| 362 | [ 6, 21, 21, 21, 0], |
| 363 | [21, 21, 21, 21, 0] |
| 364 | ], |
| 365 | // TX_8X4 |
| 366 | [ |
| 367 | [ 0, 16, 6, 6, 21], |
| 368 | [16, 16, 6, 21, 21], |
| 369 | [16, 16, 21, 21, 21], |
| 370 | [16, 16, 21, 21, 21], |
| 371 | [ 0, 0, 0, 0, 0] |
| 372 | ], |
| 373 | // TX_8X16 |
| 374 | [ |
| 375 | [ 0, 11, 11, 11, 11], |
| 376 | [11, 11, 11, 11, 11], |
| 377 | [ 6, 6, 21, 21, 21], |
| 378 | [ 6, 21, 21, 21, 21], |
| 379 | [21, 21, 21, 21, 21] |
| 380 | ], |
| 381 | // TX_16X8 |
| 382 | [ |
| 383 | [ 0, 16, 6, 6, 21], |
| 384 | [16, 16, 6, 21, 21], |
| 385 | [16, 16, 21, 21, 21], |
| 386 | [16, 16, 21, 21, 21], |
| 387 | [16, 16, 21, 21, 21] |
| 388 | ], |
| 389 | // TX_16X32 |
| 390 | [ |
| 391 | [ 0, 11, 11, 11, 11], |
| 392 | [11, 11, 11, 11, 11], |
| 393 | [ 6, 6, 21, 21, 21], |
| 394 | [ 6, 21, 21, 21, 21], |
| 395 | [21, 21, 21, 21, 21] |
| 396 | ], |
| 397 | // TX_32X16 |
| 398 | [ |
| 399 | [ 0, 16, 6, 6, 21], |
| 400 | [16, 16, 6, 21, 21], |
| 401 | [16, 16, 21, 21, 21], |
| 402 | [16, 16, 21, 21, 21], |
| 403 | [16, 16, 21, 21, 21] |
| 404 | ], |
| 405 | // TX_32X64 |
| 406 | [ |
| 407 | [ 0, 11, 11, 11, 11], |
| 408 | [11, 11, 11, 11, 11], |
| 409 | [ 6, 6, 21, 21, 21], |
| 410 | [ 6, 21, 21, 21, 21], |
| 411 | [21, 21, 21, 21, 21] |
| 412 | ], |
| 413 | // TX_64X32 |
| 414 | [ |
| 415 | [ 0, 16, 6, 6, 21], |
| 416 | [16, 16, 6, 21, 21], |
| 417 | [16, 16, 21, 21, 21], |
| 418 | [16, 16, 21, 21, 21], |
| 419 | [16, 16, 21, 21, 21] |
| 420 | ], |
| 421 | // TX_4X16 |
| 422 | [ |
| 423 | [ 0, 11, 11, 11, 0], |
| 424 | [11, 11, 11, 11, 0], |
| 425 | [ 6, 6, 21, 21, 0], |
| 426 | [ 6, 21, 21, 21, 0], |
| 427 | [21, 21, 21, 21, 0] |
| 428 | ], |
| 429 | // TX_16X4 |
| 430 | [ |
| 431 | [ 0, 16, 6, 6, 21], |
| 432 | [16, 16, 6, 21, 21], |
| 433 | [16, 16, 21, 21, 21], |
| 434 | [16, 16, 21, 21, 21], |
| 435 | [ 0, 0, 0, 0, 0] |
| 436 | ], |
| 437 | // TX_8X32 |
| 438 | [ |
| 439 | [ 0, 11, 11, 11, 11], |
| 440 | [11, 11, 11, 11, 11], |
| 441 | [ 6, 6, 21, 21, 21], |
| 442 | [ 6, 21, 21, 21, 21], |
| 443 | [21, 21, 21, 21, 21] |
| 444 | ], |
| 445 | // TX_32X8 |
| 446 | [ |
| 447 | [ 0, 16, 6, 6, 21], |
| 448 | [16, 16, 6, 21, 21], |
| 449 | [16, 16, 21, 21, 21], |
| 450 | [16, 16, 21, 21, 21], |
| 451 | [16, 16, 21, 21, 21] |
| 452 | ], |
| 453 | // TX_16X64 |
| 454 | [ |
| 455 | [ 0, 11, 11, 11, 11], |
| 456 | [11, 11, 11, 11, 11], |
| 457 | [ 6, 6, 21, 21, 21], |
| 458 | [ 6, 21, 21, 21, 21], |
| 459 | [21, 21, 21, 21, 21] |
| 460 | ], |
| 461 | // TX_64X16 |
| 462 | [ |
| 463 | [ 0, 16, 6, 6, 21], |
| 464 | [16, 16, 6, 21, 21], |
| 465 | [16, 16, 21, 21, 21], |
| 466 | [16, 16, 21, 21, 21], |
| 467 | [16, 16, 21, 21, 21] |
| 468 | ] |
| 469 | ]; |
| 470 | |
| 471 | const NZ_MAP_CTX_0: usize = SIG_COEF_CONTEXTS_2D; |
| 472 | const NZ_MAP_CTX_5: usize = NZ_MAP_CTX_0 + 5; |
| 473 | const NZ_MAP_CTX_10: usize = NZ_MAP_CTX_0 + 10; |
| 474 | |
| 475 | pub static nz_map_ctx_offset_1d: [usize; 32] = [ |
| 476 | NZ_MAP_CTX_0, |
| 477 | NZ_MAP_CTX_5, |
| 478 | NZ_MAP_CTX_10, |
| 479 | NZ_MAP_CTX_10, |
| 480 | NZ_MAP_CTX_10, |
| 481 | NZ_MAP_CTX_10, |
| 482 | NZ_MAP_CTX_10, |
| 483 | NZ_MAP_CTX_10, |
| 484 | NZ_MAP_CTX_10, |
| 485 | NZ_MAP_CTX_10, |
| 486 | NZ_MAP_CTX_10, |
| 487 | NZ_MAP_CTX_10, |
| 488 | NZ_MAP_CTX_10, |
| 489 | NZ_MAP_CTX_10, |
| 490 | NZ_MAP_CTX_10, |
| 491 | NZ_MAP_CTX_10, |
| 492 | NZ_MAP_CTX_10, |
| 493 | NZ_MAP_CTX_10, |
| 494 | NZ_MAP_CTX_10, |
| 495 | NZ_MAP_CTX_10, |
| 496 | NZ_MAP_CTX_10, |
| 497 | NZ_MAP_CTX_10, |
| 498 | NZ_MAP_CTX_10, |
| 499 | NZ_MAP_CTX_10, |
| 500 | NZ_MAP_CTX_10, |
| 501 | NZ_MAP_CTX_10, |
| 502 | NZ_MAP_CTX_10, |
| 503 | NZ_MAP_CTX_10, |
| 504 | NZ_MAP_CTX_10, |
| 505 | NZ_MAP_CTX_10, |
| 506 | NZ_MAP_CTX_10, |
| 507 | NZ_MAP_CTX_10, |
| 508 | ]; |
| 509 | |
| 510 | const CONTEXT_MAG_POSITION_NUM: usize = 3; |
| 511 | |
| 512 | static mag_ref_offset_with_txclass: [[[usize; 2]; CONTEXT_MAG_POSITION_NUM]; |
| 513 | 3] = [ |
| 514 | [[0, 1], [1, 0], [1, 1]], |
| 515 | [[0, 1], [1, 0], [0, 2]], |
| 516 | [[0, 1], [1, 0], [2, 0]], |
| 517 | ]; |
| 518 | |
| 519 | // End of Level Map |
| 520 | |
| 521 | pub struct TXB_CTX { |
| 522 | pub txb_skip_ctx: usize, |
| 523 | pub dc_sign_ctx: usize, |
| 524 | } |
| 525 | |
| 526 | impl<'a> ContextWriter<'a> { |
| 527 | /// # Panics |
| 528 | /// |
| 529 | /// - If an invalid combination of `tx_type` and `tx_size` is passed |
| 530 | pub fn write_tx_type<W: Writer>( |
| 531 | &mut self, w: &mut W, tx_size: TxSize, tx_type: TxType, |
| 532 | y_mode: PredictionMode, is_inter: bool, use_reduced_tx_set: bool, |
| 533 | ) { |
| 534 | let square_tx_size = tx_size.sqr(); |
| 535 | let tx_set = get_tx_set(tx_size, is_inter, use_reduced_tx_set); |
| 536 | let num_tx_types = num_tx_set[tx_set as usize]; |
| 537 | |
| 538 | if num_tx_types > 1 { |
| 539 | let tx_set_index = |
| 540 | get_tx_set_index(tx_size, is_inter, use_reduced_tx_set); |
| 541 | assert!(tx_set_index > 0); |
| 542 | assert!(av1_tx_used[tx_set as usize][tx_type as usize] != 0); |
| 543 | |
| 544 | if is_inter { |
| 545 | let s = av1_tx_ind[tx_set as usize][tx_type as usize] as u32; |
| 546 | if tx_set_index == 1 { |
| 547 | let cdf = &self.fc.inter_tx_1_cdf[square_tx_size as usize]; |
| 548 | symbol_with_update!(self, w, s, cdf); |
| 549 | } else if tx_set_index == 2 { |
| 550 | let cdf = &self.fc.inter_tx_2_cdf[square_tx_size as usize]; |
| 551 | symbol_with_update!(self, w, s, cdf); |
| 552 | } else { |
| 553 | let cdf = &self.fc.inter_tx_3_cdf[square_tx_size as usize]; |
| 554 | symbol_with_update!(self, w, s, cdf); |
| 555 | } |
| 556 | } else { |
| 557 | let intra_dir = y_mode; |
| 558 | // TODO: Once use_filter_intra is enabled, |
| 559 | // intra_dir = |
| 560 | // fimode_to_intradir[mbmi->filter_intra_mode_info.filter_intra_mode]; |
| 561 | |
| 562 | let s = av1_tx_ind[tx_set as usize][tx_type as usize] as u32; |
| 563 | if tx_set_index == 1 { |
| 564 | let cdf = &self.fc.intra_tx_1_cdf[square_tx_size as usize] |
| 565 | [intra_dir as usize]; |
| 566 | symbol_with_update!(self, w, s, cdf); |
| 567 | } else { |
| 568 | let cdf = &self.fc.intra_tx_2_cdf[square_tx_size as usize] |
| 569 | [intra_dir as usize]; |
| 570 | symbol_with_update!(self, w, s, cdf); |
| 571 | } |
| 572 | } |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | fn get_tx_size_context( |
| 577 | &self, bo: TileBlockOffset, bsize: BlockSize, |
| 578 | ) -> usize { |
| 579 | let max_tx_size = max_txsize_rect_lookup[bsize as usize]; |
| 580 | let max_tx_wide = max_tx_size.width() as u8; |
| 581 | let max_tx_high = max_tx_size.height() as u8; |
| 582 | let has_above = bo.0.y > 0; |
| 583 | let has_left = bo.0.x > 0; |
| 584 | let mut above = self.bc.above_tx_context[bo.0.x] >= max_tx_wide; |
| 585 | let mut left = self.bc.left_tx_context[bo.y_in_sb()] >= max_tx_high; |
| 586 | |
| 587 | if has_above { |
| 588 | let above_blk = self.bc.blocks.above_of(bo); |
| 589 | if above_blk.is_inter() { |
| 590 | above = (above_blk.n4_w << MI_SIZE_LOG2) >= max_tx_wide; |
| 591 | }; |
| 592 | } |
| 593 | if has_left { |
| 594 | let left_blk = self.bc.blocks.left_of(bo); |
| 595 | if left_blk.is_inter() { |
| 596 | left = (left_blk.n4_h << MI_SIZE_LOG2) >= max_tx_high; |
| 597 | }; |
| 598 | } |
| 599 | if has_above && has_left { |
| 600 | return above as usize + left as usize; |
| 601 | }; |
| 602 | if has_above { |
| 603 | return above as usize; |
| 604 | }; |
| 605 | if has_left { |
| 606 | return left as usize; |
| 607 | }; |
| 608 | 0 |
| 609 | } |
| 610 | |
| 611 | pub fn write_tx_size_intra<W: Writer>( |
| 612 | &mut self, w: &mut W, bo: TileBlockOffset, bsize: BlockSize, |
| 613 | tx_size: TxSize, |
| 614 | ) { |
| 615 | fn tx_size_to_depth(tx_size: TxSize, bsize: BlockSize) -> usize { |
| 616 | let mut ctx_size = max_txsize_rect_lookup[bsize as usize]; |
| 617 | let mut depth: usize = 0; |
| 618 | while tx_size != ctx_size { |
| 619 | depth += 1; |
| 620 | ctx_size = sub_tx_size_map[ctx_size as usize]; |
| 621 | debug_assert!(depth <= MAX_TX_DEPTH); |
| 622 | } |
| 623 | depth |
| 624 | } |
| 625 | fn bsize_to_max_depth(bsize: BlockSize) -> usize { |
| 626 | let mut tx_size: TxSize = max_txsize_rect_lookup[bsize as usize]; |
| 627 | let mut depth = 0; |
| 628 | while depth < MAX_TX_DEPTH && tx_size != TX_4X4 { |
| 629 | depth += 1; |
| 630 | tx_size = sub_tx_size_map[tx_size as usize]; |
| 631 | debug_assert!(depth <= MAX_TX_DEPTH); |
| 632 | } |
| 633 | depth |
| 634 | } |
| 635 | fn bsize_to_tx_size_cat(bsize: BlockSize) -> usize { |
| 636 | let mut tx_size: TxSize = max_txsize_rect_lookup[bsize as usize]; |
| 637 | debug_assert!(tx_size != TX_4X4); |
| 638 | let mut depth = 0; |
| 639 | while tx_size != TX_4X4 { |
| 640 | depth += 1; |
| 641 | tx_size = sub_tx_size_map[tx_size as usize]; |
| 642 | } |
| 643 | debug_assert!(depth <= MAX_TX_CATS); |
| 644 | |
| 645 | depth - 1 |
| 646 | } |
| 647 | |
| 648 | debug_assert!(!self.bc.blocks[bo].is_inter()); |
| 649 | debug_assert!(bsize > BlockSize::BLOCK_4X4); |
| 650 | |
| 651 | let tx_size_ctx = self.get_tx_size_context(bo, bsize); |
| 652 | let depth = tx_size_to_depth(tx_size, bsize); |
| 653 | |
| 654 | let max_depths = bsize_to_max_depth(bsize); |
| 655 | let tx_size_cat = bsize_to_tx_size_cat(bsize); |
| 656 | |
| 657 | debug_assert!(depth <= max_depths); |
| 658 | debug_assert!(!tx_size.is_rect() || bsize.is_rect_tx_allowed()); |
| 659 | |
| 660 | if tx_size_cat > 0 { |
| 661 | let cdf = &self.fc.tx_size_cdf[tx_size_cat - 1][tx_size_ctx]; |
| 662 | symbol_with_update!(self, w, depth as u32, cdf); |
| 663 | } else { |
| 664 | let cdf = &self.fc.tx_size_8x8_cdf[tx_size_ctx]; |
| 665 | symbol_with_update!(self, w, depth as u32, cdf); |
| 666 | } |
| 667 | } |
| 668 | |
| 669 | // Based on https://aomediacodec.github.io/av1-spec/#cdf-selection-process |
| 670 | // Used to decide the cdf (context) for txfm_split |
| 671 | fn get_above_tx_width( |
| 672 | &self, bo: TileBlockOffset, _bsize: BlockSize, _tx_size: TxSize, |
| 673 | first_tx: bool, |
| 674 | ) -> usize { |
| 675 | let has_above = bo.0.y > 0; |
| 676 | if first_tx { |
| 677 | if !has_above { |
| 678 | return 64; |
| 679 | } |
| 680 | let above_blk = self.bc.blocks.above_of(bo); |
| 681 | if above_blk.skip && above_blk.is_inter() { |
| 682 | return above_blk.bsize.width(); |
| 683 | } |
| 684 | } |
| 685 | self.bc.above_tx_context[bo.0.x] as usize |
| 686 | } |
| 687 | |
| 688 | fn get_left_tx_height( |
| 689 | &self, bo: TileBlockOffset, _bsize: BlockSize, _tx_size: TxSize, |
| 690 | first_tx: bool, |
| 691 | ) -> usize { |
| 692 | let has_left = bo.0.x > 0; |
| 693 | if first_tx { |
| 694 | if !has_left { |
| 695 | return 64; |
| 696 | } |
| 697 | let left_blk = self.bc.blocks.left_of(bo); |
| 698 | if left_blk.skip && left_blk.is_inter() { |
| 699 | return left_blk.bsize.height(); |
| 700 | } |
| 701 | } |
| 702 | self.bc.left_tx_context[bo.y_in_sb()] as usize |
| 703 | } |
| 704 | |
| 705 | fn txfm_partition_context( |
| 706 | &self, bo: TileBlockOffset, bsize: BlockSize, tx_size: TxSize, tbx: usize, |
| 707 | tby: usize, |
| 708 | ) -> usize { |
| 709 | debug_assert!(tx_size > TX_4X4); |
| 710 | debug_assert!(bsize > BlockSize::BLOCK_4X4); |
| 711 | |
| 712 | // TODO: from 2nd level partition, must know whether the tx block is the topmost(or leftmost) within a partition |
| 713 | let above = (self.get_above_tx_width(bo, bsize, tx_size, tby == 0) |
| 714 | < tx_size.width()) as usize; |
| 715 | let left = (self.get_left_tx_height(bo, bsize, tx_size, tbx == 0) |
| 716 | < tx_size.height()) as usize; |
| 717 | |
| 718 | let max_tx_size: TxSize = bsize.tx_size().sqr_up(); |
| 719 | let category: usize = (tx_size.sqr_up() != max_tx_size) as usize |
| 720 | + (TxSize::TX_SIZES - 1 - max_tx_size as usize) * 2; |
| 721 | |
| 722 | debug_assert!(category < TXFM_PARTITION_CONTEXTS); |
| 723 | |
| 724 | category * 3 + above + left |
| 725 | } |
| 726 | |
| 727 | pub fn write_tx_size_inter<W: Writer>( |
| 728 | &mut self, w: &mut W, bo: TileBlockOffset, bsize: BlockSize, |
| 729 | tx_size: TxSize, txfm_split: bool, tbx: usize, tby: usize, depth: usize, |
| 730 | ) { |
| 731 | if bo.0.x >= self.bc.blocks.cols() || bo.0.y >= self.bc.blocks.rows() { |
| 732 | return; |
| 733 | } |
| 734 | debug_assert!(self.bc.blocks[bo].is_inter()); |
| 735 | debug_assert!(bsize > BlockSize::BLOCK_4X4); |
| 736 | debug_assert!(!tx_size.is_rect() || bsize.is_rect_tx_allowed()); |
| 737 | |
| 738 | if tx_size != TX_4X4 && depth < MAX_VARTX_DEPTH { |
| 739 | let ctx = self.txfm_partition_context(bo, bsize, tx_size, tbx, tby); |
| 740 | let cdf = &self.fc.txfm_partition_cdf[ctx]; |
| 741 | symbol_with_update!(self, w, txfm_split as u32, cdf); |
| 742 | } else { |
| 743 | debug_assert!(!txfm_split); |
| 744 | } |
| 745 | |
| 746 | if !txfm_split { |
| 747 | self.bc.update_tx_size_context(bo, tx_size.block_size(), tx_size, false); |
| 748 | } else { |
| 749 | // if txfm_split == true, split one level only |
| 750 | let split_tx_size = sub_tx_size_map[tx_size as usize]; |
| 751 | let bw = bsize.width_mi() / split_tx_size.width_mi(); |
| 752 | let bh = bsize.height_mi() / split_tx_size.height_mi(); |
| 753 | |
| 754 | for by in 0..bh { |
| 755 | for bx in 0..bw { |
| 756 | let tx_bo = TileBlockOffset(BlockOffset { |
| 757 | x: bo.0.x + bx * split_tx_size.width_mi(), |
| 758 | y: bo.0.y + by * split_tx_size.height_mi(), |
| 759 | }); |
| 760 | self.write_tx_size_inter( |
| 761 | w, |
| 762 | tx_bo, |
| 763 | bsize, |
| 764 | split_tx_size, |
| 765 | false, |
| 766 | bx, |
| 767 | by, |
| 768 | depth + 1, |
| 769 | ); |
| 770 | } |
| 771 | } |
| 772 | } |
| 773 | } |
| 774 | |
| 775 | #[inline ] |
| 776 | pub const fn get_txsize_entropy_ctx(tx_size: TxSize) -> usize { |
| 777 | (tx_size.sqr() as usize + tx_size.sqr_up() as usize + 1) >> 1 |
| 778 | } |
| 779 | |
| 780 | pub fn txb_init_levels<T: Coefficient>( |
| 781 | &self, coeffs: &[T], height: usize, levels: &mut [u8], |
| 782 | levels_stride: usize, |
| 783 | ) { |
| 784 | // Coefficients and levels are transposed from how they work in the spec |
| 785 | for (coeffs_col, levels_col) in |
| 786 | coeffs.chunks_exact(height).zip(levels.chunks_exact_mut(levels_stride)) |
| 787 | { |
| 788 | for (coeff, level) in coeffs_col.iter().zip(levels_col) { |
| 789 | *level = coeff.abs().min(T::cast_from(127)).as_(); |
| 790 | } |
| 791 | } |
| 792 | } |
| 793 | |
| 794 | // Since the coefficients and levels are transposed in relation to how they |
| 795 | // work in the spec, use the log of block height in our calculations instead |
| 796 | // of block width. |
| 797 | #[inline ] |
| 798 | pub const fn get_txb_bhl(tx_size: TxSize) -> usize { |
| 799 | av1_get_coded_tx_size(tx_size).height_log2() |
| 800 | } |
| 801 | |
| 802 | /// Returns `(eob_pt, eob_extra)` |
| 803 | /// |
| 804 | /// # Panics |
| 805 | /// |
| 806 | /// - If `eob` is prior to the start of the group |
| 807 | #[inline ] |
| 808 | pub fn get_eob_pos_token(eob: u16) -> (u32, u32) { |
| 809 | let t = if eob < 33 { |
| 810 | eob_to_pos_small[usize::from(eob)] as u32 |
| 811 | } else { |
| 812 | let e = usize::from(cmp::min((eob - 1) >> 5, 16)); |
| 813 | eob_to_pos_large[e] as u32 |
| 814 | }; |
| 815 | assert!(eob as i32 >= k_eob_group_start[t as usize] as i32); |
| 816 | let extra = eob as u32 - k_eob_group_start[t as usize] as u32; |
| 817 | |
| 818 | (t, extra) |
| 819 | } |
| 820 | |
| 821 | pub fn get_nz_mag(levels: &[u8], bhl: usize, tx_class: TxClass) -> usize { |
| 822 | // Levels are transposed from how they work in the spec |
| 823 | |
| 824 | // May version. |
| 825 | // Note: AOMMIN(level, 3) is useless for decoder since level < 3. |
| 826 | let mut mag = cmp::min(3, levels[1]); // { 1, 0 } |
| 827 | mag += cmp::min(3, levels[(1 << bhl) + TX_PAD_HOR]); // { 0, 1 } |
| 828 | |
| 829 | if tx_class == TX_CLASS_2D { |
| 830 | mag += cmp::min(3, levels[(1 << bhl) + TX_PAD_HOR + 1]); // { 1, 1 } |
| 831 | mag += cmp::min(3, levels[2]); // { 2, 0 } |
| 832 | mag += cmp::min(3, levels[(2 << bhl) + (2 << TX_PAD_HOR_LOG2)]); // { 0, 2 } |
| 833 | } else if tx_class == TX_CLASS_VERT { |
| 834 | mag += cmp::min(3, levels[2]); // { 2, 0 } |
| 835 | mag += cmp::min(3, levels[3]); // { 3, 0 } |
| 836 | mag += cmp::min(3, levels[4]); // { 4, 0 } |
| 837 | } else { |
| 838 | mag += cmp::min(3, levels[(2 << bhl) + (2 << TX_PAD_HOR_LOG2)]); // { 0, 2 } |
| 839 | mag += cmp::min(3, levels[(3 << bhl) + (3 << TX_PAD_HOR_LOG2)]); // { 0, 3 } |
| 840 | mag += cmp::min(3, levels[(4 << bhl) + (4 << TX_PAD_HOR_LOG2)]); // { 0, 4 } |
| 841 | } |
| 842 | |
| 843 | mag as usize |
| 844 | } |
| 845 | |
| 846 | fn get_nz_map_ctx_from_stats( |
| 847 | stats: usize, |
| 848 | coeff_idx: usize, // raster order |
| 849 | bhl: usize, |
| 850 | tx_size: TxSize, |
| 851 | tx_class: TxClass, |
| 852 | ) -> usize { |
| 853 | if (tx_class as u32 | coeff_idx as u32) == 0 { |
| 854 | return 0; |
| 855 | }; |
| 856 | |
| 857 | // Coefficients are transposed from how they work in the spec |
| 858 | let col: usize = coeff_idx >> bhl; |
| 859 | let row: usize = coeff_idx - (col << bhl); |
| 860 | |
| 861 | let ctx = ((stats + 1) >> 1).min(4); |
| 862 | |
| 863 | ctx |
| 864 | + match tx_class { |
| 865 | TX_CLASS_2D => { |
| 866 | // This is the algorithm to generate table av1_nz_map_ctx_offset[]. |
| 867 | // const int width = tx_size_wide[tx_size]; |
| 868 | // const int height = tx_size_high[tx_size]; |
| 869 | // if (width < height) { |
| 870 | // if (row < 2) return 11 + ctx; |
| 871 | // } else if (width > height) { |
| 872 | // if (col < 2) return 16 + ctx; |
| 873 | // } |
| 874 | // if (row + col < 2) return ctx + 1; |
| 875 | // if (row + col < 4) return 5 + ctx + 1; |
| 876 | // return 21 + ctx; |
| 877 | av1_nz_map_ctx_offset[tx_size as usize][cmp::min(row, 4)] |
| 878 | [cmp::min(col, 4)] as usize |
| 879 | } |
| 880 | TX_CLASS_HORIZ => nz_map_ctx_offset_1d[col], |
| 881 | TX_CLASS_VERT => nz_map_ctx_offset_1d[row], |
| 882 | } |
| 883 | } |
| 884 | |
| 885 | fn get_nz_map_ctx( |
| 886 | levels: &[u8], coeff_idx: usize, bhl: usize, area: usize, scan_idx: usize, |
| 887 | is_eob: bool, tx_size: TxSize, tx_class: TxClass, |
| 888 | ) -> usize { |
| 889 | if is_eob { |
| 890 | if scan_idx == 0 { |
| 891 | return 0; |
| 892 | } |
| 893 | if scan_idx <= area / 8 { |
| 894 | return 1; |
| 895 | } |
| 896 | if scan_idx <= area / 4 { |
| 897 | return 2; |
| 898 | } |
| 899 | return 3; |
| 900 | } |
| 901 | |
| 902 | // Levels are transposed from how they work in the spec |
| 903 | let padded_idx = coeff_idx + ((coeff_idx >> bhl) << TX_PAD_HOR_LOG2); |
| 904 | let stats = Self::get_nz_mag(&levels[padded_idx..], bhl, tx_class); |
| 905 | |
| 906 | Self::get_nz_map_ctx_from_stats(stats, coeff_idx, bhl, tx_size, tx_class) |
| 907 | } |
| 908 | |
| 909 | /// `coeff_contexts_no_scan` is not in the scan order. |
| 910 | /// Value for `pos = scan[i]` is at `coeff[i]`, not at `coeff[pos]`. |
| 911 | pub fn get_nz_map_contexts<'c>( |
| 912 | &self, levels: &mut [u8], scan: &[u16], eob: u16, tx_size: TxSize, |
| 913 | tx_class: TxClass, coeff_contexts_no_scan: &'c mut [MaybeUninit<i8>], |
| 914 | ) -> &'c mut [i8] { |
| 915 | let bhl = Self::get_txb_bhl(tx_size); |
| 916 | let area = av1_get_coded_tx_size(tx_size).area(); |
| 917 | |
| 918 | let scan = &scan[..usize::from(eob)]; |
| 919 | let coeffs = &mut coeff_contexts_no_scan[..usize::from(eob)]; |
| 920 | for (i, (coeff, pos)) in |
| 921 | coeffs.iter_mut().zip(scan.iter().copied()).enumerate() |
| 922 | { |
| 923 | coeff.write(Self::get_nz_map_ctx( |
| 924 | levels, |
| 925 | pos as usize, |
| 926 | bhl, |
| 927 | area, |
| 928 | i, |
| 929 | i == usize::from(eob) - 1, |
| 930 | tx_size, |
| 931 | tx_class, |
| 932 | ) as i8); |
| 933 | } |
| 934 | // SAFETY: every element has been initialized |
| 935 | unsafe { slice_assume_init_mut(coeffs) } |
| 936 | } |
| 937 | |
| 938 | pub fn get_br_ctx( |
| 939 | levels: &[u8], |
| 940 | coeff_idx: usize, // raster order |
| 941 | bhl: usize, |
| 942 | tx_class: TxClass, |
| 943 | ) -> usize { |
| 944 | // Coefficients and levels are transposed from how they work in the spec |
| 945 | let col: usize = coeff_idx >> bhl; |
| 946 | let row: usize = coeff_idx - (col << bhl); |
| 947 | let stride: usize = (1 << bhl) + TX_PAD_HOR; |
| 948 | let pos: usize = col * stride + row; |
| 949 | let mut mag: usize = (levels[pos + 1] + levels[pos + stride]) as usize; |
| 950 | |
| 951 | match tx_class { |
| 952 | TX_CLASS_2D => { |
| 953 | mag += levels[pos + stride + 1] as usize; |
| 954 | mag = cmp::min((mag + 1) >> 1, 6); |
| 955 | if coeff_idx == 0 { |
| 956 | return mag; |
| 957 | } |
| 958 | if (row < 2) && (col < 2) { |
| 959 | return mag + 7; |
| 960 | } |
| 961 | } |
| 962 | TX_CLASS_HORIZ => { |
| 963 | mag += levels[pos + (stride << 1)] as usize; |
| 964 | mag = cmp::min((mag + 1) >> 1, 6); |
| 965 | if coeff_idx == 0 { |
| 966 | return mag; |
| 967 | } |
| 968 | if col == 0 { |
| 969 | return mag + 7; |
| 970 | } |
| 971 | } |
| 972 | TX_CLASS_VERT => { |
| 973 | mag += levels[pos + 2] as usize; |
| 974 | mag = cmp::min((mag + 1) >> 1, 6); |
| 975 | if coeff_idx == 0 { |
| 976 | return mag; |
| 977 | } |
| 978 | if row == 0 { |
| 979 | return mag + 7; |
| 980 | } |
| 981 | } |
| 982 | } |
| 983 | |
| 984 | mag + 14 |
| 985 | } |
| 986 | } |
| 987 | |