use super::*;
use crate::predict::PredictionMode;
use crate::predict::PredictionMode::*;
use crate::transform::TxType::*;
use std::mem::MaybeUninit;
pub const MAX_TX_SIZE: usize = 64;
pub const MAX_CODED_TX_SIZE: usize = 32;
pub const MAX_CODED_TX_SQUARE: usize = MAX_CODED_TX_SIZE * MAX_CODED_TX_SIZE;
pub const TX_SIZE_SQR_CONTEXTS: usize = 4; pub const TX_SETS: usize = 6;
pub const TX_SETS_INTRA: usize = 3;
pub const TX_SETS_INTER: usize = 4;
pub const INTRA_MODES: usize = 13;
pub const UV_INTRA_MODES: usize = 14;
const MAX_VARTX_DEPTH: usize = 2;
pub const TXFM_PARTITION_CONTEXTS: usize =
(TxSize::TX_SIZES - TxSize::TX_8X8 as usize) * 6 - 3;
pub static num_tx_set: [usize; TX_SETS] = [1, 2, 5, 7, 12, 16];
pub static av1_tx_used: [[usize; TX_TYPES]; TX_SETS] = [
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
static tx_set_index_intra: [i8; TX_SETS] = [0, -1, 2, 1, -1, -1];
static tx_set_index_inter: [i8; TX_SETS] = [0, 3, -1, -1, 2, 1];
pub static av1_tx_ind: [[usize; TX_TYPES]; TX_SETS] = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 3, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 5, 6, 4, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, 0, 0],
[3, 4, 5, 8, 6, 7, 9, 10, 11, 0, 1, 2, 0, 0, 0, 0],
[7, 8, 9, 12, 10, 11, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6],
];
pub static max_txsize_rect_lookup: [TxSize; BlockSize::BLOCK_SIZES_ALL] = [
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, ];
pub static sub_tx_size_map: [TxSize; TxSize::TX_SIZES_ALL] = [
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, ];
#[inline]
pub fn has_chroma(
bo: TileBlockOffset, bsize: BlockSize, subsampling_x: usize,
subsampling_y: usize, chroma_sampling: ChromaSampling,
) -> bool {
if chroma_sampling == ChromaSampling::Cs400 {
return false;
};
let bw = bsize.width_mi();
let bh = bsize.height_mi();
((bo.0.x & 0x01) == 1 || (bw & 0x01) == 0 || subsampling_x == 0)
&& ((bo.0.y & 0x01) == 1 || (bh & 0x01) == 0 || subsampling_y == 0)
}
pub fn get_tx_set(
tx_size: TxSize, is_inter: bool, use_reduced_set: bool,
) -> TxSet {
let tx_size_sqr_up = tx_size.sqr_up();
let tx_size_sqr = tx_size.sqr();
if tx_size_sqr_up.block_size() > BlockSize::BLOCK_32X32 {
return TxSet::TX_SET_DCTONLY;
}
if is_inter {
if use_reduced_set || tx_size_sqr_up == TxSize::TX_32X32 {
TxSet::TX_SET_INTER_3
} else if tx_size_sqr == TxSize::TX_16X16 {
TxSet::TX_SET_INTER_2
} else {
TxSet::TX_SET_INTER_1
}
} else if tx_size_sqr_up == TxSize::TX_32X32 {
TxSet::TX_SET_DCTONLY
} else if use_reduced_set || tx_size_sqr == TxSize::TX_16X16 {
TxSet::TX_SET_INTRA_2
} else {
TxSet::TX_SET_INTRA_1
}
}
pub fn get_tx_set_index(
tx_size: TxSize, is_inter: bool, use_reduced_set: bool,
) -> i8 {
let set_type = get_tx_set(tx_size, is_inter, use_reduced_set);
if is_inter {
tx_set_index_inter[set_type as usize]
} else {
tx_set_index_intra[set_type as usize]
}
}
static intra_mode_to_tx_type_context: [TxType; INTRA_MODES] = [
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, ];
static uv2y: [PredictionMode; UV_INTRA_MODES] = [
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, ];
pub fn uv_intra_mode_to_tx_type_context(pred: PredictionMode) -> TxType {
intra_mode_to_tx_type_context[uv2y[pred as usize] as usize]
}
pub const TXB_SKIP_CONTEXTS: usize = 13;
pub const EOB_COEF_CONTEXTS: usize = 9;
const SIG_COEF_CONTEXTS_2D: usize = 26;
const SIG_COEF_CONTEXTS_1D: usize = 16;
pub const SIG_COEF_CONTEXTS_EOB: usize = 4;
pub const SIG_COEF_CONTEXTS: usize =
SIG_COEF_CONTEXTS_2D + SIG_COEF_CONTEXTS_1D;
const COEFF_BASE_CONTEXTS: usize = SIG_COEF_CONTEXTS;
pub const DC_SIGN_CONTEXTS: usize = 3;
const BR_TMP_OFFSET: usize = 12;
const BR_REF_CAT: usize = 4;
pub const LEVEL_CONTEXTS: usize = 21;
pub const NUM_BASE_LEVELS: usize = 2;
pub const BR_CDF_SIZE: usize = 4;
pub const COEFF_BASE_RANGE: usize = 4 * (BR_CDF_SIZE - 1);
pub const COEFF_CONTEXT_BITS: usize = 6;
pub const COEFF_CONTEXT_MASK: usize = (1 << COEFF_CONTEXT_BITS) - 1;
const MAX_BASE_BR_RANGE: usize = COEFF_BASE_RANGE + NUM_BASE_LEVELS + 1;
const BASE_CONTEXT_POSITION_NUM: usize = 12;
pub const TX_PAD_HOR_LOG2: usize = 2;
pub const TX_PAD_HOR: usize = 4;
pub const TX_PAD_TOP: usize = 2;
pub const TX_PAD_BOTTOM: usize = 4;
pub const TX_PAD_VER: usize = TX_PAD_TOP + TX_PAD_BOTTOM;
const TX_PAD_END: usize = 16;
pub const TX_PAD_2D: usize = (MAX_CODED_TX_SIZE + TX_PAD_HOR)
* (MAX_CODED_TX_SIZE + TX_PAD_VER)
+ TX_PAD_END;
const TX_CLASSES: usize = 3;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum TxClass {
TX_CLASS_2D = 0,
TX_CLASS_HORIZ = 1,
TX_CLASS_VERT = 2,
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum SegLvl {
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,
SEG_LVL_MAX = 8,
}
pub const seg_feature_bits: [u32; SegLvl::SEG_LVL_MAX as usize] =
[8, 6, 6, 6, 6, 3, 0, 0];
pub const seg_feature_is_signed: [bool; SegLvl::SEG_LVL_MAX as usize] =
[true, true, true, true, true, false, false, false];
use crate::context::TxClass::*;
pub static tx_type_to_class: [TxClass; TX_TYPES] = [
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, ];
pub static eob_to_pos_small: [u8; 33] = [
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, ];
pub static eob_to_pos_large: [u8; 17] = [
6, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, ];
pub static k_eob_group_start: [u16; 12] =
[0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513];
pub static k_eob_offset_bits: [u16; 12] = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
#[rustfmt::skip]
pub static av1_nz_map_ctx_offset: [[[i8; 5]; 5]; TxSize::TX_SIZES_ALL] = [
[
[ 0, 1, 6, 6, 0],
[ 1, 6, 6, 21, 0],
[ 6, 6, 21, 21, 0],
[ 6, 21, 21, 21, 0],
[ 0, 0, 0, 0, 0]
],
[
[ 0, 1, 6, 6, 21],
[ 1, 6, 6, 21, 21],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 1, 6, 6, 21],
[ 1, 6, 6, 21, 21],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 1, 6, 6, 21],
[ 1, 6, 6, 21, 21],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 1, 6, 6, 21],
[ 1, 6, 6, 21, 21],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 11, 11, 11, 0],
[11, 11, 11, 11, 0],
[ 6, 6, 21, 21, 0],
[ 6, 21, 21, 21, 0],
[21, 21, 21, 21, 0]
],
[
[ 0, 16, 6, 6, 21],
[16, 16, 6, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21],
[ 0, 0, 0, 0, 0]
],
[
[ 0, 11, 11, 11, 11],
[11, 11, 11, 11, 11],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 16, 6, 6, 21],
[16, 16, 6, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21]
],
[
[ 0, 11, 11, 11, 11],
[11, 11, 11, 11, 11],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 16, 6, 6, 21],
[16, 16, 6, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21]
],
[
[ 0, 11, 11, 11, 11],
[11, 11, 11, 11, 11],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 16, 6, 6, 21],
[16, 16, 6, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21]
],
[
[ 0, 11, 11, 11, 0],
[11, 11, 11, 11, 0],
[ 6, 6, 21, 21, 0],
[ 6, 21, 21, 21, 0],
[21, 21, 21, 21, 0]
],
[
[ 0, 16, 6, 6, 21],
[16, 16, 6, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21],
[ 0, 0, 0, 0, 0]
],
[
[ 0, 11, 11, 11, 11],
[11, 11, 11, 11, 11],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 16, 6, 6, 21],
[16, 16, 6, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21]
],
[
[ 0, 11, 11, 11, 11],
[11, 11, 11, 11, 11],
[ 6, 6, 21, 21, 21],
[ 6, 21, 21, 21, 21],
[21, 21, 21, 21, 21]
],
[
[ 0, 16, 6, 6, 21],
[16, 16, 6, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21],
[16, 16, 21, 21, 21]
]
];
const NZ_MAP_CTX_0: usize = SIG_COEF_CONTEXTS_2D;
const NZ_MAP_CTX_5: usize = NZ_MAP_CTX_0 + 5;
const NZ_MAP_CTX_10: usize = NZ_MAP_CTX_0 + 10;
pub static nz_map_ctx_offset_1d: [usize; 32] = [
NZ_MAP_CTX_0,
NZ_MAP_CTX_5,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
NZ_MAP_CTX_10,
];
const CONTEXT_MAG_POSITION_NUM: usize = 3;
static mag_ref_offset_with_txclass: [[[usize; 2]; CONTEXT_MAG_POSITION_NUM];
3] = [
[[0, 1], [1, 0], [1, 1]],
[[0, 1], [1, 0], [0, 2]],
[[0, 1], [1, 0], [2, 0]],
];
pub struct TXB_CTX {
pub txb_skip_ctx: usize,
pub dc_sign_ctx: usize,
}
impl<'a> ContextWriter<'a> {
pub fn write_tx_type<W: Writer>(
&mut self, w: &mut W, tx_size: TxSize, tx_type: TxType,
y_mode: PredictionMode, is_inter: bool, use_reduced_tx_set: bool,
) {
let square_tx_size = tx_size.sqr();
let tx_set = get_tx_set(tx_size, is_inter, use_reduced_tx_set);
let num_tx_types = num_tx_set[tx_set as usize];
if num_tx_types > 1 {
let tx_set_index =
get_tx_set_index(tx_size, is_inter, use_reduced_tx_set);
assert!(tx_set_index > 0);
assert!(av1_tx_used[tx_set as usize][tx_type as usize] != 0);
if is_inter {
let s = av1_tx_ind[tx_set as usize][tx_type as usize] as u32;
if tx_set_index == 1 {
let cdf = &self.fc.inter_tx_1_cdf[square_tx_size as usize];
symbol_with_update!(self, w, s, cdf);
} else if tx_set_index == 2 {
let cdf = &self.fc.inter_tx_2_cdf[square_tx_size as usize];
symbol_with_update!(self, w, s, cdf);
} else {
let cdf = &self.fc.inter_tx_3_cdf[square_tx_size as usize];
symbol_with_update!(self, w, s, cdf);
}
} else {
let intra_dir = y_mode;
let s = av1_tx_ind[tx_set as usize][tx_type as usize] as u32;
if tx_set_index == 1 {
let cdf = &self.fc.intra_tx_1_cdf[square_tx_size as usize]
[intra_dir as usize];
symbol_with_update!(self, w, s, cdf);
} else {
let cdf = &self.fc.intra_tx_2_cdf[square_tx_size as usize]
[intra_dir as usize];
symbol_with_update!(self, w, s, cdf);
}
}
}
}
fn get_tx_size_context(
&self, bo: TileBlockOffset, bsize: BlockSize,
) -> usize {
let max_tx_size = max_txsize_rect_lookup[bsize as usize];
let max_tx_wide = max_tx_size.width() as u8;
let max_tx_high = max_tx_size.height() as u8;
let has_above = bo.0.y > 0;
let has_left = bo.0.x > 0;
let mut above = self.bc.above_tx_context[bo.0.x] >= max_tx_wide;
let mut left = self.bc.left_tx_context[bo.y_in_sb()] >= max_tx_high;
if has_above {
let above_blk = self.bc.blocks.above_of(bo);
if above_blk.is_inter() {
above = (above_blk.n4_w << MI_SIZE_LOG2) >= max_tx_wide;
};
}
if has_left {
let left_blk = self.bc.blocks.left_of(bo);
if left_blk.is_inter() {
left = (left_blk.n4_h << MI_SIZE_LOG2) >= max_tx_high;
};
}
if has_above && has_left {
return above as usize + left as usize;
};
if has_above {
return above as usize;
};
if has_left {
return left as usize;
};
0
}
pub fn write_tx_size_intra<W: Writer>(
&mut self, w: &mut W, bo: TileBlockOffset, bsize: BlockSize,
tx_size: TxSize,
) {
fn tx_size_to_depth(tx_size: TxSize, bsize: BlockSize) -> usize {
let mut ctx_size = max_txsize_rect_lookup[bsize as usize];
let mut depth: usize = 0;
while tx_size != ctx_size {
depth += 1;
ctx_size = sub_tx_size_map[ctx_size as usize];
debug_assert!(depth <= MAX_TX_DEPTH);
}
depth
}
fn bsize_to_max_depth(bsize: BlockSize) -> usize {
let mut tx_size: TxSize = max_txsize_rect_lookup[bsize as usize];
let mut depth = 0;
while depth < MAX_TX_DEPTH && tx_size != TX_4X4 {
depth += 1;
tx_size = sub_tx_size_map[tx_size as usize];
debug_assert!(depth <= MAX_TX_DEPTH);
}
depth
}
fn bsize_to_tx_size_cat(bsize: BlockSize) -> usize {
let mut tx_size: TxSize = max_txsize_rect_lookup[bsize as usize];
debug_assert!(tx_size != TX_4X4);
let mut depth = 0;
while tx_size != TX_4X4 {
depth += 1;
tx_size = sub_tx_size_map[tx_size as usize];
}
debug_assert!(depth <= MAX_TX_CATS);
depth - 1
}
debug_assert!(!self.bc.blocks[bo].is_inter());
debug_assert!(bsize > BlockSize::BLOCK_4X4);
let tx_size_ctx = self.get_tx_size_context(bo, bsize);
let depth = tx_size_to_depth(tx_size, bsize);
let max_depths = bsize_to_max_depth(bsize);
let tx_size_cat = bsize_to_tx_size_cat(bsize);
debug_assert!(depth <= max_depths);
debug_assert!(!tx_size.is_rect() || bsize.is_rect_tx_allowed());
if tx_size_cat > 0 {
let cdf = &self.fc.tx_size_cdf[tx_size_cat - 1][tx_size_ctx];
symbol_with_update!(self, w, depth as u32, cdf);
} else {
let cdf = &self.fc.tx_size_8x8_cdf[tx_size_ctx];
symbol_with_update!(self, w, depth as u32, cdf);
}
}
fn get_above_tx_width(
&self, bo: TileBlockOffset, _bsize: BlockSize, _tx_size: TxSize,
first_tx: bool,
) -> usize {
let has_above = bo.0.y > 0;
if first_tx {
if !has_above {
return 64;
}
let above_blk = self.bc.blocks.above_of(bo);
if above_blk.skip && above_blk.is_inter() {
return above_blk.bsize.width();
}
}
self.bc.above_tx_context[bo.0.x] as usize
}
fn get_left_tx_height(
&self, bo: TileBlockOffset, _bsize: BlockSize, _tx_size: TxSize,
first_tx: bool,
) -> usize {
let has_left = bo.0.x > 0;
if first_tx {
if !has_left {
return 64;
}
let left_blk = self.bc.blocks.left_of(bo);
if left_blk.skip && left_blk.is_inter() {
return left_blk.bsize.height();
}
}
self.bc.left_tx_context[bo.y_in_sb()] as usize
}
fn txfm_partition_context(
&self, bo: TileBlockOffset, bsize: BlockSize, tx_size: TxSize, tbx: usize,
tby: usize,
) -> usize {
debug_assert!(tx_size > TX_4X4);
debug_assert!(bsize > BlockSize::BLOCK_4X4);
let above = (self.get_above_tx_width(bo, bsize, tx_size, tby == 0)
< tx_size.width()) as usize;
let left = (self.get_left_tx_height(bo, bsize, tx_size, tbx == 0)
< tx_size.height()) as usize;
let max_tx_size: TxSize = bsize.tx_size().sqr_up();
let category: usize = (tx_size.sqr_up() != max_tx_size) as usize
+ (TxSize::TX_SIZES - 1 - max_tx_size as usize) * 2;
debug_assert!(category < TXFM_PARTITION_CONTEXTS);
category * 3 + above + left
}
pub fn write_tx_size_inter<W: Writer>(
&mut self, w: &mut W, bo: TileBlockOffset, bsize: BlockSize,
tx_size: TxSize, txfm_split: bool, tbx: usize, tby: usize, depth: usize,
) {
if bo.0.x >= self.bc.blocks.cols() || bo.0.y >= self.bc.blocks.rows() {
return;
}
debug_assert!(self.bc.blocks[bo].is_inter());
debug_assert!(bsize > BlockSize::BLOCK_4X4);
debug_assert!(!tx_size.is_rect() || bsize.is_rect_tx_allowed());
if tx_size != TX_4X4 && depth < MAX_VARTX_DEPTH {
let ctx = self.txfm_partition_context(bo, bsize, tx_size, tbx, tby);
let cdf = &self.fc.txfm_partition_cdf[ctx];
symbol_with_update!(self, w, txfm_split as u32, cdf);
} else {
debug_assert!(!txfm_split);
}
if !txfm_split {
self.bc.update_tx_size_context(bo, tx_size.block_size(), tx_size, false);
} else {
let split_tx_size = sub_tx_size_map[tx_size as usize];
let bw = bsize.width_mi() / split_tx_size.width_mi();
let bh = bsize.height_mi() / split_tx_size.height_mi();
for by in 0..bh {
for bx in 0..bw {
let tx_bo = TileBlockOffset(BlockOffset {
x: bo.0.x + bx * split_tx_size.width_mi(),
y: bo.0.y + by * split_tx_size.height_mi(),
});
self.write_tx_size_inter(
w,
tx_bo,
bsize,
split_tx_size,
false,
bx,
by,
depth + 1,
);
}
}
}
}
#[inline]
pub const fn get_txsize_entropy_ctx(tx_size: TxSize) -> usize {
(tx_size.sqr() as usize + tx_size.sqr_up() as usize + 1) >> 1
}
pub fn txb_init_levels<T: Coefficient>(
&self, coeffs: &[T], height: usize, levels: &mut [u8],
levels_stride: usize,
) {
for (coeffs_col, levels_col) in
coeffs.chunks_exact(height).zip(levels.chunks_exact_mut(levels_stride))
{
for (coeff, level) in coeffs_col.iter().zip(levels_col) {
*level = coeff.abs().min(T::cast_from(127)).as_();
}
}
}
#[inline]
pub const fn get_txb_bhl(tx_size: TxSize) -> usize {
av1_get_coded_tx_size(tx_size).height_log2()
}
#[inline]
pub fn get_eob_pos_token(eob: u16) -> (u32, u32) {
let t = if eob < 33 {
eob_to_pos_small[usize::from(eob)] as u32
} else {
let e = usize::from(cmp::min((eob - 1) >> 5, 16));
eob_to_pos_large[e] as u32
};
assert!(eob as i32 >= k_eob_group_start[t as usize] as i32);
let extra = eob as u32 - k_eob_group_start[t as usize] as u32;
(t, extra)
}
pub fn get_nz_mag(levels: &[u8], bhl: usize, tx_class: TxClass) -> usize {
let mut mag = cmp::min(3, levels[1]); mag += cmp::min(3, levels[(1 << bhl) + TX_PAD_HOR]); if tx_class == TX_CLASS_2D {
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 {
mag += cmp::min(3, levels[2]); mag += cmp::min(3, levels[3]); mag += cmp::min(3, levels[4]); } else {
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)]); }
mag as usize
}
fn get_nz_map_ctx_from_stats(
stats: usize,
coeff_idx: usize, bhl: usize,
tx_size: TxSize,
tx_class: TxClass,
) -> usize {
if (tx_class as u32 | coeff_idx as u32) == 0 {
return 0;
};
let col: usize = coeff_idx >> bhl;
let row: usize = coeff_idx - (col << bhl);
let ctx = ((stats + 1) >> 1).min(4);
ctx
+ match tx_class {
TX_CLASS_2D => {
av1_nz_map_ctx_offset[tx_size as usize][cmp::min(row, 4)]
[cmp::min(col, 4)] as usize
}
TX_CLASS_HORIZ => nz_map_ctx_offset_1d[col],
TX_CLASS_VERT => nz_map_ctx_offset_1d[row],
}
}
fn get_nz_map_ctx(
levels: &[u8], coeff_idx: usize, bhl: usize, area: usize, scan_idx: usize,
is_eob: bool, tx_size: TxSize, tx_class: TxClass,
) -> usize {
if is_eob {
if scan_idx == 0 {
return 0;
}
if scan_idx <= area / 8 {
return 1;
}
if scan_idx <= area / 4 {
return 2;
}
return 3;
}
let padded_idx = coeff_idx + ((coeff_idx >> bhl) << TX_PAD_HOR_LOG2);
let stats = Self::get_nz_mag(&levels[padded_idx..], bhl, tx_class);
Self::get_nz_map_ctx_from_stats(stats, coeff_idx, bhl, tx_size, tx_class)
}
pub fn get_nz_map_contexts<'c>(
&self, levels: &mut [u8], scan: &[u16], eob: u16, tx_size: TxSize,
tx_class: TxClass, coeff_contexts_no_scan: &'c mut [MaybeUninit<i8>],
) -> &'c mut [i8] {
let bhl = Self::get_txb_bhl(tx_size);
let area = av1_get_coded_tx_size(tx_size).area();
let scan = &scan[..usize::from(eob)];
let coeffs = &mut coeff_contexts_no_scan[..usize::from(eob)];
for (i, (coeff, pos)) in
coeffs.iter_mut().zip(scan.iter().copied()).enumerate()
{
coeff.write(Self::get_nz_map_ctx(
levels,
pos as usize,
bhl,
area,
i,
i == usize::from(eob) - 1,
tx_size,
tx_class,
) as i8);
}
unsafe { slice_assume_init_mut(coeffs) }
}
pub fn get_br_ctx(
levels: &[u8],
coeff_idx: usize, bhl: usize,
tx_class: TxClass,
) -> usize {
let col: usize = coeff_idx >> bhl;
let row: usize = coeff_idx - (col << bhl);
let stride: usize = (1 << bhl) + TX_PAD_HOR;
let pos: usize = col * stride + row;
let mut mag: usize = (levels[pos + 1] + levels[pos + stride]) as usize;
match tx_class {
TX_CLASS_2D => {
mag += levels[pos + stride + 1] as usize;
mag = cmp::min((mag + 1) >> 1, 6);
if coeff_idx == 0 {
return mag;
}
if (row < 2) && (col < 2) {
return mag + 7;
}
}
TX_CLASS_HORIZ => {
mag += levels[pos + (stride << 1)] as usize;
mag = cmp::min((mag + 1) >> 1, 6);
if coeff_idx == 0 {
return mag;
}
if col == 0 {
return mag + 7;
}
}
TX_CLASS_VERT => {
mag += levels[pos + 2] as usize;
mag = cmp::min((mag + 1) >> 1, 6);
if coeff_idx == 0 {
return mag;
}
if row == 0 {
return mag + 7;
}
}
}
mag + 14
}
}