#![allow(dead_code)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::bool_to_int_with_if)]
#![allow(clippy::needless_bool_assign)]
#![allow(clippy::if_not_else)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::match_same_arms)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::explicit_iter_loop)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::comparison_chain)]
#![allow(clippy::cast_lossless)]
use super::transform::{TxClass, TxSize, TxType};
pub const MAX_EOB: usize = 4096;
pub const EOB_COEF_CONTEXTS: usize = 9;
pub const COEFF_BASE_CONTEXTS: usize = 42;
pub const COEFF_BASE_EOB_CONTEXTS: usize = 3;
pub const DC_SIGN_CONTEXTS: usize = 3;
pub const COEFF_BR_CONTEXTS: usize = 21;
pub const COEFF_BASE_RANGE_MAX: u32 = 3;
pub const COEFF_BR_RICE_PARAM: u8 = 1;
pub const BASE_LEVEL_CUTOFFS: [u32; 5] = [0, 1, 2, 3, 4];
pub const TX_CLASSES: usize = 3;
pub const COEFF_CONTEXT_MASK: usize = 63;
pub const MAX_NEIGHBORS: usize = 2;
pub const EOB_OFFSET: [u16; 19] = [
0, 16, 80, 336, 1360, 16, 16, 80, 80, 336, 336, 1360, 1360, 48, 48, 176, 176, 592, 592, ];
pub const EOB_EXTRA_BITS: [u8; 19] = [
0, 1, 2, 3, 4, 1, 1, 2, 2, 3, 3, 4, 4, 2, 2, 3, 3, 4, 4, ];
pub const EOB_GROUP_START: [u16; 12] = [0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513];
pub const EOB_TO_POS: [u16; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
#[derive(Clone, Debug, Default)]
pub struct LevelContext {
pub mag: u32,
pub count: u8,
pub pos_ctx: u8,
}
impl LevelContext {
#[must_use]
pub const fn new() -> Self {
Self {
mag: 0,
count: 0,
pos_ctx: 0,
}
}
#[must_use]
pub fn mag_context(&self) -> u8 {
let mag = self.mag;
if mag > 512 {
4
} else if mag > 256 {
3
} else if mag > 128 {
2
} else if mag > 64 {
1
} else {
0
}
}
#[must_use]
pub fn context(&self) -> u8 {
self.mag_context() * 3 + self.count.min(2)
}
}
#[derive(Clone, Debug)]
pub struct CoeffContext {
pub tx_size: TxSize,
pub tx_type: TxType,
pub plane: u8,
pub scan_pos: u16,
pub eob: u16,
pub levels: Vec<i32>,
pub signs: Vec<bool>,
pub left_ctx: Vec<u8>,
pub above_ctx: Vec<u8>,
pub block_width: u8,
pub block_height: u8,
}
impl CoeffContext {
#[must_use]
pub fn new(tx_size: TxSize, tx_type: TxType, plane: u8) -> Self {
let area = tx_size.area() as usize;
let width = (tx_size.width() / 4) as u8;
let height = (tx_size.height() / 4) as u8;
Self {
tx_size,
tx_type,
plane,
scan_pos: 0,
eob: 0,
levels: vec![0; area],
signs: vec![false; area],
left_ctx: vec![0; height as usize * 4],
above_ctx: vec![0; width as usize * 4],
block_width: width,
block_height: height,
}
}
pub fn reset(&mut self) {
self.scan_pos = 0;
self.eob = 0;
self.levels.fill(0);
self.signs.fill(false);
self.left_ctx.fill(0);
self.above_ctx.fill(0);
}
#[must_use]
pub fn tx_class(&self) -> TxClass {
self.tx_type.tx_class()
}
#[must_use]
pub fn get_scan_position(&self, idx: usize) -> (u32, u32) {
let width = self.tx_size.width();
let row = (idx as u32) / width;
let col = (idx as u32) % width;
(row, col)
}
#[must_use]
pub fn get_coeff_index(&self, row: u32, col: u32) -> usize {
(row * self.tx_size.width() + col) as usize
}
#[must_use]
pub fn compute_level_context(&self, pos: usize) -> LevelContext {
let width = self.tx_size.width() as usize;
let _height = self.tx_size.height() as usize;
let row = pos / width;
let col = pos % width;
let mut ctx = LevelContext::new();
if col > 0 {
let left = self.levels[row * width + col - 1].unsigned_abs();
ctx.mag += left;
if left > 0 {
ctx.count += 1;
}
}
if row > 0 {
let above = self.levels[(row - 1) * width + col].unsigned_abs();
ctx.mag += above;
if above > 0 {
ctx.count += 1;
}
}
if row > 0 && col > 0 {
let diag = self.levels[(row - 1) * width + col - 1].unsigned_abs();
ctx.mag += diag;
}
ctx.pos_ctx = if row + col == 0 {
0
} else if row + col < 2 {
1
} else if row + col < 4 {
2
} else {
3
};
ctx
}
#[must_use]
pub fn dc_sign_context(&self) -> u8 {
let left_sign = if !self.left_ctx.is_empty() {
(self.left_ctx[0] as i8 - 1).signum()
} else {
0
};
let above_sign = if !self.above_ctx.is_empty() {
(self.above_ctx[0] as i8 - 1).signum()
} else {
0
};
let sign_sum = left_sign + above_sign;
if sign_sum < 0 {
0
} else if sign_sum > 0 {
2
} else {
1
}
}
pub fn set_coeff(&mut self, pos: usize, level: i32, sign: bool) {
if pos < self.levels.len() {
self.levels[pos] = if sign { -level } else { level };
self.signs[pos] = sign;
}
}
#[must_use]
pub fn get_coeff(&self, pos: usize) -> i32 {
self.levels.get(pos).copied().unwrap_or(0)
}
#[must_use]
pub fn has_nonzero(&self) -> bool {
self.eob > 0
}
#[must_use]
pub fn count_nonzero(&self) -> u16 {
self.levels.iter().filter(|&&l| l != 0).count() as u16
}
}
impl Default for CoeffContext {
fn default() -> Self {
Self::new(TxSize::Tx4x4, TxType::DctDct, 0)
}
}
#[must_use]
pub fn generate_diagonal_scan(width: usize, height: usize) -> Vec<u16> {
let mut scan = Vec::with_capacity(width * height);
for diag in 0..(width + height - 1) {
let col_start = if diag < width { 0 } else { diag - width + 1 };
let col_end = diag.min(height - 1);
for offset in 0..=(col_end - col_start) {
let row = col_start + offset;
let col = diag - row;
if col < width && row < height {
scan.push((row * width + col) as u16);
}
}
}
scan
}
#[must_use]
pub fn generate_horizontal_scan(width: usize, height: usize) -> Vec<u16> {
let mut scan = Vec::with_capacity(width * height);
for row in 0..height {
for col in 0..width {
scan.push((row * width + col) as u16);
}
}
scan
}
#[must_use]
pub fn generate_vertical_scan(width: usize, height: usize) -> Vec<u16> {
let mut scan = Vec::with_capacity(width * height);
for col in 0..width {
for row in 0..height {
scan.push((row * width + col) as u16);
}
}
scan
}
#[must_use]
pub fn get_scan_order(tx_size: TxSize, tx_class: TxClass) -> Vec<u16> {
let width = tx_size.width() as usize;
let height = tx_size.height() as usize;
match tx_class {
TxClass::Class2D => generate_diagonal_scan(width, height),
TxClass::ClassHoriz => generate_horizontal_scan(width, height),
TxClass::ClassVert => generate_vertical_scan(width, height),
}
}
#[derive(Clone, Debug)]
pub struct ScanOrderCache {
cache: Vec<Vec<Vec<u16>>>,
}
impl ScanOrderCache {
#[must_use]
pub fn new() -> Self {
let mut cache = Vec::with_capacity(19);
for tx_size_idx in 0..19 {
let tx_size = TxSize::from_u8(tx_size_idx as u8).unwrap_or_default();
let mut class_scans = Vec::with_capacity(3);
for tx_class_idx in 0..3 {
let tx_class = TxClass::from_u8(tx_class_idx as u8).unwrap_or_default();
class_scans.push(get_scan_order(tx_size, tx_class));
}
cache.push(class_scans);
}
Self { cache }
}
#[must_use]
pub fn get(&self, tx_size: TxSize, tx_class: TxClass) -> &[u16] {
let size_idx = tx_size as usize;
let class_idx = tx_class as usize;
if size_idx < self.cache.len() && class_idx < self.cache[size_idx].len() {
&self.cache[size_idx][class_idx]
} else {
&[]
}
}
}
impl Default for ScanOrderCache {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug, Default)]
pub struct EobContext {
pub eob_multi: u8,
pub eob_extra: u8,
pub base_ctx: u8,
}
impl EobContext {
#[must_use]
pub fn new(tx_size: TxSize) -> Self {
let size_idx = tx_size as usize;
let extra_bits = if size_idx < EOB_EXTRA_BITS.len() {
EOB_EXTRA_BITS[size_idx]
} else {
0
};
Self {
eob_multi: 0,
eob_extra: extra_bits,
base_ctx: 0,
}
}
#[must_use]
pub fn get_eob_context(eob: u16) -> u8 {
if eob <= 1 {
0
} else if eob <= 2 {
1
} else if eob <= 4 {
2
} else if eob <= 8 {
3
} else if eob <= 16 {
4
} else if eob <= 32 {
5
} else if eob <= 64 {
6
} else if eob <= 128 {
7
} else {
8
}
}
#[must_use]
pub fn compute_eob(eob_multi: u8, eob_extra: u16) -> u16 {
let group_idx = eob_multi as usize;
if group_idx >= EOB_GROUP_START.len() {
return 0;
}
let base = EOB_GROUP_START[group_idx];
base + eob_extra
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EobPt {
EobPt0 = 0,
EobPt1 = 1,
EobPt2 = 2,
EobPt3To4 = 3,
EobPt5To8 = 4,
EobPt9To16 = 5,
EobPt17To32 = 6,
EobPt33To64 = 7,
EobPt65To128 = 8,
EobPt129To256 = 9,
EobPt257To512 = 10,
EobPt513To1024 = 11,
}
impl EobPt {
#[must_use]
pub fn from_eob(eob: u16) -> Self {
match eob {
0 => Self::EobPt0,
1 => Self::EobPt1,
2 => Self::EobPt2,
3..=4 => Self::EobPt3To4,
5..=8 => Self::EobPt5To8,
9..=16 => Self::EobPt9To16,
17..=32 => Self::EobPt17To32,
33..=64 => Self::EobPt33To64,
65..=128 => Self::EobPt65To128,
129..=256 => Self::EobPt129To256,
257..=512 => Self::EobPt257To512,
_ => Self::EobPt513To1024,
}
}
#[must_use]
pub const fn base_eob(self) -> u16 {
match self {
Self::EobPt0 => 0,
Self::EobPt1 => 1,
Self::EobPt2 => 2,
Self::EobPt3To4 => 3,
Self::EobPt5To8 => 5,
Self::EobPt9To16 => 9,
Self::EobPt17To32 => 17,
Self::EobPt33To64 => 33,
Self::EobPt65To128 => 65,
Self::EobPt129To256 => 129,
Self::EobPt257To512 => 257,
Self::EobPt513To1024 => 513,
}
}
#[must_use]
pub const fn extra_bits(self) -> u8 {
match self {
Self::EobPt0 | Self::EobPt1 | Self::EobPt2 => 0,
Self::EobPt3To4 => 1,
Self::EobPt5To8 => 2,
Self::EobPt9To16 => 3,
Self::EobPt17To32 => 4,
Self::EobPt33To64 => 5,
Self::EobPt65To128 => 6,
Self::EobPt129To256 => 7,
Self::EobPt257To512 => 8,
Self::EobPt513To1024 => 9,
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct CoeffBaseRange {
pub base_level: u8,
pub range_ctx: u8,
}
impl CoeffBaseRange {
#[must_use]
pub fn get_br_context(level_ctx: &LevelContext, pos: usize, width: usize) -> u8 {
let row = pos / width;
let col = pos % width;
let pos_ctx = if row + col == 0 {
0
} else if row + col < 2 {
7
} else {
14
};
pos_ctx + level_ctx.mag_context().min(6)
}
#[must_use]
pub fn compute_level(base: u8, range: u16) -> u32 {
u32::from(base) + u32::from(range)
}
}
#[must_use]
pub fn dequantize_coeff(level: i32, dequant: i16, shift: u8) -> i32 {
let abs_level = level.abs();
let dq_level = (abs_level * i32::from(dequant)) >> shift;
if level < 0 {
-dq_level
} else {
dq_level
}
}
pub fn dequantize_block(coeffs: &mut [i32], dc_dequant: i16, ac_dequant: i16, shift: u8) {
if coeffs.is_empty() {
return;
}
coeffs[0] = dequantize_coeff(coeffs[0], dc_dequant, shift);
for coeff in coeffs.iter_mut().skip(1) {
*coeff = dequantize_coeff(*coeff, ac_dequant, shift);
}
}
#[must_use]
pub const fn get_dequant_shift(bit_depth: u8) -> u8 {
match bit_depth {
8 => 0,
10 => 2,
12 => 4,
_ => 0,
}
}
#[derive(Clone, Debug)]
pub struct CoeffBuffer {
coeffs: Vec<i32>,
width: usize,
height: usize,
}
impl CoeffBuffer {
#[must_use]
pub fn new(width: usize, height: usize) -> Self {
Self {
coeffs: vec![0; width * height],
width,
height,
}
}
#[must_use]
pub fn from_tx_size(tx_size: TxSize) -> Self {
Self::new(tx_size.width() as usize, tx_size.height() as usize)
}
#[must_use]
pub fn get(&self, row: usize, col: usize) -> i32 {
if row < self.height && col < self.width {
self.coeffs[row * self.width + col]
} else {
0
}
}
pub fn set(&mut self, row: usize, col: usize, value: i32) {
if row < self.height && col < self.width {
self.coeffs[row * self.width + col] = value;
}
}
pub fn clear(&mut self) {
self.coeffs.fill(0);
}
pub fn as_mut_slice(&mut self) -> &mut [i32] {
&mut self.coeffs
}
#[must_use]
pub fn as_slice(&self) -> &[i32] {
&self.coeffs
}
pub fn copy_from_scan(&mut self, src: &[i32], scan: &[u16]) {
for (i, &pos) in scan.iter().enumerate() {
if i < src.len() && (pos as usize) < self.coeffs.len() {
self.coeffs[pos as usize] = src[i];
}
}
}
pub fn copy_to_scan(&self, dst: &mut [i32], scan: &[u16]) {
for (i, &pos) in scan.iter().enumerate() {
if i < dst.len() && (pos as usize) < self.coeffs.len() {
dst[i] = self.coeffs[pos as usize];
}
}
}
}
impl Default for CoeffBuffer {
fn default() -> Self {
Self::new(4, 4)
}
}
#[must_use]
pub fn get_neighbor_positions(pos: usize, width: usize, _height: usize) -> [(usize, bool); 5] {
let row = pos / width;
let col = pos % width;
let mut neighbors = [(0usize, false); 5];
if col > 0 {
neighbors[0] = (row * width + col - 1, true);
}
if row > 0 {
neighbors[1] = ((row - 1) * width + col, true);
}
if row > 0 && col > 0 {
neighbors[2] = ((row - 1) * width + col - 1, true);
}
if row > 0 && col + 1 < width {
neighbors[3] = ((row - 1) * width + col + 1, true);
}
if col > 1 {
neighbors[4] = (row * width + col - 2, true);
}
neighbors
}
#[must_use]
pub fn compute_context_from_neighbors(levels: &[i32], neighbors: &[(usize, bool); 5]) -> u8 {
let mut mag = 0u32;
let mut count = 0u8;
for &(pos, valid) in neighbors.iter() {
if valid && pos < levels.len() {
let level = levels[pos].unsigned_abs();
mag += level;
if level > 0 {
count += 1;
}
}
}
let mag_ctx = if mag > 512 {
4
} else if mag > 256 {
3
} else if mag > 128 {
2
} else if mag > 64 {
1
} else {
0
};
mag_ctx * 3 + count.min(2)
}
#[must_use]
pub fn compute_dc_sign_context(left_dc: i32, above_dc: i32) -> u8 {
let left_sign = left_dc.signum();
let above_sign = above_dc.signum();
let sum = left_sign + above_sign;
if sum < 0 {
0
} else if sum > 0 {
2
} else {
1
}
}
pub fn update_level_context(
left_ctx: &mut [u8],
above_ctx: &mut [u8],
level: i32,
row: usize,
col: usize,
) {
let level_ctx = (level.unsigned_abs().min(63) as u8) + 1;
if row < left_ctx.len() {
left_ctx[row] = level_ctx;
}
if col < above_ctx.len() {
above_ctx[col] = level_ctx;
}
}
#[derive(Clone, Debug, Default)]
pub struct CoeffStats {
pub zero_count: u32,
pub level1_count: u32,
pub level2_count: u32,
pub high_level_count: u32,
pub level_sum: u64,
pub max_level: u32,
}
impl CoeffStats {
#[must_use]
pub fn from_coeffs(coeffs: &[i32]) -> Self {
let mut stats = Self::default();
for &coeff in coeffs {
let level = coeff.unsigned_abs();
match level {
0 => stats.zero_count += 1,
1 => stats.level1_count += 1,
2 => stats.level2_count += 1,
_ => stats.high_level_count += 1,
}
stats.level_sum += u64::from(level);
stats.max_level = stats.max_level.max(level);
}
stats
}
#[must_use]
pub fn nonzero_count(&self) -> u32 {
self.level1_count + self.level2_count + self.high_level_count
}
#[must_use]
pub fn average_level(&self) -> f64 {
let count = self.nonzero_count();
if count > 0 {
self.level_sum as f64 / count as f64
} else {
0.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_level_context() {
let mut ctx = LevelContext::new();
assert_eq!(ctx.mag, 0);
assert_eq!(ctx.count, 0);
ctx.mag = 100;
ctx.count = 2;
assert_eq!(ctx.mag_context(), 1);
assert_eq!(ctx.context(), 1 * 3 + 2);
}
#[test]
fn test_coeff_context_new() {
let ctx = CoeffContext::new(TxSize::Tx8x8, TxType::DctDct, 0);
assert_eq!(ctx.levels.len(), 64);
assert_eq!(ctx.tx_class(), TxClass::Class2D);
}
#[test]
fn test_coeff_context_set_get() {
let mut ctx = CoeffContext::new(TxSize::Tx4x4, TxType::DctDct, 0);
ctx.set_coeff(5, 100, false);
assert_eq!(ctx.get_coeff(5), 100);
ctx.set_coeff(10, 50, true);
assert_eq!(ctx.get_coeff(10), -50);
}
#[test]
fn test_diagonal_scan_4x4() {
let scan = generate_diagonal_scan(4, 4);
assert_eq!(scan.len(), 16);
assert_eq!(scan[0], 0); assert_eq!(scan[1], 1); }
#[test]
fn test_horizontal_scan() {
let scan = generate_horizontal_scan(4, 4);
assert_eq!(scan.len(), 16);
for i in 0..16 {
assert_eq!(scan[i], i as u16);
}
}
#[test]
fn test_vertical_scan() {
let scan = generate_vertical_scan(4, 4);
assert_eq!(scan.len(), 16);
assert_eq!(scan[0], 0);
assert_eq!(scan[1], 4);
assert_eq!(scan[2], 8);
assert_eq!(scan[3], 12);
}
#[test]
fn test_scan_order_cache() {
let cache = ScanOrderCache::new();
let scan = cache.get(TxSize::Tx4x4, TxClass::Class2D);
assert_eq!(scan.len(), 16);
}
#[test]
fn test_eob_context() {
let ctx = EobContext::new(TxSize::Tx8x8);
assert!(ctx.eob_extra > 0);
}
#[test]
fn test_eob_pt() {
assert_eq!(EobPt::from_eob(0), EobPt::EobPt0);
assert_eq!(EobPt::from_eob(1), EobPt::EobPt1);
assert_eq!(EobPt::from_eob(5), EobPt::EobPt5To8);
assert_eq!(EobPt::from_eob(100), EobPt::EobPt65To128);
assert_eq!(EobPt::EobPt5To8.extra_bits(), 2);
assert_eq!(EobPt::EobPt5To8.base_eob(), 5);
}
#[test]
fn test_dequantize_coeff() {
let level = 10;
let dequant = 16;
let result = dequantize_coeff(level, dequant, 0);
assert_eq!(result, 160);
let neg_result = dequantize_coeff(-level, dequant, 0);
assert_eq!(neg_result, -160);
}
#[test]
fn test_dequantize_block() {
let mut coeffs = vec![10, 5, 5, 5, 5, 5, 5, 5];
dequantize_block(&mut coeffs, 20, 10, 0);
assert_eq!(coeffs[0], 200); assert_eq!(coeffs[1], 50); }
#[test]
fn test_get_dequant_shift() {
assert_eq!(get_dequant_shift(8), 0);
assert_eq!(get_dequant_shift(10), 2);
assert_eq!(get_dequant_shift(12), 4);
}
#[test]
fn test_coeff_buffer() {
let mut buf = CoeffBuffer::new(4, 4);
buf.set(1, 2, 100);
assert_eq!(buf.get(1, 2), 100);
assert_eq!(buf.get(0, 0), 0);
buf.clear();
assert_eq!(buf.get(1, 2), 0);
}
#[test]
fn test_coeff_buffer_from_tx_size() {
let buf = CoeffBuffer::from_tx_size(TxSize::Tx8x8);
assert_eq!(buf.as_slice().len(), 64);
}
#[test]
fn test_neighbor_positions() {
let neighbors = get_neighbor_positions(5, 4, 4);
assert!(neighbors[0].1);
assert_eq!(neighbors[0].0, 4);
assert!(neighbors[1].1);
assert_eq!(neighbors[1].0, 1);
}
#[test]
fn test_compute_dc_sign_context() {
assert_eq!(compute_dc_sign_context(-5, -3), 0); assert_eq!(compute_dc_sign_context(5, 3), 2); assert_eq!(compute_dc_sign_context(-5, 3), 1); assert_eq!(compute_dc_sign_context(0, 0), 1); }
#[test]
fn test_coeff_stats() {
let coeffs = vec![0, 1, 2, 3, 0, 1, 5, 0];
let stats = CoeffStats::from_coeffs(&coeffs);
assert_eq!(stats.zero_count, 3);
assert_eq!(stats.level1_count, 2);
assert_eq!(stats.level2_count, 1);
assert_eq!(stats.high_level_count, 2);
assert_eq!(stats.max_level, 5);
assert_eq!(stats.nonzero_count(), 5);
}
#[test]
fn test_coeff_context_dc_sign() {
let ctx = CoeffContext::new(TxSize::Tx4x4, TxType::DctDct, 0);
let dc_ctx = ctx.dc_sign_context();
assert!(dc_ctx <= 2);
}
#[test]
fn test_coeff_context_level_context() {
let mut ctx = CoeffContext::new(TxSize::Tx4x4, TxType::DctDct, 0);
ctx.levels[0] = 5;
ctx.levels[1] = 3;
ctx.levels[4] = 2;
let level_ctx = ctx.compute_level_context(5);
assert!(level_ctx.mag > 0);
}
#[test]
fn test_eob_compute() {
assert_eq!(EobContext::compute_eob(0, 0), 0);
assert_eq!(EobContext::compute_eob(1, 0), 1);
assert_eq!(EobContext::compute_eob(2, 0), 2);
}
#[test]
fn test_coeff_base_range() {
let level_ctx = LevelContext {
mag: 100,
count: 2,
pos_ctx: 1,
};
let br_ctx = CoeffBaseRange::get_br_context(&level_ctx, 5, 4);
assert!(br_ctx > 0);
let level = CoeffBaseRange::compute_level(2, 5);
assert_eq!(level, 7);
}
#[test]
fn test_constants() {
assert_eq!(MAX_EOB, 4096);
assert_eq!(EOB_COEF_CONTEXTS, 9);
assert_eq!(TX_CLASSES, 3);
}
#[test]
fn test_coeff_context_reset() {
let mut ctx = CoeffContext::new(TxSize::Tx4x4, TxType::DctDct, 0);
ctx.eob = 10;
ctx.levels[5] = 100;
ctx.reset();
assert_eq!(ctx.eob, 0);
assert_eq!(ctx.levels[5], 0);
}
#[test]
fn test_coeff_context_count_nonzero() {
let mut ctx = CoeffContext::new(TxSize::Tx4x4, TxType::DctDct, 0);
ctx.levels[0] = 5;
ctx.levels[5] = 3;
ctx.levels[10] = -2;
assert_eq!(ctx.count_nonzero(), 3);
}
#[test]
fn test_scan_order_all_sizes() {
for size_idx in 0..19 {
if let Some(tx_size) = TxSize::from_u8(size_idx) {
for class_idx in 0..3 {
if let Some(tx_class) = TxClass::from_u8(class_idx) {
let scan = get_scan_order(tx_size, tx_class);
assert_eq!(scan.len(), tx_size.area() as usize);
}
}
}
}
}
}