use super::cabac::{CabacDecoder, ContextModel, context};
use super::debug;
use super::transform::MAX_COEFF;
use crate::error::HevcError;
macro_rules! rc_eprintln {
($($arg:tt)*) => {
#[cfg(feature = "std")]
eprintln!($($arg)*);
};
}
type Result<T> = core::result::Result<T, HevcError>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScanOrder {
Diagonal = 0,
Horizontal = 1,
Vertical = 2,
}
pub fn get_scan_order(log2_size: u8, intra_mode: u8, c_idx: u8) -> ScanOrder {
let use_directional = if c_idx == 0 {
log2_size == 2 || log2_size == 3
} else {
log2_size == 2
};
if use_directional {
if (6..=14).contains(&intra_mode) {
ScanOrder::Vertical
} else if (22..=30).contains(&intra_mode) {
ScanOrder::Horizontal
} else {
ScanOrder::Diagonal
}
} else {
ScanOrder::Diagonal
}
}
pub static SCAN_ORDER_4X4_DIAG: [(u8, u8); 16] = [
(0, 0),
(0, 1),
(1, 0),
(0, 2),
(1, 1),
(2, 0),
(0, 3),
(1, 2),
(2, 1),
(3, 0),
(1, 3),
(2, 2),
(3, 1),
(2, 3),
(3, 2),
(3, 3),
];
pub static SCAN_ORDER_4X4_HORIZ: [(u8, u8); 16] = [
(0, 0),
(1, 0),
(2, 0),
(3, 0),
(0, 1),
(1, 1),
(2, 1),
(3, 1),
(0, 2),
(1, 2),
(2, 2),
(3, 2),
(0, 3),
(1, 3),
(2, 3),
(3, 3),
];
pub static SCAN_ORDER_4X4_VERT: [(u8, u8); 16] = [
(0, 0),
(0, 1),
(0, 2),
(0, 3),
(1, 0),
(1, 1),
(1, 2),
(1, 3),
(2, 0),
(2, 1),
(2, 2),
(2, 3),
(3, 0),
(3, 1),
(3, 2),
(3, 3),
];
pub fn get_scan_4x4(order: ScanOrder) -> &'static [(u8, u8); 16] {
match order {
ScanOrder::Diagonal => &SCAN_ORDER_4X4_DIAG,
ScanOrder::Horizontal => &SCAN_ORDER_4X4_HORIZ,
ScanOrder::Vertical => &SCAN_ORDER_4X4_VERT,
}
}
#[derive(Clone)]
pub struct CoeffBuffer {
pub coeffs: [i16; MAX_COEFF],
pub log2_size: u8,
pub num_nonzero: u16,
}
impl Default for CoeffBuffer {
fn default() -> Self {
Self {
coeffs: [0; MAX_COEFF],
log2_size: 2,
num_nonzero: 0,
}
}
}
impl CoeffBuffer {
#[inline]
pub fn new(log2_size: u8) -> Self {
Self {
coeffs: [0; MAX_COEFF],
log2_size,
num_nonzero: 0,
}
}
#[inline]
pub fn size(&self) -> usize {
1 << self.log2_size
}
#[allow(dead_code)]
#[inline]
pub fn get(&self, x: usize, y: usize) -> i16 {
let stride = self.size();
self.coeffs[y * stride + x]
}
#[inline]
pub fn set(&mut self, x: usize, y: usize, value: i16) {
let stride = self.size();
self.coeffs[y * stride + x] = value;
if value != 0 {
self.num_nonzero = self.num_nonzero.saturating_add(1);
}
}
pub fn is_zero(&self) -> bool {
self.num_nonzero == 0
}
}
pub static DEBUG_RESIDUAL_COUNTER: core::sync::atomic::AtomicU32 =
core::sync::atomic::AtomicU32::new(0);
#[allow(clippy::too_many_arguments)]
pub fn decode_residual(
cabac: &mut CabacDecoder<'_>,
ctx: &mut [ContextModel],
log2_size: u8,
c_idx: u8, scan_order: ScanOrder,
sign_data_hiding_enabled: bool,
cu_transquant_bypass: bool,
transform_skip_enabled: bool,
_x0: u32,
_y0: u32,
) -> Result<(CoeffBuffer, bool)> {
DEBUG_RESIDUAL_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
#[cfg(feature = "std")]
{
let se_num =
crate::hevc::ctu::SE_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
#[allow(clippy::absurd_extreme_comparisons)]
if se_num < crate::hevc::ctu::SE_TRACE_LIMIT {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
eprintln!(
"SE#{} residual_coding c_idx={} log2={} range={} byte={}",
se_num, c_idx, log2_size, _range, _byte_pos
);
}
}
#[cfg(feature = "std")]
let rc_trace = false;
#[cfg(not(feature = "std"))]
let rc_trace = false;
let _rcp = "RCX";
let mut buffer = CoeffBuffer::new(log2_size);
let size = 1u32 << log2_size;
let transform_skip = if transform_skip_enabled && !cu_transquant_bypass && log2_size <= 2 {
let ctx_idx = context::TRANSFORM_SKIP_FLAG + if c_idx > 0 { 1 } else { 0 };
let flag = cabac.decode_bin(&mut ctx[ctx_idx])? != 0;
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
rc_eprintln!(
"{_rcp}_TSKIP c_idx={} val={} range={} byte={}",
c_idx,
flag as u8,
_range,
_byte_pos
);
}
flag
} else {
false
};
let (last_x, last_y) = decode_last_sig_coeff_pos(cabac, ctx, log2_size, c_idx)?;
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
rc_eprintln!(
"{_rcp}_LAST lastX={} lastY={} range={} byte={}",
last_x,
last_y,
_range,
_byte_pos
);
}
let (last_x, last_y) = if scan_order == ScanOrder::Vertical {
(last_y, last_x)
} else {
(last_x, last_y)
};
if last_x >= size || last_y >= size {
return Err(HevcError::InvalidBitstream("invalid last coeff position"));
}
let scan_sub = get_scan_sub_block(log2_size, scan_order);
let scan_pos = get_scan_4x4(scan_order);
let scan_idx = match scan_order {
ScanOrder::Diagonal => 0,
ScanOrder::Horizontal => 1,
ScanOrder::Vertical => 2,
};
let sb_width = (size / 4) as usize;
let last_sb_x = last_x / 4;
let last_sb_y = last_y / 4;
let last_sb_idx = find_scan_pos(scan_sub, last_sb_x, last_sb_y, sb_width as u32);
let local_x = (last_x % 4) as u8;
let local_y = (last_y % 4) as u8;
let last_pos_in_sb = find_scan_pos_4x4(scan_pos, local_x, local_y);
if rc_trace {
rc_eprintln!(
"{_rcp}_SCAN scanIdx={} lastSB={} lastPos={} sb=({},{}) local=({},{})",
scan_idx,
last_sb_idx,
last_pos_in_sb,
last_sb_x,
last_sb_y,
local_x,
local_y
);
}
let mut coded_sb_flags = [[false; 8]; 8];
let mut prev_subblock_had_gt1 = false;
for sb_idx in (0..=last_sb_idx).rev() {
let (sb_x, sb_y) = scan_sub[sb_idx as usize];
let csbf_neighbors = {
let right_coded = if (sb_x as usize + 1) < sb_width {
coded_sb_flags[sb_y as usize][sb_x as usize + 1]
} else {
false
};
let below_coded = if (sb_y as usize + 1) < sb_width {
coded_sb_flags[sb_y as usize + 1][sb_x as usize]
} else {
false
};
(if right_coded { 1 } else { 0 }) | (if below_coded { 2 } else { 0 })
};
let (sb_coded, infer_sb_dc_sig) = if sb_idx > 0 && sb_idx < last_sb_idx {
let coded = decode_coded_sub_block_flag(cabac, ctx, c_idx, csbf_neighbors)?;
(coded, coded)
} else {
(true, false) };
if sb_coded {
coded_sb_flags[sb_y as usize][sb_x as usize] = true;
}
let prev_csbf = csbf_neighbors;
if !sb_coded {
continue;
}
let start_pos = if sb_idx == last_sb_idx {
last_pos_in_sb
} else {
15
};
let mut coeff_values = [0i16; 16];
let mut coeff_flags = [false; 16];
let mut num_coeffs = 0u8;
let mut can_infer_dc = infer_sb_dc_sig;
let last_coeff = if sb_idx == last_sb_idx {
coeff_flags[start_pos as usize] = true;
coeff_values[start_pos as usize] = 1;
num_coeffs = 1;
can_infer_dc = false; start_pos.saturating_sub(1)
} else {
15
};
for n in (1..=last_coeff).rev() {
let sig = decode_sig_coeff_flag(
cabac, ctx, c_idx, n, log2_size, scan_idx, sb_x, sb_y, prev_csbf, scan_pos,
)?;
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
let (x_in_sb, y_in_sb) = scan_pos[n as usize];
let xc = sb_x * 4 + x_in_sb;
let yc = sb_y * 4 + y_in_sb;
let _ctx_idx =
calc_sig_coeff_flag_ctx(xc, yc, log2_size, c_idx, scan_idx, prev_csbf);
rc_eprintln!(
"{_rcp}_SIG n={} pos=({},{}) ctx={} val={} range={} byte={}",
n,
xc,
yc,
_ctx_idx,
if sig { 1 } else { 0 },
_range,
_byte_pos
);
}
if sig {
coeff_flags[n as usize] = true;
coeff_values[n as usize] = 1;
num_coeffs += 1;
can_infer_dc = false; }
}
if start_pos > 0 {
if can_infer_dc {
coeff_flags[0] = true;
coeff_values[0] = 1;
num_coeffs += 1;
if rc_trace {
rc_eprintln!("{_rcp}_SIG n=0 DC_INFERRED");
}
} else {
let sig = decode_sig_coeff_flag(
cabac, ctx, c_idx, 0, log2_size, scan_idx, sb_x, sb_y, prev_csbf, scan_pos,
)?;
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
let _ctx_idx = calc_sig_coeff_flag_ctx(
sb_x * 4,
sb_y * 4,
log2_size,
c_idx,
scan_idx,
prev_csbf,
);
rc_eprintln!(
"{_rcp}_SIG n=0 pos=({},{}) ctx={} val={} range={} byte={}",
sb_x * 4,
sb_y * 4,
_ctx_idx,
if sig { 1 } else { 0 },
_range,
_byte_pos
);
}
if sig {
coeff_flags[0] = true;
coeff_values[0] = 1;
num_coeffs += 1;
}
}
}
if num_coeffs == 0 {
continue;
}
let base = if sb_idx == 0 || c_idx > 0 { 0 } else { 2 };
let ctx_set = base + if prev_subblock_had_gt1 { 1 } else { 0 };
if rc_trace {
rc_eprintln!(
"{_rcp}_COEFF sb_idx={} num_coeffs={} ctx_set={}",
sb_idx,
num_coeffs,
ctx_set
);
}
let mut this_subblock_had_gt1 = false;
let mut greater1_ctx = 1u8;
let mut last_greater1_flag = false;
let mut first_g1_idx: Option<u8> = None;
let mut g1_positions = [false; 16]; let max_g1 = (num_coeffs as usize).min(8);
let mut g1_count = 0;
let mut needs_remaining = [false; 16];
for n in (0..=start_pos).rev() {
if !coeff_flags[n as usize] {
continue;
}
if g1_count >= max_g1 {
needs_remaining[n as usize] = true;
continue;
}
if g1_count > 0 && greater1_ctx > 0 {
if last_greater1_flag {
greater1_ctx = 0;
} else {
greater1_ctx += 1;
}
}
let g1 = decode_coeff_greater1_flag(cabac, ctx, c_idx, ctx_set, greater1_ctx)?;
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
let _full_ctx = context::COEFF_ABS_LEVEL_GREATER1_FLAG
+ if c_idx > 0 { 16 } else { 0 }
+ (ctx_set as usize) * 4
+ (greater1_ctx as usize).min(3);
rc_eprintln!(
"{_rcp}_G1 c={} ctxSet={} g1ctx={} fullCtx={} val={} range={} byte={}",
g1_count,
ctx_set,
greater1_ctx,
_full_ctx,
if g1 { 1 } else { 0 },
_range,
_byte_pos
);
}
last_greater1_flag = g1;
if g1 {
coeff_values[n as usize] = 2;
g1_positions[n as usize] = true;
this_subblock_had_gt1 = true; if first_g1_idx.is_none() {
first_g1_idx = Some(n);
} else {
needs_remaining[n as usize] = true;
}
}
g1_count += 1;
}
if let Some(g1_idx) = first_g1_idx {
let g2 = decode_coeff_greater2_flag(cabac, ctx, c_idx, ctx_set)?;
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
rc_eprintln!(
"{_rcp}_G2 ctxSet={} val={} range={} byte={}",
ctx_set,
if g2 { 1 } else { 0 },
_range,
_byte_pos
);
}
if g2 {
coeff_values[g1_idx as usize] = 3;
needs_remaining[g1_idx as usize] = true;
}
}
let mut first_sig_pos = None;
let mut last_sig_pos = None;
for n in 0..=start_pos {
if coeff_flags[n as usize] {
if first_sig_pos.is_none() {
first_sig_pos = Some(n);
}
last_sig_pos = Some(n);
}
}
let first_sig_pos = first_sig_pos.unwrap_or(0);
let last_sig_pos = last_sig_pos.unwrap_or(start_pos);
let sign_hidden =
sign_data_hiding_enabled && !cu_transquant_bypass && (last_sig_pos - first_sig_pos) > 3;
let mut sig_positions = [0u8; 16];
let mut n_sig = 0usize;
for n in (0..=start_pos).rev() {
if coeff_flags[n as usize] {
sig_positions[n_sig] = n;
n_sig += 1;
}
}
let mut coeff_signs = [0u8; 16];
for (i, sign) in coeff_signs[..n_sig.saturating_sub(1)]
.iter_mut()
.enumerate()
{
*sign = cabac.decode_bypass()?;
let _ = i;
}
if n_sig > 0 && !sign_hidden {
coeff_signs[n_sig - 1] = cabac.decode_bypass()?;
}
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
rc_eprintln!(
"{_rcp}_SIGNS n_sig={} hidden={} signs={:?} range={} byte={}",
n_sig,
sign_hidden,
&coeff_signs[..n_sig],
_range,
_byte_pos
);
}
let mut rice_param = 0u8;
for n in (0..=start_pos).rev() {
if coeff_flags[n as usize] && needs_remaining[n as usize] {
let base = coeff_values[n as usize];
let (remaining, new_rice) =
decode_coeff_abs_level_remaining(cabac, rice_param, base)?;
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
rc_eprintln!(
"{_rcp}_REM n={} base={} rice={} rem={} final={} range={} byte={}",
n,
base,
rice_param,
remaining,
base + remaining,
_range,
_byte_pos
);
}
rice_param = new_rice;
coeff_values[n as usize] = base.saturating_add(remaining);
}
}
let mut sum_abs_level = 0i32;
for (i, &pos) in sig_positions[..n_sig].iter().enumerate() {
let pos = pos as usize;
if coeff_signs[i] != 0 {
coeff_values[pos] = -coeff_values[pos];
}
sum_abs_level += coeff_values[pos] as i32;
if i == n_sig - 1 && sign_hidden && (sum_abs_level & 1) != 0 {
coeff_values[pos] = -coeff_values[pos];
}
}
for (n, &(px, py)) in scan_pos.iter().enumerate() {
if coeff_flags[n] {
let x = sb_x as usize * 4 + px as usize;
let y = sb_y as usize * 4 + py as usize;
buffer.set(x, y, coeff_values[n]);
if coeff_values[n].abs() > 500 {
let (_byte_pos, _, _) = cabac.get_position();
debug::track_large_coeff(_byte_pos);
}
}
}
prev_subblock_had_gt1 = this_subblock_had_gt1;
}
if rc_trace {
let (_range, _, _) = cabac.get_state_extended();
let (_byte_pos, _, _) = cabac.get_position();
rc_eprintln!("{_rcp}_END range={} byte={}", _range, _byte_pos);
}
Ok((buffer, transform_skip))
}
fn get_scan_sub_block(log2_size: u8, order: ScanOrder) -> &'static [(u8, u8)] {
static SCAN_1X1: [(u8, u8); 1] = [(0, 0)];
static SCAN_2X2_DIAG: [(u8, u8); 4] = [(0, 0), (0, 1), (1, 0), (1, 1)];
static SCAN_2X2_HORIZ: [(u8, u8); 4] = [(0, 0), (1, 0), (0, 1), (1, 1)];
#[allow(dead_code)]
static SCAN_2X2_VERT: [(u8, u8); 4] = [(0, 0), (0, 1), (1, 0), (1, 1)];
static SCAN_4X4_DIAG: [(u8, u8); 16] = [
(0, 0),
(0, 1),
(1, 0),
(0, 2),
(1, 1),
(2, 0),
(0, 3),
(1, 2),
(2, 1),
(3, 0),
(1, 3),
(2, 2),
(3, 1),
(2, 3),
(3, 2),
(3, 3),
];
static SCAN_8X8_DIAG: [(u8, u8); 64] = [
(0, 0),
(0, 1),
(1, 0),
(0, 2),
(1, 1),
(2, 0),
(0, 3),
(1, 2),
(2, 1),
(3, 0),
(0, 4),
(1, 3),
(2, 2),
(3, 1),
(4, 0),
(0, 5),
(1, 4),
(2, 3),
(3, 2),
(4, 1),
(5, 0),
(0, 6),
(1, 5),
(2, 4),
(3, 3),
(4, 2),
(5, 1),
(6, 0),
(0, 7),
(1, 6),
(2, 5),
(3, 4),
(4, 3),
(5, 2),
(6, 1),
(7, 0),
(1, 7),
(2, 6),
(3, 5),
(4, 4),
(5, 3),
(6, 2),
(7, 1),
(2, 7),
(3, 6),
(4, 5),
(5, 4),
(6, 3),
(7, 2),
(3, 7),
(4, 6),
(5, 5),
(6, 4),
(7, 3),
(4, 7),
(5, 6),
(6, 5),
(7, 4),
(5, 7),
(6, 6),
(7, 5),
(6, 7),
(7, 6),
(7, 7),
];
match log2_size {
2 => &SCAN_1X1,
3 => match order {
ScanOrder::Horizontal => &SCAN_2X2_HORIZ,
_ => &SCAN_2X2_DIAG, },
4 => &SCAN_4X4_DIAG,
5 => &SCAN_8X8_DIAG,
_ => &SCAN_1X1,
}
}
fn find_scan_pos(scan: &[(u8, u8)], x: u32, y: u32, _width: u32) -> u32 {
for (i, &(sx, sy)) in scan.iter().enumerate() {
if sx as u32 == x && sy as u32 == y {
return i as u32;
}
}
0
}
fn find_scan_pos_4x4(scan: &[(u8, u8); 16], x: u8, y: u8) -> u8 {
for (i, &(sx, sy)) in scan.iter().enumerate() {
if sx == x && sy == y {
return i as u8;
}
}
0
}
fn decode_last_sig_coeff_pos(
cabac: &mut CabacDecoder<'_>,
ctx: &mut [ContextModel],
log2_size: u8,
c_idx: u8,
) -> Result<(u32, u32)> {
let x_prefix = decode_last_sig_coeff_prefix(cabac, ctx, log2_size, c_idx, true)?;
let y_prefix = decode_last_sig_coeff_prefix(cabac, ctx, log2_size, c_idx, false)?;
let x = if x_prefix > 3 {
let n_bits = (x_prefix >> 1) - 1;
let suffix = cabac.decode_bypass_bits(n_bits as u8)?;
((2 + (x_prefix & 1)) << n_bits) + suffix
} else {
x_prefix
};
let y = if y_prefix > 3 {
let n_bits = (y_prefix >> 1) - 1;
let suffix = cabac.decode_bypass_bits(n_bits as u8)?;
((2 + (y_prefix & 1)) << n_bits) + suffix
} else {
y_prefix
};
Ok((x, y))
}
fn decode_last_sig_coeff_prefix(
cabac: &mut CabacDecoder<'_>,
ctx: &mut [ContextModel],
log2_size: u8,
c_idx: u8,
is_x: bool,
) -> Result<u32> {
let ctx_base = if is_x {
context::LAST_SIG_COEFF_X_PREFIX
} else {
context::LAST_SIG_COEFF_Y_PREFIX
};
let (ctx_offset, ctx_shift) = if c_idx == 0 {
let offset = 3 * (log2_size as usize - 2) + ((log2_size as usize - 1) >> 2);
let shift = (log2_size + 1) >> 2;
(offset, shift)
} else {
(15, log2_size - 2)
};
let max_prefix = (log2_size << 1) - 1;
let mut prefix = 0u32;
while prefix < max_prefix as u32 {
let ctx_idx = ctx_base + ctx_offset + (prefix as usize >> ctx_shift as usize);
let bin = cabac.decode_bin(&mut ctx[ctx_idx])?;
if bin == 0 {
break;
}
prefix += 1;
}
Ok(prefix)
}
fn decode_coded_sub_block_flag(
cabac: &mut CabacDecoder<'_>,
ctx: &mut [ContextModel],
c_idx: u8,
csbf_neighbors: u8, ) -> Result<bool> {
let csbf_ctx = if csbf_neighbors != 0 { 1 } else { 0 };
let ctx_idx = context::CODED_SUB_BLOCK_FLAG + csbf_ctx + if c_idx > 0 { 2 } else { 0 };
Ok(cabac.decode_bin(&mut ctx[ctx_idx])? != 0)
}
static CTX_IDX_MAP_4X4: [u8; 16] = [0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8];
fn calc_sig_coeff_flag_ctx(
x_c: u8,
y_c: u8,
log2_size: u8,
c_idx: u8,
scan_idx: u8,
prev_csbf: u8,
) -> usize {
let sb_width = 1u8 << (log2_size - 2);
let sig_ctx = if sb_width == 1 {
CTX_IDX_MAP_4X4[(y_c as usize * 4 + x_c as usize).min(15)]
} else if x_c == 0 && y_c == 0 {
0
} else {
let x_s = x_c >> 2;
let y_s = y_c >> 2;
let x_p = x_c & 3;
let y_p = y_c & 3;
let mut ctx = match prev_csbf {
0 => {
if x_p + y_p >= 3 {
0
} else if x_p + y_p > 0 {
1
} else {
2
}
}
1 => {
if y_p == 0 {
2
} else if y_p == 1 {
1
} else {
0
}
}
2 => {
if x_p == 0 {
2
} else if x_p == 1 {
1
} else {
0
}
}
_ => {
2
}
};
if c_idx == 0 {
if x_s + y_s > 0 {
ctx += 3; }
if sb_width == 2 {
ctx += if scan_idx == 0 { 9 } else { 15 };
} else {
ctx += 21;
}
} else {
if sb_width == 2 {
ctx += 9;
} else {
ctx += 12;
}
}
ctx
};
context::SIG_COEFF_FLAG + if c_idx > 0 { 27 } else { 0 } + sig_ctx as usize
}
#[allow(clippy::too_many_arguments)]
fn decode_sig_coeff_flag(
cabac: &mut CabacDecoder<'_>,
ctx: &mut [ContextModel],
c_idx: u8,
pos: u8,
log2_size: u8,
scan_idx: u8,
sb_x: u8,
sb_y: u8,
prev_csbf: u8,
scan_table: &[(u8, u8); 16],
) -> Result<bool> {
let (x_in_sb, y_in_sb) = scan_table[pos as usize];
let x_c = sb_x * 4 + x_in_sb;
let y_c = sb_y * 4 + y_in_sb;
let ctx_idx = calc_sig_coeff_flag_ctx(x_c, y_c, log2_size, c_idx, scan_idx, prev_csbf);
Ok(cabac.decode_bin(&mut ctx[ctx_idx])? != 0)
}
fn decode_coeff_greater1_flag(
cabac: &mut CabacDecoder<'_>,
ctx: &mut [ContextModel],
c_idx: u8,
ctx_set: u8,
greater1_ctx: u8,
) -> Result<bool> {
let ctx_idx = context::COEFF_ABS_LEVEL_GREATER1_FLAG
+ if c_idx > 0 { 16 } else { 0 }
+ (ctx_set as usize) * 4
+ (greater1_ctx as usize).min(3);
Ok(cabac.decode_bin(&mut ctx[ctx_idx])? != 0)
}
fn decode_coeff_greater2_flag(
cabac: &mut CabacDecoder<'_>,
ctx: &mut [ContextModel],
c_idx: u8,
ctx_set: u8,
) -> Result<bool> {
let ctx_idx =
context::COEFF_ABS_LEVEL_GREATER2_FLAG + if c_idx > 0 { 4 } else { 0 } + ctx_set as usize;
Ok(cabac.decode_bin(&mut ctx[ctx_idx])? != 0)
}
fn decode_coeff_abs_level_remaining(
cabac: &mut CabacDecoder<'_>,
rice_param: u8,
base_level: i16,
) -> Result<(i16, u8)> {
let mut prefix = 0u32;
while cabac.decode_bypass()? != 0 && prefix < 24 {
prefix += 1;
}
let value = if prefix <= 3 {
let suffix = if rice_param > 0 {
cabac.decode_bypass_bits(rice_param)?
} else {
0
};
((prefix << rice_param) + suffix) as i16
} else {
let suffix_bits = (prefix - 3 + rice_param as u32) as u8;
let suffix = cabac.decode_bypass_bits(suffix_bits)?;
let base = ((1u32 << (prefix - 3)) + 2) << rice_param;
(base + suffix) as i16
};
let threshold = 3 * (1 << rice_param);
let new_rice_param = if (base_level.unsigned_abs() as u32)
.saturating_add(value.unsigned_abs() as u32)
> threshold
{
(rice_param + 1).min(4)
} else {
rice_param
};
Ok((value, new_rice_param))
}