use crate::BitstreamError;
pub struct BitReader<'a> {
pub(crate) bytes: &'a [u8],
pub(crate) bit_pos: usize,
}
impl<'a> BitReader<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
Self { bytes, bit_pos: 0 }
}
pub fn total_bits(&self) -> usize {
self.bytes.len() * 8
}
pub fn bit_pos(&self) -> usize {
self.bit_pos
}
pub fn bits_remaining(&self) -> usize {
self.total_bits().saturating_sub(self.bit_pos)
}
pub fn at_end(&self) -> bool {
self.bit_pos >= self.total_bits()
}
pub fn byte_aligned(&self) -> bool {
self.bit_pos % 8 == 0
}
pub fn skip(&mut self, n: usize) {
self.bit_pos = self.bit_pos.saturating_add(n);
}
pub fn align_to_byte(&mut self) {
let rem = self.bit_pos % 8;
if rem != 0 {
self.bit_pos += 8 - rem;
}
}
pub fn read_bit(&mut self) -> u32 {
let byte_idx = self.bit_pos / 8;
let shift = 7 - (self.bit_pos % 8) as u32;
let bit = if byte_idx < self.bytes.len() {
((self.bytes[byte_idx] >> shift) & 1) as u32
} else {
0
};
self.bit_pos += 1;
bit
}
pub fn u(&mut self, n: u32) -> u32 {
debug_assert!(n <= 32, "BitReader::u({n}) > 32 bits");
let mut value: u32 = 0;
for _ in 0..n {
value = (value << 1) | self.read_bit();
}
value
}
pub fn u64(&mut self, n: u32) -> u64 {
debug_assert!(n <= 64, "BitReader::u64({n}) > 64 bits");
let mut value: u64 = 0;
for _ in 0..n {
value = (value << 1) | (self.read_bit() as u64);
}
value
}
pub fn peek_bits(&self, n: u32) -> u32 {
debug_assert!(n <= 32, "BitReader::peek_bits({n}) > 32 bits");
let mut value: u32 = 0;
let total = self.total_bits();
for offset in 0..n as usize {
let pos = self.bit_pos + offset;
let bit = if pos < total {
let byte_idx = pos / 8;
let shift = 7 - (pos % 8) as u32;
((self.bytes[byte_idx] >> shift) & 1) as u32
} else {
0
};
value = (value << 1) | bit;
}
value
}
pub fn more_rbsp_data(&self) -> bool {
let total = self.total_bits();
if self.bit_pos >= total {
return false;
}
let mut saw_one = false;
for p in self.bit_pos..total {
let b = (self.bytes[p / 8] >> (7 - (p % 8))) & 1;
if !saw_one {
if b == 1 {
saw_one = true;
}
} else if b == 1 {
return true;
}
}
false
}
pub fn read_rbsp_trailing_bits(&mut self) -> Result<(), BitstreamError> {
if self.at_end() {
return Err(BitstreamError::UnexpectedEnd(
"rbsp_trailing_bits: no bits left for stop bit".into(),
));
}
if self.read_bit() != 1 {
return Err(BitstreamError::InvalidData(
"rbsp_trailing_bits: rbsp_stop_one_bit was 0".into(),
));
}
while !self.byte_aligned() {
if self.at_end() {
return Err(BitstreamError::UnexpectedEnd(
"rbsp_trailing_bits: stream ended before byte alignment".into(),
));
}
if self.read_bit() != 0 {
return Err(BitstreamError::InvalidData(
"rbsp_trailing_bits: alignment_zero_bit was 1".into(),
));
}
}
Ok(())
}
pub fn ue(&mut self) -> Result<u32, BitstreamError> {
let mut leading_zeros = 0u32;
while !self.at_end() && self.read_bit() == 0 {
leading_zeros += 1;
if leading_zeros >= 32 {
return Err(BitstreamError::InvalidData(
"ue(v): 32 or more leading zero bits".into(),
));
}
}
if leading_zeros >= 32 {
return Err(BitstreamError::InvalidData(
"ue(v): 32 or more leading zero bits".into(),
));
}
if leading_zeros == 0 {
Ok(0)
} else {
let suffix = self.u(leading_zeros);
Ok((1u32 << leading_zeros) - 1 + suffix)
}
}
pub fn se(&mut self) -> Result<i32, BitstreamError> {
let code = self.ue()?;
if code == 0 {
Ok(0)
} else if code & 1 == 1 {
Ok(code.div_ceil(2) as i32)
} else {
Ok(-((code / 2) as i32))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u_reads_known_pattern() {
let bytes = [0b1010_1100, 0b1111_0000];
let mut r = BitReader::new(&bytes);
assert_eq!(r.u(4), 0b1010);
assert_eq!(r.u(4), 0b1100);
assert_eq!(r.u(8), 0b1111_0000);
}
#[test]
fn ue_decodes_known_values() {
let bytes = [0b1010_0110, 0b0100_0000];
let mut r = BitReader::new(&bytes);
assert_eq!(r.ue().unwrap(), 0);
assert_eq!(r.ue().unwrap(), 1);
assert_eq!(r.ue().unwrap(), 2);
assert_eq!(r.ue().unwrap(), 3);
}
#[test]
fn se_decodes_zero_pos_neg() {
let bytes = [0b1010_0110, 0b0000_0000];
let mut r = BitReader::new(&bytes);
assert_eq!(r.se().unwrap(), 0);
assert_eq!(r.se().unwrap(), 1);
assert_eq!(r.se().unwrap(), -1);
}
#[test]
fn align_to_byte_no_op_when_aligned() {
let bytes = [0xff, 0x00];
let mut r = BitReader::new(&bytes);
r.u(8);
assert!(r.byte_aligned());
r.align_to_byte();
assert_eq!(r.bit_pos, 8);
}
#[test]
fn align_to_byte_advances_to_next_byte() {
let bytes = [0xff, 0x00];
let mut r = BitReader::new(&bytes);
r.u(3);
r.align_to_byte();
assert_eq!(r.bit_pos, 8);
}
#[test]
fn past_end_reads_zero() {
let bytes = [0xff];
let mut r = BitReader::new(&bytes);
r.u(8);
assert_eq!(r.u(8), 0);
assert!(r.at_end());
}
#[test]
fn peek_bits_does_not_advance() {
let bytes = [0b1010_1100, 0b1111_0000];
let r0 = BitReader::new(&bytes);
assert_eq!(r0.peek_bits(4), 0b1010);
let mut r = BitReader::new(&bytes);
let peeked = r.peek_bits(8);
assert_eq!(peeked, 0b1010_1100);
assert_eq!(r.bit_pos(), 0);
assert_eq!(r.u(8), 0b1010_1100);
}
#[test]
fn peek_bits_past_end_is_zero_padded() {
let bytes = [0b1111_0000];
let mut r = BitReader::new(&bytes);
r.u(4);
assert_eq!(r.peek_bits(8), 0b0000_0000);
r.u(4);
assert_eq!(r.peek_bits(16), 0);
}
#[test]
fn more_rbsp_data_after_payload() {
let bytes = [0xB0];
let mut r = BitReader::new(&bytes);
assert!(r.more_rbsp_data(), "before payload there's more data");
r.u(1); assert!(r.more_rbsp_data());
r.u(1); assert!(r.more_rbsp_data());
r.u(1); assert!(!r.more_rbsp_data());
}
#[test]
fn more_rbsp_data_minimal_stop_byte() {
let bytes = [0x80];
let r = BitReader::new(&bytes);
assert!(
!r.more_rbsp_data(),
"stop-bit-only buffer has no further RBSP data"
);
}
#[test]
fn more_rbsp_data_at_end_is_false() {
let bytes = [0xff];
let mut r = BitReader::new(&bytes);
r.u(8);
assert!(!r.more_rbsp_data());
}
#[test]
fn read_rbsp_trailing_bits_accepts_minimal_marker() {
let bytes = [0x80];
let mut r = BitReader::new(&bytes);
r.read_rbsp_trailing_bits().unwrap();
assert!(r.byte_aligned());
assert!(r.at_end());
}
#[test]
fn read_rbsp_trailing_bits_after_payload() {
let bytes = [0xB4];
let mut r = BitReader::new(&bytes);
assert_eq!(r.u(5), 0b10110);
r.read_rbsp_trailing_bits().unwrap();
assert!(r.byte_aligned());
assert!(r.at_end());
}
#[test]
fn read_rbsp_trailing_bits_rejects_zero_stop_bit() {
let bytes = [0x00];
let mut r = BitReader::new(&bytes);
match r.read_rbsp_trailing_bits() {
Err(BitstreamError::InvalidData(msg)) => assert!(msg.contains("stop")),
other => panic!("expected InvalidData, got {other:?}"),
}
}
#[test]
fn read_rbsp_trailing_bits_rejects_nonzero_alignment_bit() {
let bytes = [0b1000_1000];
let mut r = BitReader::new(&bytes);
match r.read_rbsp_trailing_bits() {
Err(BitstreamError::InvalidData(msg)) => assert!(msg.contains("alignment")),
other => panic!("expected InvalidData, got {other:?}"),
}
}
#[test]
fn read_rbsp_trailing_bits_rejects_empty_reader() {
let bytes: [u8; 0] = [];
let mut r = BitReader::new(&bytes);
match r.read_rbsp_trailing_bits() {
Err(BitstreamError::UnexpectedEnd(_)) => {}
other => panic!("expected UnexpectedEnd, got {other:?}"),
}
}
}