#![allow(dead_code)]
use crate::bits::BoolDecoder;
use crate::prob_tables::*;
use crate::scan_tables::*;
use crate::transform::TxType;
const CAT_MIN_VAL: [i32; 6] = [5, 7, 11, 19, 35, 67];
pub fn get_scan(tx_size: usize, tx_type: TxType) -> (&'static [i16], &'static [i16]) {
match tx_size {
0 => match tx_type {
TxType::DctDct | TxType::AdstAdst => (&DEFAULT_SCAN_4X4, &DEFAULT_SCAN_4X4_NEIGHBORS),
TxType::AdstDct => (&ROW_SCAN_4X4, &ROW_SCAN_4X4_NEIGHBORS),
TxType::DctAdst => (&COL_SCAN_4X4, &COL_SCAN_4X4_NEIGHBORS),
},
1 => match tx_type {
TxType::DctDct | TxType::AdstAdst => (&DEFAULT_SCAN_8X8, &DEFAULT_SCAN_8X8_NEIGHBORS),
TxType::AdstDct => (&ROW_SCAN_8X8, &ROW_SCAN_8X8_NEIGHBORS),
TxType::DctAdst => (&COL_SCAN_8X8, &COL_SCAN_8X8_NEIGHBORS),
},
2 => match tx_type {
TxType::DctDct | TxType::AdstAdst => {
(&DEFAULT_SCAN_16X16, &DEFAULT_SCAN_16X16_NEIGHBORS)
}
TxType::AdstDct => (&ROW_SCAN_16X16, &ROW_SCAN_16X16_NEIGHBORS),
TxType::DctAdst => (&COL_SCAN_16X16, &COL_SCAN_16X16_NEIGHBORS),
},
_ => (&DEFAULT_SCAN_32X32, &DEFAULT_SCAN_32X32_NEIGHBORS),
}
}
#[inline]
pub(crate) fn get_coef_context(nb: &[i16], cache: &[u8], c: usize) -> usize {
((1 + cache[nb[2 * c] as usize] as usize + cache[nb[2 * c + 1] as usize] as usize) >> 1)
as usize
}
#[inline]
fn read_coeff(bd: &mut BoolDecoder, probs: &[u8], n: usize) -> i32 {
let mut val = 0i32;
for i in 0..n {
val = (val << 1) | bd.read_bool(probs[i]) as i32;
}
val
}
#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_arguments)]
pub fn decode_coefs(
bd: &mut BoolDecoder,
coef_probs: &[[[u8; 3]; 6]; 6],
tx_size: usize,
scan: &[i16],
nb: &[i16],
dq: (i32, i32),
mut ctx: usize,
dqcoeff: &mut [i32],
token_cache: &mut [u8],
coef_cnt: &mut [[[u32; 4]; 6]; 6],
eob_cnt: &mut [[u32; 6]; 6],
bit_depth: u32,
) -> (usize, usize) {
let max_eob = 16usize << (tx_size << 1);
let n = 4usize << tx_size; let mut max_row = 0usize; let band_translate: &[u8] = if tx_size == 0 {
&COEFBAND_4X4
} else {
&COEFBAND_8X8PLUS
};
let dq_shift = if tx_size == 3 { 1 } else { 0 };
let (cat6_prob, cat6_bits): (&[u8], usize) = match bit_depth {
10 => (&CAT6_PROB_HIGH10, 16),
12 => (&CAT6_PROB_HIGH12, 18),
_ => (&CAT6_PROB, 14),
};
let mut dqv = dq.0; dqcoeff[..max_eob].iter_mut().for_each(|v| *v = 0);
token_cache[..max_eob].iter_mut().for_each(|v| *v = 0);
let mut c = 0usize;
while c < max_eob {
let mut band = band_translate[c] as usize;
let mut prob = coef_probs[band][ctx];
eob_cnt[band][ctx] += 1;
if bd.read_bool(prob[0]) == 0 {
coef_cnt[band][ctx][3] += 1; break;
}
while bd.read_bool(prob[1]) == 0 {
coef_cnt[band][ctx][0] += 1; token_cache[scan[c] as usize] = 0;
dqv = dq.1;
c += 1;
if c >= max_eob {
return (c, max_row);
}
ctx = get_coef_context(nb, &token_cache, c);
band = band_translate[c] as usize;
prob = coef_probs[band][ctx];
}
let pos = scan[c] as usize;
let two_plus = bd.read_bool(prob[2]) != 0;
coef_cnt[band][ctx][if two_plus { 2 } else { 1 }] += 1; let v: i32 = if two_plus {
let p = &PARETO8_FULL[prob[2] as usize - 1];
if bd.read_bool(p[0]) != 0 {
if bd.read_bool(p[3]) != 0 {
token_cache[pos] = 5;
let val = if bd.read_bool(p[5]) != 0 {
if bd.read_bool(p[7]) != 0 {
CAT_MIN_VAL[5] + read_coeff(bd, cat6_prob, cat6_bits)
} else {
CAT_MIN_VAL[4] + read_coeff(bd, &CAT5_PROB, 5)
}
} else if bd.read_bool(p[6]) != 0 {
CAT_MIN_VAL[3] + read_coeff(bd, &CAT4_PROB, 4)
} else {
CAT_MIN_VAL[2] + read_coeff(bd, &CAT3_PROB, 3)
};
(val * dqv) >> dq_shift
} else {
token_cache[pos] = 4;
let val = if bd.read_bool(p[4]) != 0 {
CAT_MIN_VAL[1] + read_coeff(bd, &CAT2_PROB, 2)
} else {
CAT_MIN_VAL[0] + read_coeff(bd, &CAT1_PROB, 1)
};
(val * dqv) >> dq_shift
}
} else if bd.read_bool(p[1]) != 0 {
token_cache[pos] = 3;
((3 + bd.read_bool(p[2]) as i32) * dqv) >> dq_shift
} else {
token_cache[pos] = 2;
(2 * dqv) >> dq_shift
}
} else {
token_cache[pos] = 1;
dqv >> dq_shift
};
dqcoeff[pos] = if bd.read_bool(128) != 0 { -v } else { v };
max_row = max_row.max(pos / n);
c += 1;
ctx = get_coef_context(nb, &token_cache, c);
dqv = dq.1;
}
(c, max_row)
}
pub fn default_coef_probs(tx: usize, plane: usize, refr: usize) -> &'static [[[u8; 3]; 6]; 6] {
&DEFAULT_COEF_PROBS[tx][plane][refr]
}
pub fn read_tree(bd: &mut BoolDecoder, tree: &[i8], probs: &[u8]) -> i32 {
let mut i: usize = 0;
loop {
let b = bd.read_bool(probs[i >> 1]) as usize;
let next = tree[i + b];
if next <= 0 {
return (-next) as i32;
}
i = next as usize;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scan_selection_matches_libvpx_mapping() {
assert_eq!(get_scan(0, TxType::AdstDct).0, &ROW_SCAN_4X4[..]);
assert_eq!(get_scan(0, TxType::DctAdst).0, &COL_SCAN_4X4[..]);
assert_eq!(get_scan(0, TxType::DctDct).0, &DEFAULT_SCAN_4X4[..]);
assert_eq!(get_scan(0, TxType::AdstAdst).0, &DEFAULT_SCAN_4X4[..]);
assert_eq!(get_scan(3, TxType::AdstDct).0, &DEFAULT_SCAN_32X32[..]);
}
#[test]
fn scan_tables_are_permutations() {
for (scan, n) in [
(&DEFAULT_SCAN_4X4[..], 16),
(&ROW_SCAN_8X8[..], 64),
(&COL_SCAN_16X16[..], 256),
(&DEFAULT_SCAN_32X32[..], 1024),
] {
let mut seen = vec![false; n];
for &p in scan {
seen[p as usize] = true;
}
assert!(seen.iter().all(|&b| b), "scan not a permutation");
}
}
#[test]
fn coef_context_formula() {
let nb = [0i16, 0, 1, 2];
let cache = [4u8, 2, 5];
assert_eq!(get_coef_context(&nb, &cache, 0), (1 + 4 + 4) >> 1); assert_eq!(get_coef_context(&nb, &cache, 1), (1 + 2 + 5) >> 1); }
#[test]
fn read_coeff_assembles_msb_first() {
let data = [0x9Au8, 0x3C, 0x71, 0xE5, 0x42, 0x88];
let probs = [200u8, 50, 130, 90];
let mut a = BoolDecoder::new(&data).unwrap();
let got = read_coeff(&mut a, &probs, 4);
let mut b = BoolDecoder::new(&data).unwrap();
let mut want = 0i32;
for i in 0..4 {
want = (want << 1) | b.read_bool(probs[i]) as i32;
}
assert_eq!(got, want);
}
#[test]
fn read_tree_walks_to_leaf() {
let tree = [0i8, -1]; let data = [0u8; 8];
let mut bd = BoolDecoder::new(&data).unwrap();
assert_eq!(read_tree(&mut bd, &tree, &[128]), 0);
}
#[test]
fn decode_coefs_smoke_returns_within_bounds() {
let data = [0x42u8, 0x9C, 0x17, 0xE3, 0x55, 0xAA, 0x01, 0xFF, 0x80, 0x33];
let probs = default_coef_probs(0, 0, 0);
let (scan, nb) = get_scan(0, TxType::DctDct);
let mut bd = BoolDecoder::new(&data).unwrap();
let mut out = [0i32; 16];
let mut tc = [0u8; 16];
let mut cc = [[[0u32; 4]; 6]; 6];
let mut ec = [[0u32; 6]; 6];
let (eob, _max_row) = decode_coefs(
&mut bd,
probs,
0,
scan,
nb,
(20, 18),
0,
&mut out,
&mut tc,
&mut cc,
&mut ec,
8,
);
assert!(eob <= 16);
}
}