Files
filmcraft/crates/av1/src/bits.rs
Brandon ThomasandClaude Opus 5.5 1813bbaca2 M9.7: AV1 headers, symbol decoder, CDFs, intra decoding, transforms, intra prediction
New L0 crate filmcraft-av1 from the AV1 Bitstream & Decoding Process
Specification v1.0.0 with Errata 1 (tables extracted from the spec's Markdown
source by tools/extract_tables.py).

Stages: OBU parsing, sequence and uncompressed frame headers (all fields),
reference state (set_frame_refs, load_previous, reference update,
show_existing_frame), symbol decoder with CDF adaptation and
init/load/save/frame-end CDF handling, tiles, intra frame mode info
(partitions, segment ids, delta q/lf, CDEF index, modes, angle deltas, CfL,
palette, filter intra, tx size), coefficient decoding, dequantisation,
inverse transforms (DCT 4-64, ADST, identity, WHT), intra prediction (all
modes, edge filter/upsampling, recursive filter, CfL, palette), LR syntax.

All-intra libsvtav1 streams with in-loop filters disabled decode bit-exactly
against libdav1d (8/10-bit, 128x128..1280x720, odd sizes, presets 2-8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:00:03 -04:00

125 lines
3.0 KiB
Rust

//! MSB-first bit reader for OBU headers and the uncompressed frame header (spec 4.10 descriptors).
use crate::{Error, Result};
#[derive(Clone)]
pub(crate) struct BitReader<'a> {
data: &'a [u8],
/// Position in bits.
pos: usize,
}
impl<'a> BitReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
BitReader { data, pos: 0 }
}
/// `get_position()`: bits consumed.
pub fn position(&self) -> usize {
self.pos
}
pub fn byte_pos(&self) -> usize {
self.pos.div_ceil(8)
}
#[inline]
pub fn bit(&mut self) -> Result<u32> {
let byte = *self.data.get(self.pos >> 3).ok_or(Error::Truncated)?;
let b = (byte >> (7 - (self.pos & 7))) & 1;
self.pos += 1;
Ok(b as u32)
}
/// `f(n)`, n ≤ 32.
pub fn f(&mut self, n: u32) -> Result<u32> {
let mut x: u64 = 0;
for _ in 0..n {
x = (x << 1) | self.bit()? as u64;
}
Ok(x as u32)
}
pub fn flag(&mut self) -> Result<bool> {
Ok(self.bit()? == 1)
}
/// `uvlc()`
pub fn uvlc(&mut self) -> Result<u32> {
let mut leading = 0u32;
while self.bit()? == 0 {
leading += 1;
if leading > 40 {
return Err(Error::Invalid("uvlc"));
}
}
if leading >= 32 {
return Ok(u32::MAX);
}
let v = self.f(leading)?;
Ok(v + ((1u64 << leading) - 1) as u32)
}
/// `le(n)`
pub fn le(&mut self, n: u32) -> Result<u32> {
let mut t = 0u32;
for i in 0..n {
t |= self.f(8)? << (8 * i);
}
Ok(t)
}
/// `leb128()`
pub fn leb128(&mut self) -> Result<u64> {
let mut v = 0u64;
for i in 0..8 {
let b = self.f(8)? as u64;
v |= (b & 0x7f) << (7 * i);
if b & 0x80 == 0 {
break;
}
}
Ok(v)
}
/// `su(n)`
pub fn su(&mut self, n: u32) -> Result<i32> {
let v = self.f(n)? as i64;
let sign = 1i64 << (n - 1);
Ok(if v & sign != 0 { (v - 2 * sign) as i32 } else { v as i32 })
}
/// `ns(n)`
pub fn ns(&mut self, n: u32) -> Result<u32> {
if n <= 1 {
return Ok(0);
}
let w = 32 - n.leading_zeros(); // FloorLog2(n) + 1
let m = (1u32 << w) - n;
let v = self.f(w - 1)?;
if v < m {
return Ok(v);
}
let extra = self.bit()?;
Ok((v << 1) - m + extra)
}
/// `byte_alignment()`
pub fn byte_align(&mut self) {
self.pos = self.pos.div_ceil(8) * 8;
}
}
/// Read a leb128 from a byte slice; returns (value, bytes used).
pub(crate) fn leb128(data: &[u8]) -> Result<(u64, usize)> {
let mut v = 0u64;
for i in 0..8 {
let b = *data.get(i).ok_or(Error::Truncated)? as u64;
v |= (b & 0x7f) << (7 * i);
if b & 0x80 == 0 {
return Ok((v, i + 1));
}
}
Ok((v, 8))
}