#[rustfmt::skip]
static TRANSITION_MPS: [u8; 64] = [
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 52, 53, 54, 55, 56,
57, 58, 59, 60, 61, 62, 62, 63,
];
#[rustfmt::skip]
static TRANSITION_LPS: [u8; 64] = [
0, 0, 1, 2, 2, 4, 4, 5,
6, 7, 8, 9, 9, 11, 11, 12,
13, 13, 15, 15, 16, 16, 18, 18,
19, 19, 21, 21, 22, 22, 23, 24,
24, 25, 26, 26, 27, 27, 28, 29,
29, 30, 30, 30, 31, 32, 32, 33,
33, 33, 34, 34, 35, 35, 35, 36,
36, 36, 37, 37, 37, 38, 38, 63,
];
#[rustfmt::skip]
static RANGE_TABLE: [[u16; 4]; 64] = [
[128, 176, 208, 240],
[128, 167, 197, 227],
[128, 158, 187, 216],
[123, 150, 178, 205],
[116, 142, 169, 195],
[111, 135, 160, 185],
[105, 128, 152, 175],
[100, 122, 144, 166],
[ 95, 116, 137, 158],
[ 90, 110, 130, 150],
[ 85, 104, 123, 142],
[ 81, 99, 117, 135],
[ 77, 94, 111, 128],
[ 73, 89, 105, 122],
[ 69, 85, 100, 116],
[ 66, 80, 95, 110],
[ 62, 76, 90, 104],
[ 59, 72, 86, 99],
[ 56, 69, 81, 94],
[ 53, 65, 77, 89],
[ 51, 62, 73, 85],
[ 48, 59, 69, 80],
[ 46, 56, 66, 76],
[ 43, 53, 63, 72],
[ 41, 50, 59, 69],
[ 39, 48, 56, 65],
[ 37, 45, 54, 62],
[ 35, 43, 51, 59],
[ 33, 41, 48, 56],
[ 32, 39, 46, 53],
[ 30, 37, 43, 50],
[ 29, 35, 41, 48],
[ 27, 33, 39, 45],
[ 26, 31, 37, 43],
[ 24, 30, 35, 41],
[ 23, 28, 33, 39],
[ 22, 27, 32, 37],
[ 21, 26, 30, 35],
[ 20, 24, 29, 33],
[ 19, 23, 27, 31],
[ 18, 22, 26, 30],
[ 17, 21, 25, 28],
[ 16, 20, 23, 27],
[ 15, 19, 22, 25],
[ 14, 18, 21, 24],
[ 14, 17, 20, 23],
[ 13, 16, 19, 22],
[ 12, 15, 18, 21],
[ 12, 14, 17, 20],
[ 11, 14, 16, 19],
[ 11, 13, 15, 18],
[ 10, 12, 15, 17],
[ 10, 12, 14, 16],
[ 9, 11, 13, 15],
[ 9, 11, 12, 14],
[ 8, 10, 12, 14],
[ 8, 9, 11, 13],
[ 7, 9, 11, 12],
[ 7, 9, 10, 12],
[ 7, 8, 10, 11],
[ 6, 8, 9, 11],
[ 6, 7, 9, 10],
[ 6, 7, 8, 9],
[ 2, 2, 2, 2],
];
pub const NUM_CABAC_CONTEXTS: usize = 460;
#[derive(Debug, Clone)]
pub struct CabacContext {
pub state: u8,
pub mps: bool,
}
impl CabacContext {
pub fn new(slice_qp: i32, init_value: i16) -> Self {
let m = (init_value >> 4) * 5 - 45;
let n = ((init_value & 15) << 3) - 16;
let pre = ((m * (slice_qp.clamp(0, 51) as i16 - 16)) >> 4) + n;
let pre = pre.clamp(1, 126);
if pre <= 63 {
CabacContext {
state: (63 - pre) as u8,
mps: false,
}
} else {
CabacContext {
state: (pre - 64) as u8,
mps: true,
}
}
}
pub fn equiprobable() -> Self {
CabacContext {
state: 0,
mps: false,
}
}
}
fn init_cabac_context_direct(slice_qp: i32, m: i16, n: i16) -> CabacContext {
let pre = ((m as i32 * (slice_qp.clamp(0, 51) - 16)) >> 4) + n as i32;
let pre = pre.clamp(1, 126);
if pre <= 63 {
CabacContext {
state: (63 - pre) as u8,
mps: false,
}
} else {
CabacContext {
state: (pre - 64) as u8,
mps: true,
}
}
}
pub fn init_cabac_contexts(slice_qp: i32) -> Vec<CabacContext> {
let mut mn_pairs = vec![(0i16, 0i16); NUM_CABAC_CONTEXTS];
let mb_type_i: [(i16, i16); 8] = [
(20, 29), (2, 26), (0, 27), (0, 27), (0, 27), (0, 27), (0, 27), (0, 27), ];
for (i, &(m, n)) in mb_type_i.iter().enumerate() {
mn_pairs[3 + i] = (m, n);
}
let qp_delta: [(i16, i16); 9] = [
(0, 39), (0, 39), (0, 39), (0, 39), (0, 39), (0, 39), (0, 39), (0, 39), (0, 39), ];
for (i, &(m, n)) in qp_delta.iter().enumerate() {
mn_pairs[60 + i] = (m, n);
}
let cbp_luma: [(i16, i16); 4] = [
(0, 41), (-3, 40), (-7, 39), (-5, 44), ];
for (i, &(m, n)) in cbp_luma.iter().enumerate() {
mn_pairs[73 + i] = (m, n);
}
let cbp_chroma: [(i16, i16); 8] = [
(-11, 43), (-15, 39), (-4, 44), (-7, 43), (-11, 43), (-15, 39), (-4, 44), (-7, 43), ];
for (i, &(m, n)) in cbp_chroma.iter().enumerate() {
mn_pairs[77 + i] = (m, n);
}
let coded_block_flag: [(i16, i16); 20] = [
(0, 45), (-2, 40), (-6, 41), (-7, 44), (0, 49), (-3, 44), (-7, 40), (-5, 45), (0, 45), (-2, 40), (-6, 41), (-7, 44), (-12, 56), (-11, 51), (-10, 52), (-8, 48), (-1, 42), (-1, 36), (-7, 42), (-6, 40), ];
for (i, &(m, n)) in coded_block_flag.iter().enumerate() {
mn_pairs[85 + i] = (m, n);
}
let sig_coeff_flag: [(i16, i16); 61] = [
(-2, 13), (-6, 17), (-3, 14), (-5, 17), (-8, 21), (-5, 15), (-4, 16), (-4, 17), (-6, 20), (-10, 24), (-3, 12), (-3, 14), (-3, 16), (-6, 17), (-8, 17), (-4, 15), (-3, 14), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), (-3, 14), (-4, 16), (-7, 19), (-3, 13), ];
for (i, &(m, n)) in sig_coeff_flag.iter().enumerate() {
mn_pairs[105 + i] = (m, n);
}
let last_sig_coeff_flag: [(i16, i16); 61] = [
(1, 7), (1, 7), (0, 11), (-1, 15), (-1, 15), (-2, 17), (-4, 21), (-1, 13), (-1, 15), (-2, 18), (-5, 22), (-3, 17), (-1, 14), (-2, 16), (-5, 19), (-2, 14), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), (-1, 12), (-2, 14), (-4, 17), (-1, 12), ];
for (i, &(m, n)) in last_sig_coeff_flag.iter().enumerate() {
mn_pairs[166 + i] = (m, n);
}
let coeff_abs_level: [(i16, i16); 49] = [
(-7, 21), (-5, 22), (-4, 22), (-3, 20), (-1, 16), (-8, 24), (-5, 22), (-4, 21), (-3, 18), (-1, 14), (-7, 21), (-5, 22), (-4, 22), (-3, 20), (-1, 16), (-8, 24), (-5, 22), (-4, 21), (-3, 18), (-1, 14), (-7, 21), (-5, 22), (-4, 22), (-3, 20), (-1, 16), (-8, 24), (-5, 22), (-4, 21), (-3, 18), (-1, 14), (-13, 30), (-12, 30), (-9, 27), (-6, 22), (-2, 16), (-7, 21), (-5, 22), (-4, 22), (-3, 20), (-1, 16), (-8, 24), (-5, 22), (-4, 21), (-3, 18), (-1, 14), (-7, 21), (-5, 22), (-4, 22), (-3, 20), ];
for (i, &(m, n)) in coeff_abs_level.iter().enumerate() {
mn_pairs[227 + i] = (m, n);
}
mn_pairs
.iter()
.map(|&(m, n)| init_cabac_context_direct(slice_qp, m, n))
.collect()
}
pub struct CabacDecoder<'a> {
data: &'a [u8],
offset: usize,
bits_left: u32,
range: u32,
value: u32,
}
impl<'a> CabacDecoder<'a> {
pub fn new(data: &'a [u8]) -> Self {
let mut dec = CabacDecoder {
data,
offset: 0,
bits_left: 0,
range: 510,
value: 0,
};
dec.value = dec.read_bits(9);
dec
}
#[inline(always)]
fn read_bit(&mut self) -> u32 {
if self.bits_left == 0 {
if self.offset < self.data.len() {
self.bits_left = 8;
self.offset += 1;
} else {
return 0;
}
}
self.bits_left -= 1;
let byte = self.data[self.offset - 1];
(u32::from(byte) >> self.bits_left) & 1
}
fn read_bits(&mut self, n: u32) -> u32 {
let mut val = 0u32;
for _ in 0..n {
val = (val << 1) | self.read_bit();
}
val
}
#[inline(always)]
fn renorm(&mut self) {
while self.range < 256 {
self.range <<= 1;
self.value = (self.value << 1) | self.read_bit();
}
}
#[inline(always)]
pub fn decode_decision(&mut self, ctx: &mut CabacContext) -> bool {
let q_idx = (self.range >> 6) & 3;
let lps_range = RANGE_TABLE[ctx.state as usize][q_idx as usize] as u32;
self.range -= lps_range;
if self.value < self.range {
ctx.state = TRANSITION_MPS[ctx.state as usize];
self.renorm();
ctx.mps
} else {
self.value -= self.range;
self.range = lps_range;
if ctx.state == 0 {
ctx.mps = !ctx.mps;
}
ctx.state = TRANSITION_LPS[ctx.state as usize];
self.renorm();
!ctx.mps
}
}
#[inline(always)]
pub fn decode_bypass(&mut self) -> bool {
self.value = (self.value << 1) | self.read_bit();
if self.value >= self.range {
self.value -= self.range;
true
} else {
false
}
}
pub fn decode_terminate(&mut self) -> bool {
self.range -= 2;
if self.value >= self.range {
true
} else {
self.renorm();
false
}
}
pub fn bytes_remaining(&self) -> usize {
let full_bytes = self.data.len().saturating_sub(self.offset);
if self.bits_left > 0 {
full_bytes + 1
} else {
full_bytes
}
}
}
pub fn decode_unary(decoder: &mut CabacDecoder<'_>, ctx: &mut CabacContext, max_bins: u32) -> u32 {
let mut val = 0u32;
while val < max_bins {
if decoder.decode_decision(ctx) {
val += 1;
} else {
return val;
}
}
val
}
pub fn decode_truncated_unary(
decoder: &mut CabacDecoder<'_>,
ctx: &mut CabacContext,
max_val: u32,
) -> u32 {
if max_val == 0 {
return 0;
}
let mut val = 0u32;
while val < max_val {
if decoder.decode_decision(ctx) {
val += 1;
} else {
return val;
}
}
val
}
pub fn decode_fixed_length(decoder: &mut CabacDecoder<'_>, n: u32) -> u32 {
let mut val = 0u32;
for _ in 0..n {
val = (val << 1) | (decoder.decode_bypass() as u32);
}
val
}
pub fn decode_exp_golomb_bypass(decoder: &mut CabacDecoder<'_>, k: u32) -> u32 {
let mut order = 0u32;
while decoder.decode_bypass() {
order += 1;
if order > 16 {
return 0; }
}
let suffix_len = order + k;
let mut val = (1u32 << order) - 1;
if suffix_len > 0 {
val += decode_fixed_length(decoder, suffix_len);
}
val
}
pub mod ctx {
pub const MB_TYPE_I_START: usize = 3;
pub const MB_TYPE_P_START: usize = 14;
pub const CODED_BLOCK_FLAG_LUMA: usize = 85;
pub const SIGNIFICANT_COEFF_START: usize = 105;
pub const LAST_SIGNIFICANT_COEFF_START: usize = 166;
pub const COEFF_ABS_LEVEL_START: usize = 227;
}
pub fn decode_mb_type_i_slice(
decoder: &mut CabacDecoder<'_>,
contexts: &mut [CabacContext],
) -> u32 {
let ci = ctx::MB_TYPE_I_START;
if !decoder.decode_decision(&mut contexts[ci]) {
return 0; }
if decoder.decode_decision(&mut contexts[ci + 1]) {
return 25; }
let cbp_luma = decoder.decode_decision(&mut contexts[ci + 2]) as u32;
let cbp_c0 = decoder.decode_decision(&mut contexts[ci + 3]) as u32;
let cbp_chroma = if cbp_c0 == 0 {
0u32
} else if decoder.decode_decision(&mut contexts[ci + 4]) {
2
} else {
1
};
let pred0 = decoder.decode_decision(&mut contexts[ci + 5]) as u32;
let pred1 = decoder.decode_decision(&mut contexts[ci + 6]) as u32;
let pred_mode = (pred0 << 1) | pred1;
1 + cbp_luma * 12 + cbp_chroma * 4 + pred_mode
}
pub fn decode_mb_type_p_slice(
decoder: &mut CabacDecoder<'_>,
contexts: &mut [CabacContext],
) -> u32 {
let ci = ctx::MB_TYPE_P_START;
if !decoder.decode_decision(&mut contexts[ci]) {
if !decoder.decode_decision(&mut contexts[ci + 1]) {
return 0; }
if !decoder.decode_decision(&mut contexts[ci + 2]) {
return 1; }
return 2; }
if !decoder.decode_decision(&mut contexts[ci + 3]) {
return 3; }
let intra_type = decode_mb_type_i_slice(decoder, contexts);
5 + intra_type
}
pub fn decode_coded_block_flag(
decoder: &mut CabacDecoder<'_>,
contexts: &mut [CabacContext],
cat_offset: usize,
) -> bool {
let ci = (ctx::CODED_BLOCK_FLAG_LUMA + cat_offset * 4).min(contexts.len() - 1);
decoder.decode_decision(&mut contexts[ci])
}
pub fn decode_residual_block_cabac(
decoder: &mut CabacDecoder<'_>,
contexts: &mut [CabacContext],
max_num_coeff: usize,
) -> Vec<i32> {
let mut coeffs = vec![0i32; max_num_coeff];
let mut significant = vec![false; max_num_coeff];
let mut last = vec![false; max_num_coeff];
let mut num_coeff = 0usize;
let max_scan = max_num_coeff.saturating_sub(1);
for i in 0..max_scan {
let sig_ctx = if max_num_coeff <= 4 {
ctx::SIGNIFICANT_COEFF_START + i.min(3)
} else if max_num_coeff <= 16 {
ctx::SIGNIFICANT_COEFF_START + i.min(14)
} else {
ctx::SIGNIFICANT_COEFF_START + (i >> 2).min(14)
};
let sig_ctx = sig_ctx.min(contexts.len() - 1);
significant[i] = decoder.decode_decision(&mut contexts[sig_ctx]);
if significant[i] {
let last_ctx = if max_num_coeff <= 4 {
ctx::LAST_SIGNIFICANT_COEFF_START + i.min(3)
} else if max_num_coeff <= 16 {
ctx::LAST_SIGNIFICANT_COEFF_START + i.min(14)
} else {
ctx::LAST_SIGNIFICANT_COEFF_START + (i >> 2).min(14)
};
let last_ctx = last_ctx.min(contexts.len() - 1);
last[i] = decoder.decode_decision(&mut contexts[last_ctx]);
num_coeff += 1;
if last[i] {
break;
}
}
}
if num_coeff > 0 && !last.iter().any(|&l| l) {
significant[max_num_coeff - 1] = true;
num_coeff += 1;
}
if num_coeff == 0 {
return coeffs;
}
let sig_positions: Vec<usize> = (0..max_num_coeff).filter(|&i| significant[i]).collect();
let mut num_gt1 = 0u32;
let mut num_t1 = 0u32;
for &pos in sig_positions.iter().rev() {
let base_ctx = ctx::COEFF_ABS_LEVEL_START;
let ci0 = (base_ctx + num_t1.min(4) as usize).min(contexts.len() - 1);
let prefix_bin0 = decoder.decode_decision(&mut contexts[ci0]);
let abs_level = if !prefix_bin0 {
1u32 } else {
let mut abs_minus1 = 1u32;
let ci_rest = (base_ctx + 5 + num_gt1.min(4) as usize).min(contexts.len() - 1);
while abs_minus1 < 14 {
if !decoder.decode_decision(&mut contexts[ci_rest]) {
break;
}
abs_minus1 += 1;
}
if abs_minus1 >= 14 {
abs_minus1 += decode_exp_golomb_bypass(decoder, 0);
}
abs_minus1 + 1
};
let sign = decoder.decode_bypass();
coeffs[pos] = if sign {
-(abs_level as i32)
} else {
abs_level as i32
};
if abs_level == 1 {
num_t1 += 1;
}
if abs_level > 1 {
num_gt1 += 1;
num_t1 = 0; }
}
coeffs
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntropyCodingMode {
Cavlc,
Cabac,
}
impl EntropyCodingMode {
pub fn from_flag(flag: bool) -> Self {
if flag {
EntropyCodingMode::Cabac
} else {
EntropyCodingMode::Cavlc
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cabac_context_init_equiprobable() {
let ctx = CabacContext::equiprobable();
assert_eq!(ctx.state, 0);
assert!(!ctx.mps);
}
#[test]
fn test_cabac_context_init_from_value() {
let ctx = CabacContext::new(26, 0x7E);
assert_eq!(ctx.state, 25);
assert!(ctx.mps);
}
#[test]
fn test_cabac_decode_bypass_deterministic() {
let data = [0x00, 0x00, 0x00, 0x00];
let mut dec = CabacDecoder::new(&data);
for _ in 0..8 {
assert!(!dec.decode_bypass());
}
}
#[test]
fn test_cabac_decode_terminate_on_end() {
let data = [0xFF, 0xFF, 0xFF, 0xFF];
let mut dec = CabacDecoder::new(&data);
assert!(dec.decode_terminate());
}
#[test]
fn test_cabac_decode_decision_updates_state() {
let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let mut dec = CabacDecoder::new(&data);
let mut ctx = CabacContext::equiprobable();
let initial_state = ctx.state;
let _bin = dec.decode_decision(&mut ctx);
assert!(ctx.state <= 63);
let _ = initial_state;
}
#[test]
fn test_decode_unary_zero() {
let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let mut dec = CabacDecoder::new(&data);
let mut ctx = CabacContext::equiprobable();
let val = decode_unary(&mut dec, &mut ctx, 10);
assert_eq!(val, 0);
}
#[test]
fn test_fixed_length_decode() {
let data = [0xFF, 0xFF, 0xFF, 0xFF];
let mut dec = CabacDecoder::new(&data);
let val = decode_fixed_length(&mut dec, 3);
assert_eq!(val, 7);
}
#[test]
fn test_entropy_coding_mode_from_flag() {
assert_eq!(
EntropyCodingMode::from_flag(false),
EntropyCodingMode::Cavlc
);
assert_eq!(EntropyCodingMode::from_flag(true), EntropyCodingMode::Cabac);
}
#[test]
fn test_init_cabac_contexts_count() {
let contexts = init_cabac_contexts(26);
assert_eq!(contexts.len(), NUM_CABAC_CONTEXTS);
}
#[test]
fn test_decode_residual_block_length() {
let data = [0x00; 32];
let mut dec = CabacDecoder::new(&data);
let mut contexts = init_cabac_contexts(26);
let coeffs = decode_residual_block_cabac(&mut dec, &mut contexts, 16);
assert_eq!(coeffs.len(), 16);
let data2 = [0x00; 32];
let mut dec2 = CabacDecoder::new(&data2);
let mut contexts2 = init_cabac_contexts(26);
let coeffs2 = decode_residual_block_cabac(&mut dec2, &mut contexts2, 4);
assert_eq!(coeffs2.len(), 4);
}
#[test]
fn test_transition_table_bounds() {
for &s in TRANSITION_MPS.iter() {
assert!(s <= 63);
}
for &s in TRANSITION_LPS.iter() {
assert!(s <= 63);
}
}
#[test]
fn test_range_table_positive() {
for row in RANGE_TABLE.iter() {
for &val in row.iter() {
assert!(val > 0);
}
}
}
}