mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-25 10:37:34 -06:00
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>
125 lines
3.0 KiB
Rust
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))
|
|
}
|