1use super::*;
11use crate::predict::PredictionMode;
12use crate::predict::PredictionMode::*;
13use crate::transform::TxType::*;
14use std::mem::MaybeUninit;
15
16pub const MAX_TX_SIZE: usize = 64;
17
18pub const MAX_CODED_TX_SIZE: usize = 32;
19pub const MAX_CODED_TX_SQUARE: usize = MAX_CODED_TX_SIZE * MAX_CODED_TX_SIZE;
20
21pub const TX_SIZE_SQR_CONTEXTS: usize = 4; pub const TX_SETS: usize = 6;
24pub const TX_SETS_INTRA: usize = 3;
25pub const TX_SETS_INTER: usize = 4;
26
27pub const INTRA_MODES: usize = 13;
28pub const UV_INTRA_MODES: usize = 14;
29
30const MAX_VARTX_DEPTH: usize = 2;
31
32pub const TXFM_PARTITION_CONTEXTS: usize =
33  (TxSize::TX_SIZES - TxSize::TX_8X8 as usize) * 6 - 3;
34
35pub static num_tx_set: [usize; TX_SETS] = [1, 2, 5, 7, 12, 16];
37pub 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
46static tx_set_index_intra: [i8; TX_SETS] = [0, -1, 2, 1, -1, -1];
48static tx_set_index_inter: [i8; TX_SETS] = [0, 3, -1, -1, 2, 1];
50
51pub 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
60pub static max_txsize_rect_lookup: [TxSize; BlockSize::BLOCK_SIZES_ALL] = [
61  TX_4X4,   TX_4X8,   TX_8X4,   TX_8X8,   TX_8X16,  TX_16X8,  TX_16X16, TX_16X32, TX_32X16, TX_32X32, TX_32X64, TX_64X32, TX_64X64, TX_64X64, TX_64X64, TX_64X64, TX_4X16,  TX_16X4,  TX_8X32,  TX_32X8,  TX_16X64, TX_64X16, ];
84
85pub static sub_tx_size_map: [TxSize; TxSize::TX_SIZES_ALL] = [
86  TX_4X4,   TX_4X4,   TX_8X8,   TX_16X16, TX_32X32, TX_4X4,   TX_4X4,   TX_8X8,   TX_8X8,   TX_16X16, TX_16X16, TX_32X32, TX_32X32, TX_4X8,   TX_8X4,   TX_8X16,  TX_16X8,  TX_16X32, TX_32X16, ];
106
107#[inline]
108pub 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 = bsize.width_mi();
117  let bh = 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
123pub fn get_tx_set(
124  tx_size: TxSize, is_inter: bool, use_reduced_set: bool,
125) -> TxSet {
126  let tx_size_sqr_up = tx_size.sqr_up();
127  let tx_size_sqr = 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
150pub fn get_tx_set_index(
151  tx_size: TxSize, is_inter: bool, use_reduced_set: bool,
152) -> i8 {
153  let set_type = 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
162static intra_mode_to_tx_type_context: [TxType; INTRA_MODES] = [
163  DCT_DCT,   ADST_DCT,  DCT_ADST,  DCT_DCT,   ADST_ADST, ADST_DCT,  DCT_ADST,  DCT_ADST,  ADST_DCT,  ADST_ADST, ADST_DCT,  DCT_ADST,  ADST_ADST, ];
177
178static uv2y: [PredictionMode; UV_INTRA_MODES] = [
179  DC_PRED,       V_PRED,        H_PRED,        D45_PRED,      D135_PRED,     D113_PRED,     D157_PRED,     D203_PRED,     D67_PRED,      SMOOTH_PRED,   SMOOTH_V_PRED, SMOOTH_H_PRED, PAETH_PRED,    DC_PRED,       ];
194
195pub 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
199pub const TXB_SKIP_CONTEXTS: usize = 13;
201
202pub const EOB_COEF_CONTEXTS: usize = 9;
203
204const SIG_COEF_CONTEXTS_2D: usize = 26;
205const SIG_COEF_CONTEXTS_1D: usize = 16;
206pub const SIG_COEF_CONTEXTS_EOB: usize = 4;
207pub const SIG_COEF_CONTEXTS: usize =
208  SIG_COEF_CONTEXTS_2D + SIG_COEF_CONTEXTS_1D;
209
210const COEFF_BASE_CONTEXTS: usize = SIG_COEF_CONTEXTS;
211pub const DC_SIGN_CONTEXTS: usize = 3;
212
213const BR_TMP_OFFSET: usize = 12;
214const BR_REF_CAT: usize = 4;
215pub const LEVEL_CONTEXTS: usize = 21;
216
217pub const NUM_BASE_LEVELS: usize = 2;
218
219pub const BR_CDF_SIZE: usize = 4;
220pub const COEFF_BASE_RANGE: usize = 4 * (BR_CDF_SIZE - 1);
221
222pub const COEFF_CONTEXT_BITS: usize = 6;
223pub const COEFF_CONTEXT_MASK: usize = (1 << COEFF_CONTEXT_BITS) - 1;
224const MAX_BASE_BR_RANGE: usize = COEFF_BASE_RANGE + NUM_BASE_LEVELS + 1;
225
226const BASE_CONTEXT_POSITION_NUM: usize = 12;
227
228pub const TX_PAD_HOR_LOG2: usize = 2;
230pub const TX_PAD_HOR: usize = 4;
231pub const TX_PAD_TOP: usize = 2;
234pub const TX_PAD_BOTTOM: usize = 4;
235pub const TX_PAD_VER: usize = TX_PAD_TOP + TX_PAD_BOTTOM;
236const TX_PAD_END: usize = 16;
238pub 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
242const TX_CLASSES: usize = 3;
243
244#[derive(Copy, Clone, PartialEq, Eq)]
245pub 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)]
252pub enum SegLvl {
253  SEG_LVL_ALT_Q = 0,      SEG_LVL_ALT_LF_Y_V = 1, SEG_LVL_ALT_LF_Y_H = 2, SEG_LVL_ALT_LF_U = 3,   SEG_LVL_ALT_LF_V = 4,   SEG_LVL_REF_FRAME = 5,  SEG_LVL_SKIP = 6,       SEG_LVL_GLOBALMV = 7,
261  SEG_LVL_MAX = 8,
262}
263
264pub const seg_feature_bits: [u32; SegLvl::SEG_LVL_MAX as usize] =
265  [8, 6, 6, 6, 6, 3, 0, 0];
266
267pub const seg_feature_is_signed: [bool; SegLvl::SEG_LVL_MAX as usize] =
268  [true, true, true, true, true, false, false, false];
269
270use crate::context::TxClass::*;
271
272pub static tx_type_to_class: [TxClass; TX_TYPES] = [
273  TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_2D,    TX_CLASS_VERT,  TX_CLASS_HORIZ, TX_CLASS_VERT,  TX_CLASS_HORIZ, TX_CLASS_VERT,  TX_CLASS_HORIZ, ];
290
291pub static eob_to_pos_small: [u8; 33] = [
292  0, 1, 2, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ];
298
299pub static eob_to_pos_large: [u8; 17] = [
300  6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, ];
307
308pub static k_eob_group_start: [u16; 12] =
309  [0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513];
310pub static k_eob_offset_bits: [u16; 12] = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
311
312#[rustfmt::skip]
316pub static av1_nz_map_ctx_offset: [[[i8; 5]; 5]; TxSize::TX_SIZES_ALL] = [
317  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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  [
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
471const NZ_MAP_CTX_0: usize = SIG_COEF_CONTEXTS_2D;
472const NZ_MAP_CTX_5: usize = NZ_MAP_CTX_0 + 5;
473const NZ_MAP_CTX_10: usize = NZ_MAP_CTX_0 + 10;
474
475pub 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
510const CONTEXT_MAG_POSITION_NUM: usize = 3;
511
512static 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
519pub struct TXB_CTX {
522  pub txb_skip_ctx: usize,
523  pub dc_sign_ctx: usize,
524}
525
526impl ContextWriter<'_> {
527  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        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  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    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      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    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  #[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  #[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    let mut mag = cmp::min(3, levels[1]); mag += cmp::min(3, levels[(1 << bhl) + TX_PAD_HOR]); if tx_class == TX_CLASS_2D {
830      mag += cmp::min(3, levels[(1 << bhl) + TX_PAD_HOR + 1]); mag += cmp::min(3, levels[2]); mag += cmp::min(3, levels[(2 << bhl) + (2 << TX_PAD_HOR_LOG2)]); } else if tx_class == TX_CLASS_VERT {
834      mag += cmp::min(3, levels[2]); mag += cmp::min(3, levels[3]); mag += cmp::min(3, levels[4]); } else {
838      mag += cmp::min(3, levels[(2 << bhl) + (2 << TX_PAD_HOR_LOG2)]); mag += cmp::min(3, levels[(3 << bhl) + (3 << TX_PAD_HOR_LOG2)]); mag += cmp::min(3, levels[(4 << bhl) + (4 << TX_PAD_HOR_LOG2)]); }
842
843    mag as usize
844  }
845
846  fn get_nz_map_ctx_from_stats(
847    stats: usize,
848    coeff_idx: usize, 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    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          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    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  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    unsafe { slice_assume_init_mut(coeffs) }
936  }
937
938  pub fn get_br_ctx(
939    levels: &[u8],
940    coeff_idx: usize, bhl: usize,
942    tx_class: TxClass,
943  ) -> usize {
944    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}