pub struct BitReader<'a> {
data: &'a [u8],
pos: usize,
bit_buf: u32,
bits_in_buf: u8,
}
impl<'a> BitReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
pos: 0,
bit_buf: 0,
bits_in_buf: 0,
}
}
pub fn byte_pos(&self) -> usize {
self.pos
}
fn refill(&mut self) {
while self.bits_in_buf <= 24 && self.pos < self.data.len() {
let byte = self.data[self.pos];
self.pos += 1;
if byte == 0xFF {
if self.pos < self.data.len() {
let next = self.data[self.pos];
if next == 0x00 {
self.pos += 1;
} else {
self.pos -= 1; break;
}
} else {
self.pos -= 1;
break;
}
}
self.bit_buf = (self.bit_buf << 8) | u32::from(byte);
self.bits_in_buf += 8;
}
}
pub fn read_bit(&mut self) -> Option<u32> {
if self.bits_in_buf == 0 {
self.refill();
}
if self.bits_in_buf == 0 {
return None;
}
self.bits_in_buf -= 1;
Some((self.bit_buf >> self.bits_in_buf) & 1)
}
pub fn read_bits(&mut self, n: u8) -> Option<u32> {
if n == 0 {
return Some(0);
}
if self.bits_in_buf < n {
self.refill();
}
if self.bits_in_buf < n {
return None;
}
self.bits_in_buf -= n;
Some((self.bit_buf >> self.bits_in_buf) & ((1u32 << n) - 1))
}
}
#[inline]
pub fn compute_limit(max_val: i32) -> i32 {
let j = if max_val > 0 {
31 - (max_val + 1).leading_zeros() as i32
} else {
0
};
let opt1 = 2 * (j + 8);
let opt2 = 32 + j * 4;
opt1.min(opt2)
}
#[inline]
pub fn compute_qbpp(max_val: i32) -> u8 {
let n = max_val + 2;
if n <= 1 {
return 1;
}
let bits = 32u32 - (n as u32 - 1).leading_zeros();
(bits as u8).max(1)
}
pub fn decode_golomb_unsigned(reader: &mut BitReader<'_>, k: i32) -> Option<i32> {
decode_golomb_unsigned_limited(reader, k, 64, 16)
}
pub fn decode_golomb_unsigned_limited(
reader: &mut BitReader<'_>,
k: i32,
limit: i32,
qbpp: u8,
) -> Option<i32> {
let overflow_threshold = limit - k - 1;
let mut unary = 0i32;
loop {
let bit = reader.read_bit()?;
if bit == 1 {
if unary == overflow_threshold {
let raw = reader.read_bits(qbpp)? as i32;
return Some(raw - 1);
}
break;
}
unary += 1;
if unary > overflow_threshold {
return None;
}
}
let suffix = reader.read_bits(k as u8)? as i32;
Some((unary << k) | suffix)
}
#[inline]
pub fn unmap_error_lossless(e_mapped: i32) -> i32 {
if e_mapped % 2 == 0 {
e_mapped / 2
} else {
-(e_mapped + 1) / 2
}
}
#[inline]
pub fn map_error_lossless(err: i32) -> i32 {
if err >= 0 {
2 * err
} else {
-2 * err - 1
}
}
#[inline]
pub fn map_error_near(err: i32, near: i32, max_val: i32) -> i32 {
let range = max_val + 2 * near + 1;
if err < 0 {
err + range
} else {
err
}
}
#[inline]
pub fn unmap_error_near(e_mapped: i32, near: i32, max_val: i32) -> i32 {
let range = max_val + 2 * near + 1;
let half_range = range / 2;
if e_mapped > half_range {
e_mapped - range
} else {
e_mapped
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn golomb_k0_unary_three() {
let data = [0b0001_0000u8];
let mut r = BitReader::new(&data);
assert_eq!(decode_golomb_unsigned(&mut r, 0), Some(3));
}
#[test]
fn golomb_k2_value_one() {
let data = [0b1010_0000u8];
let mut r = BitReader::new(&data);
assert_eq!(decode_golomb_unsigned(&mut r, 2), Some(1));
}
#[test]
fn golomb_k1_value_five() {
let data = [0b0011_0000u8];
let mut r = BitReader::new(&data);
assert_eq!(decode_golomb_unsigned(&mut r, 1), Some(5));
}
#[test]
fn unmap_roundtrip_lossless() {
for err in -100..=100i32 {
let mapped = map_error_lossless(err);
assert_eq!(
unmap_error_lossless(mapped),
err,
"roundtrip failed for err={err}"
);
}
}
#[test]
fn byte_stuffing_skips_zero() {
let data = [0xFF, 0x00, 0x80];
let mut r = BitReader::new(&data);
let val = r.read_bits(8).expect("should read 8 bits");
assert_eq!(val, 0xFF);
let bit = r.read_bit().expect("should read bit from 0x80");
assert_eq!(bit, 1);
}
#[test]
fn marker_bytes_stop_reading() {
let data = [0xAA, 0xFF, 0xD9];
let mut r = BitReader::new(&data);
let val = r.read_bits(8).expect("should read 0xAA");
assert_eq!(val, 0xAA);
let after = r.read_bit();
assert!(
after.is_none(),
"should be None after marker, got {after:?}"
);
}
}