pub struct BitReader<'a> {
pub(crate) data: &'a [u8],
pub(crate) byte_pos: usize,
pub(crate) bit_pos: u8, }
impl<'a> BitReader<'a> {
pub const fn new(data: &'a [u8]) -> Self {
Self {
data,
byte_pos: 0,
bit_pos: 0,
}
}
pub const fn new_at(data: &'a [u8], byte_pos: usize, bit_pos: u8) -> Self {
Self {
data,
byte_pos,
bit_pos,
}
}
pub const fn align_byte(&mut self) {
if self.bit_pos != 0 {
self.consume(8 - self.bit_pos);
}
}
pub fn more_rbsp_data(&self) -> bool {
let cur = self.byte_pos * 8 + self.bit_pos as usize;
for (i, &b) in self.data.iter().enumerate().rev() {
if b != 0 {
let last_one = i * 8 + 7 - b.trailing_zeros() as usize;
return cur < last_one;
}
}
false
}
pub const fn bits_remaining(&self) -> usize {
if self.byte_pos >= self.data.len() {
return 0;
}
(self.data.len() - self.byte_pos) * 8 - self.bit_pos as usize
}
pub fn read_bits(&mut self, n: u8) -> Option<u32> {
if n == 0 {
return Some(0);
}
if n > 32 || self.bits_remaining() < n as usize {
return None;
}
let value = self.peek_padded(n);
self.consume(n);
Some(value)
}
pub fn peek_bits(&self, n: u8) -> Option<u32> {
if n == 0 {
return Some(0);
}
if n > 32 || self.bits_remaining() < n as usize {
return None;
}
Some(self.peek_padded(n))
}
fn peek_padded(&self, n: u8) -> u32 {
debug_assert!((1..=32).contains(&n));
let tail = &self.data[self.byte_pos.min(self.data.len())..];
let w = match tail.first_chunk::<8>() {
Some(chunk) => u64::from_be_bytes(*chunk),
None => {
let mut buf = [0u8; 8];
buf[..tail.len()].copy_from_slice(tail);
u64::from_be_bytes(buf)
}
};
((w << self.bit_pos) >> (64 - n as u32)) as u32
}
pub const fn consume(&mut self, n: u8) {
let total = self.byte_pos * 8 + self.bit_pos as usize + n as usize;
self.byte_pos = total / 8;
self.bit_pos = (total % 8) as u8;
}
pub fn read_ue(&mut self) -> Option<u32> {
let w = self.peek_padded(32);
let lz = w.leading_zeros();
if lz <= 15 {
let total = 2 * lz + 1;
if total as usize > self.bits_remaining() {
return None; }
self.consume(total as u8);
return Some((w >> (32 - total)) - 1);
}
let mut leading_zeros = 0u32;
loop {
let bit = self.read_bits(1)?;
if bit == 1 {
break;
}
leading_zeros += 1;
if leading_zeros > 31 {
return None;
}
}
let suffix = self.read_bits(leading_zeros as u8)?;
Some((1 << leading_zeros) - 1 + suffix)
}
pub fn read_se(&mut self) -> Option<i32> {
let code = self.read_ue()?;
let value = code.div_ceil(2) as i32;
if code % 2 == 0 {
Some(-value)
} else {
Some(value)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CavlcResult {
pub total_coeffs: usize,
pub trailing_ones: usize,
pub levels: [i32; 16],
pub total_zeros: usize,
pub runs: [u8; 16],
}
#[rustfmt::skip]
const COEFF_TOKEN_LEN: [[u8; 68]; 4] = [
[
1, 0, 0, 0,
6, 2, 0, 0, 8, 6, 3, 0, 9, 8, 7, 5, 10, 9, 8, 6,
11,10, 9, 7, 13,11,10, 8, 13,13,11, 9, 13,13,13,10,
14,14,13,11, 14,14,14,13, 15,15,14,14, 15,15,15,14,
16,15,15,15, 16,16,16,15, 16,16,16,16, 16,16,16,16,
],
[
2, 0, 0, 0,
6, 2, 0, 0, 6, 5, 3, 0, 7, 6, 6, 4, 8, 6, 6, 4,
8, 7, 7, 5, 9, 8, 8, 6, 11, 9, 9, 6, 11,11,11, 7,
12,11,11, 9, 12,12,12,11, 12,12,12,11, 13,13,13,12,
13,13,13,13, 13,14,13,13, 14,14,14,13, 14,14,14,14,
],
[
4, 0, 0, 0,
6, 4, 0, 0, 6, 5, 4, 0, 6, 5, 5, 4, 7, 5, 5, 4,
7, 5, 5, 4, 7, 6, 6, 4, 7, 6, 6, 4, 8, 7, 7, 5,
8, 8, 7, 6, 9, 8, 8, 7, 9, 9, 8, 8, 9, 9, 9, 8,
10, 9, 9, 9, 10,10,10,10, 10,10,10,10, 10,10,10,10,
],
[
6, 0, 0, 0,
6, 6, 0, 0, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
],
];
#[rustfmt::skip]
const COEFF_TOKEN_BITS: [[u8; 68]; 4] = [
[
1, 0, 0, 0,
5, 1, 0, 0, 7, 4, 1, 0, 7, 6, 5, 3, 7, 6, 5, 3,
7, 6, 5, 4, 15, 6, 5, 4, 11,14, 5, 4, 8,10,13, 4,
15,14, 9, 4, 11,10,13,12, 15,14, 9,12, 11,10,13, 8,
15, 1, 9,12, 11,14,13, 8, 7,10, 9,12, 4, 6, 5, 8,
],
[
3, 0, 0, 0,
11, 2, 0, 0, 7, 7, 3, 0, 7,10, 9, 5, 7, 6, 5, 4,
4, 6, 5, 6, 7, 6, 5, 8, 15, 6, 5, 4, 11,14,13, 4,
15,10, 9, 4, 11,14,13,12, 8,10, 9, 8, 15,14,13,12,
11,10, 9,12, 7,11, 6, 8, 9, 8,10, 1, 7, 6, 5, 4,
],
[
15, 0, 0, 0,
15,14, 0, 0, 11,15,13, 0, 8,12,14,12, 15,10,11,11,
11, 8, 9,10, 9,14,13, 9, 8,10, 9, 8, 15,14,13,13,
11,14,10,12, 15,10,13,12, 11,14, 9,12, 8,10,13, 8,
13, 7, 9,12, 9,12,11,10, 5, 8, 7, 6, 1, 4, 3, 2,
],
[
3, 0, 0, 0,
0, 1, 0, 0, 4, 5, 6, 0, 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,63,
],
];
#[rustfmt::skip]
const CHROMA_DC_COEFF_TOKEN_LEN: [u8; 20] = [
2, 0, 0, 0, 6, 1, 0, 0, 6, 6, 3, 0, 6, 7, 7, 6, 6, 8, 8, 7,
];
#[rustfmt::skip]
const CHROMA_DC_COEFF_TOKEN_BITS: [u8; 20] = [
1, 0, 0, 0, 7, 1, 0, 0, 4, 6, 1, 0, 3, 3, 2, 5, 2, 3, 2, 0,
];
#[rustfmt::skip]
const TOTAL_ZEROS_LEN: [[u8; 16]; 15] = [
[1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9],
[3,3,3,3,3,4,4,4,4,5,5,6,6,6,6,0],
[4,3,3,3,4,4,3,3,4,5,5,6,5,6,0,0],
[5,3,4,4,3,3,3,4,3,4,5,5,5,0,0,0],
[4,4,4,3,3,3,3,3,4,5,4,5,0,0,0,0],
[6,5,3,3,3,3,3,3,4,3,6,0,0,0,0,0],
[6,5,3,3,3,2,3,4,3,6,0,0,0,0,0,0],
[6,4,5,3,2,2,3,3,6,0,0,0,0,0,0,0],
[6,6,4,2,2,3,2,5,0,0,0,0,0,0,0,0],
[5,5,3,2,2,2,4,0,0,0,0,0,0,0,0,0],
[4,4,3,3,1,3,0,0,0,0,0,0,0,0,0,0],
[4,4,2,1,3,0,0,0,0,0,0,0,0,0,0,0],
[3,3,1,2,0,0,0,0,0,0,0,0,0,0,0,0],
[2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
];
#[rustfmt::skip]
const TOTAL_ZEROS_BITS: [[u8; 16]; 15] = [
[1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1],
[7,6,5,4,3,5,4,3,2,3,2,3,2,1,0,0],
[5,7,6,5,4,3,4,3,2,3,2,1,1,0,0,0],
[3,7,5,4,6,5,4,3,3,2,2,1,0,0,0,0],
[5,4,3,7,6,5,4,3,2,1,1,0,0,0,0,0],
[1,1,7,6,5,4,3,2,1,1,0,0,0,0,0,0],
[1,1,5,4,3,3,2,1,1,0,0,0,0,0,0,0],
[1,1,1,3,3,2,2,1,0,0,0,0,0,0,0,0],
[1,0,1,3,2,1,1,1,0,0,0,0,0,0,0,0],
[1,0,1,3,2,1,1,0,0,0,0,0,0,0,0,0],
[0,1,1,2,1,3,0,0,0,0,0,0,0,0,0,0],
[0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0],
[0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[0,1,1,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],
];
#[rustfmt::skip]
const CHROMA_DC_TOTAL_ZEROS_LEN: [[u8; 4]; 3] = [
[1,2,3,3],
[1,2,2,0],
[1,1,0,0],
];
#[rustfmt::skip]
const CHROMA_DC_TOTAL_ZEROS_BITS: [[u8; 4]; 3] = [
[1,1,1,0],
[1,1,0,0],
[1,0,0,0],
];
#[rustfmt::skip]
const RUN_LEN: [[u8; 16]; 7] = [
[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0],
[2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0],
[2,2,2,3,3,0,0,0,0,0,0,0,0,0,0,0],
[2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0],
[2,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0],
[3,3,3,3,3,3,3,4,5,6,7,8,9,10,11,0],
];
#[rustfmt::skip]
const RUN_BITS: [[u8; 16]; 7] = [
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[3,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
[3,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
[3,2,3,2,1,0,0,0,0,0,0,0,0,0,0,0],
[3,0,1,3,2,5,4,0,0,0,0,0,0,0,0,0],
[7,6,5,4,3,2,1,1,1,1,1,1,1,1,1,0],
];
const VLC_LUT_BITS: u8 = 9;
type VlcLut = [u16; 1 << VLC_LUT_BITS];
const fn build_vlc_lut<const N: usize>(lens: &[u8; N], bits: &[u8; N]) -> VlcLut {
let mut lut = [0u16; 1 << VLC_LUT_BITS];
let mut i = 0;
while i < N {
let len = lens[i];
if len > 0 && len <= VLC_LUT_BITS {
let lo = (bits[i] as usize) << (VLC_LUT_BITS - len);
let hi = ((bits[i] as usize) + 1) << (VLC_LUT_BITS - len);
let mut w = lo;
while w < hi {
lut[w] = ((i as u16) << 5) | len as u16;
w += 1;
}
}
i += 1;
}
lut
}
const fn build_vlc_lut_rows<const C: usize, const R: usize>(
lens: &[[u8; C]; R],
bits: &[[u8; C]; R],
) -> [VlcLut; R] {
let mut out = [[0u16; 1 << VLC_LUT_BITS]; R];
let mut r = 0;
while r < R {
out[r] = build_vlc_lut(&lens[r], &bits[r]);
r += 1;
}
out
}
static COEFF_TOKEN_LUT: [VlcLut; 4] = build_vlc_lut_rows(&COEFF_TOKEN_LEN, &COEFF_TOKEN_BITS);
static CHROMA_DC_COEFF_TOKEN_LUT: VlcLut =
build_vlc_lut(&CHROMA_DC_COEFF_TOKEN_LEN, &CHROMA_DC_COEFF_TOKEN_BITS);
static TOTAL_ZEROS_LUT: [VlcLut; 15] = build_vlc_lut_rows(&TOTAL_ZEROS_LEN, &TOTAL_ZEROS_BITS);
static CHROMA_DC_TOTAL_ZEROS_LUT: [VlcLut; 3] =
build_vlc_lut_rows(&CHROMA_DC_TOTAL_ZEROS_LEN, &CHROMA_DC_TOTAL_ZEROS_BITS);
static RUN_LUT: [VlcLut; 7] = build_vlc_lut_rows(&RUN_LEN, &RUN_BITS);
fn match_vlc(reader: &mut BitReader, lens: &[u8], bits: &[u8], lut: &VlcLut) -> Option<usize> {
let entry = lut[reader.peek_padded(VLC_LUT_BITS) as usize];
if entry != 0 {
reader.consume((entry & 31) as u8);
return Some((entry >> 5) as usize);
}
let max_len = lens.iter().copied().max().unwrap_or(0);
if max_len == 0 {
return None;
}
let window = reader.peek_padded(max_len);
for (i, (&len, &pat)) in lens.iter().zip(bits.iter()).enumerate() {
if len == 0 {
continue;
}
if (window >> (max_len - len)) == pat as u32 {
reader.consume(len);
return Some(i);
}
}
None
}
fn read_coeff_token(reader: &mut BitReader, nc: i32) -> Option<(usize, usize)> {
let idx = if nc < 0 {
match_vlc(
reader,
&CHROMA_DC_COEFF_TOKEN_LEN,
&CHROMA_DC_COEFF_TOKEN_BITS,
&CHROMA_DC_COEFF_TOKEN_LUT,
)?
} else {
let cat = match nc {
0..=1 => 0,
2..=3 => 1,
4..=7 => 2,
_ => 3,
};
match_vlc(
reader,
&COEFF_TOKEN_LEN[cat],
&COEFF_TOKEN_BITS[cat],
&COEFF_TOKEN_LUT[cat],
)?
};
Some((idx >> 2, idx & 3))
}
fn read_total_zeros(reader: &mut BitReader, total_coeff: usize, max_coeff: usize) -> Option<usize> {
if max_coeff == 4 {
let row = total_coeff - 1;
match_vlc(
reader,
&CHROMA_DC_TOTAL_ZEROS_LEN[row],
&CHROMA_DC_TOTAL_ZEROS_BITS[row],
&CHROMA_DC_TOTAL_ZEROS_LUT[row],
)
} else {
let row = total_coeff - 1;
match_vlc(
reader,
&TOTAL_ZEROS_LEN[row],
&TOTAL_ZEROS_BITS[row],
&TOTAL_ZEROS_LUT[row],
)
}
}
fn read_run_before(reader: &mut BitReader, zeros_left: usize) -> Option<usize> {
if zeros_left == 0 {
return Some(0);
}
let row = zeros_left.min(7) - 1;
match_vlc(reader, &RUN_LEN[row], &RUN_BITS[row], &RUN_LUT[row])
}
fn read_level_prefix(reader: &mut BitReader) -> Option<u32> {
let w = reader.peek_padded(32);
let lz = w.leading_zeros();
if lz >= 32 || lz as usize >= reader.bits_remaining() {
return None;
}
reader.consume(lz as u8 + 1);
Some(lz)
}
pub fn decode_cavlc_block(reader: &mut BitReader, nc: i32) -> Option<CavlcResult> {
decode_cavlc_block_max(reader, nc, 16)
}
pub fn decode_cavlc_block_max(
reader: &mut BitReader,
nc: i32,
max_coeff: usize,
) -> Option<CavlcResult> {
let (total_coeffs, trailing_ones) = read_coeff_token(reader, nc)?;
if total_coeffs > max_coeff {
return None;
}
if total_coeffs == 0 {
return Some(CavlcResult {
total_coeffs: 0,
trailing_ones: 0,
levels: [0; 16],
total_zeros: 0,
runs: [0; 16],
});
}
let mut levels = [0i32; 16];
let mut level_count = 0usize;
if trailing_ones > 0 {
let signs = reader.read_bits(trailing_ones as u8)?;
for k in 0..trailing_ones {
let bit = (signs >> (trailing_ones - 1 - k)) & 1;
levels[level_count] = if bit == 0 { 1 } else { -1 };
level_count += 1;
}
}
let mut suffix_length: u32 = if total_coeffs > 10 && trailing_ones < 3 {
1
} else {
0
};
for i in trailing_ones..total_coeffs {
let w = reader.peek_padded(32);
let lz = w.leading_zeros();
let total = lz + 1 + suffix_length;
let (level_prefix, level_suffix);
if lz <= 13 && total as usize <= reader.bits_remaining() {
level_prefix = lz;
level_suffix = (w >> (32 - total)) & ((1u32 << suffix_length) - 1);
reader.consume(total as u8);
} else {
level_prefix = read_level_prefix(reader)?;
let level_suffix_size = if level_prefix == 14 && suffix_length == 0 {
4
} else if level_prefix >= 15 {
level_prefix - 3
} else {
suffix_length
};
level_suffix = if level_suffix_size > 0 {
reader.read_bits(level_suffix_size as u8)?
} else {
0
};
}
let mut level_code = (level_prefix.min(15) << suffix_length) as i32 + level_suffix as i32;
if level_prefix >= 15 && suffix_length == 0 {
level_code += 15;
}
if level_prefix >= 16 {
level_code += ((1u32 << (level_prefix - 3)) - 4096) as i32;
}
if i == trailing_ones && trailing_ones < 3 {
level_code += 2;
}
let level = if level_code % 2 == 0 {
(level_code + 2) >> 1
} else {
(-level_code - 1) >> 1
};
levels[level_count] = level;
level_count += 1;
if suffix_length == 0 {
suffix_length = 1;
}
if level.unsigned_abs() > (3 << (suffix_length - 1)) && suffix_length < 6 {
suffix_length += 1;
}
}
let total_zeros = if total_coeffs < max_coeff {
read_total_zeros(reader, total_coeffs, max_coeff)?
} else {
0
};
let mut runs = [0u8; 16];
let mut zeros_left = total_zeros;
for run in runs.iter_mut().take(total_coeffs - 1) {
if zeros_left == 0 {
break;
}
let r = read_run_before(reader, zeros_left)?;
*run = r as u8;
zeros_left = zeros_left.saturating_sub(r);
}
runs[total_coeffs - 1] = zeros_left as u8;
Some(CavlcResult {
total_coeffs,
trailing_ones,
levels,
total_zeros,
runs,
})
}
pub fn expand_cavlc_to_coefficients(result: &CavlcResult, block_size: usize) -> Vec<i32> {
let mut coeffs = vec![0i32; block_size];
expand_cavlc_to_coefficients_into(result, &mut coeffs);
coeffs
}
pub fn expand_cavlc_to_coefficients_into(result: &CavlcResult, coeffs: &mut [i32]) {
let n = result.total_coeffs;
if n == 0 {
return;
}
let mut pos: i32 = -1;
for i in (0..n).rev() {
let run = result.runs.get(i).copied().unwrap_or(0);
pos += run as i32 + 1;
match (usize::try_from(pos), result.levels.get(i)) {
(Ok(p), Some(&level)) if p < coeffs.len() => coeffs[p] = level,
_ => break,
}
}
}
#[cfg(test)]
mod cavlc_tests {
use super::*;
fn br(bits: &str) -> Vec<u8> {
let mut out = vec![0u8; bits.len().div_ceil(8)];
for (i, c) in bits.chars().enumerate() {
if c == '1' {
out[i / 8] |= 1 << (7 - (i % 8));
}
}
out
}
fn ct(nc: i32, bits: &str) -> (usize, usize) {
let data = br(bits);
let mut r = BitReader::new(&data);
read_coeff_token(&mut r, nc).expect("coeff_token match")
}
#[test]
fn coeff_token_spec_codewords() {
assert_eq!(ct(0, "1"), (0, 0));
assert_eq!(ct(0, "01"), (1, 1));
assert_eq!(ct(0, "001"), (2, 2));
assert_eq!(ct(0, "000101"), (1, 0));
assert_eq!(ct(0, "0000101"), (3, 2));
assert_eq!(ct(0, "00011"), (3, 3));
assert_eq!(ct(2, "11"), (0, 0));
assert_eq!(ct(2, "10"), (1, 1));
assert_eq!(ct(2, "011"), (2, 2));
assert_eq!(ct(4, "1111"), (0, 0));
assert_eq!(ct(4, "1110"), (1, 1));
assert_eq!(ct(8, "000011"), (0, 0));
assert_eq!(ct(8, "000000"), (1, 0));
assert_eq!(ct(8, "000101"), (2, 1));
assert_eq!(ct(-1, "01"), (0, 0));
assert_eq!(ct(-1, "1"), (1, 1));
}
#[test]
fn total_zeros_and_run_spec() {
{
let d = br("1");
let mut r = BitReader::new(&d);
assert_eq!(read_total_zeros(&mut r, 1, 16).unwrap(), 0);
}
{
let d = br("011");
let mut r = BitReader::new(&d);
assert_eq!(read_total_zeros(&mut r, 1, 16).unwrap(), 1);
}
{
let d = br("1");
let mut r = BitReader::new(&d);
assert_eq!(read_run_before(&mut r, 1).unwrap(), 0);
}
{
let d = br("0");
let mut r = BitReader::new(&d);
assert_eq!(read_run_before(&mut r, 1).unwrap(), 1);
}
}
}