Skip to main content

oxideav_bitstream/
bit_reader.rs

1//! Shared MSB-first bit reader with `u(n)` / `ue(v)` / `se(v)`
2//! primitives. These are the basic building blocks every codec module
3//! needs.
4//!
5//! # Conventions
6//!
7//! - `u(n)` reads `n` bits (0 ≤ n ≤ 32), MSB first inside each byte.
8//! - `ue(v)` is the unsigned Exp-Golomb code from H.264 9.1 / H.265 9.2.
9//! - `se(v)` is the signed Exp-Golomb code from H.264 9.1.1 /
10//!   H.265 9.2.2.
11//! - Past-the-end reads silently yield zero bits. Callers wanting
12//!   strict EOF behaviour should compare [`BitReader::bit_pos`]
13//!   against `bytes.len() * 8` themselves.
14
15use crate::BitstreamError;
16
17/// MSB-first bit reader over a borrowed byte slice.
18pub struct BitReader<'a> {
19    pub(crate) bytes: &'a [u8],
20    pub(crate) bit_pos: usize,
21}
22
23impl<'a> BitReader<'a> {
24    /// Create a fresh reader positioned at bit 0 of `bytes`.
25    pub fn new(bytes: &'a [u8]) -> Self {
26        Self { bytes, bit_pos: 0 }
27    }
28
29    /// Total number of payload bits in the reader.
30    pub fn total_bits(&self) -> usize {
31        self.bytes.len() * 8
32    }
33
34    /// Current absolute bit offset.
35    pub fn bit_pos(&self) -> usize {
36        self.bit_pos
37    }
38
39    /// Number of unread bits (saturating at zero).
40    pub fn bits_remaining(&self) -> usize {
41        self.total_bits().saturating_sub(self.bit_pos)
42    }
43
44    /// True if the next read would fall past the end of the buffer.
45    pub fn at_end(&self) -> bool {
46        self.bit_pos >= self.total_bits()
47    }
48
49    /// True if the reader is currently byte-aligned.
50    pub fn byte_aligned(&self) -> bool {
51        self.bit_pos % 8 == 0
52    }
53
54    /// Skip forward by `n` bits.
55    pub fn skip(&mut self, n: usize) {
56        self.bit_pos = self.bit_pos.saturating_add(n);
57    }
58
59    /// Skip forward to the next byte boundary if not already aligned.
60    pub fn align_to_byte(&mut self) {
61        let rem = self.bit_pos % 8;
62        if rem != 0 {
63            self.bit_pos += 8 - rem;
64        }
65    }
66
67    /// Read one bit. Returns 0 past the end.
68    pub fn read_bit(&mut self) -> u32 {
69        let byte_idx = self.bit_pos / 8;
70        let shift = 7 - (self.bit_pos % 8) as u32;
71        let bit = if byte_idx < self.bytes.len() {
72            ((self.bytes[byte_idx] >> shift) & 1) as u32
73        } else {
74            0
75        };
76        self.bit_pos += 1;
77        bit
78    }
79
80    /// Read `n` bits MSB first into a `u32`. Past-the-end bits are 0.
81    /// `n` must be ≤ 32 (the upper limit covers every fixed-width
82    /// field used by H.264 / HEVC / AV1 OBU headers).
83    pub fn u(&mut self, n: u32) -> u32 {
84        debug_assert!(n <= 32, "BitReader::u({n}) > 32 bits");
85        let mut value: u32 = 0;
86        for _ in 0..n {
87            value = (value << 1) | self.read_bit();
88        }
89        value
90    }
91
92    /// Read `n` bits MSB first into a `u64` (for AV1's 64-bit
93    /// `reference_frame_id`-class fields).
94    pub fn u64(&mut self, n: u32) -> u64 {
95        debug_assert!(n <= 64, "BitReader::u64({n}) > 64 bits");
96        let mut value: u64 = 0;
97        for _ in 0..n {
98            value = (value << 1) | (self.read_bit() as u64);
99        }
100        value
101    }
102
103    /// Unsigned Exp-Golomb (`ue(v)`). H.264 9.1 / H.265 9.2.
104    /// Returns an error if more than 32 leading zeros are seen
105    /// (would overflow a `u32`).
106    pub fn ue(&mut self) -> Result<u32, BitstreamError> {
107        let mut leading_zeros = 0u32;
108        while !self.at_end() && self.read_bit() == 0 {
109            leading_zeros += 1;
110            if leading_zeros > 32 {
111                return Err(BitstreamError::InvalidData(
112                    "ue(v): more than 32 leading zero bits".into(),
113                ));
114            }
115        }
116        if leading_zeros == 0 {
117            Ok(0)
118        } else {
119            let suffix = self.u(leading_zeros);
120            Ok((1u32 << leading_zeros) - 1 + suffix)
121        }
122    }
123
124    /// Signed Exp-Golomb (`se(v)`). H.264 9.1.1 / H.265 9.2.2.
125    pub fn se(&mut self) -> Result<i32, BitstreamError> {
126        let code = self.ue()?;
127        if code == 0 {
128            Ok(0)
129        } else if code & 1 == 1 {
130            Ok(code.div_ceil(2) as i32)
131        } else {
132            Ok(-((code / 2) as i32))
133        }
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn u_reads_known_pattern() {
143        // 0b1010_1100 0b1111_0000
144        let bytes = [0b1010_1100, 0b1111_0000];
145        let mut r = BitReader::new(&bytes);
146        assert_eq!(r.u(4), 0b1010);
147        assert_eq!(r.u(4), 0b1100);
148        assert_eq!(r.u(8), 0b1111_0000);
149    }
150
151    #[test]
152    fn ue_decodes_known_values() {
153        // 1 010 011 00100 → ue codes 0,1,2,3 (13 bits)
154        // Packed MSB-first: 10100110 01000000
155        let bytes = [0b1010_0110, 0b0100_0000];
156        let mut r = BitReader::new(&bytes);
157        assert_eq!(r.ue().unwrap(), 0);
158        assert_eq!(r.ue().unwrap(), 1);
159        assert_eq!(r.ue().unwrap(), 2);
160        assert_eq!(r.ue().unwrap(), 3);
161    }
162
163    #[test]
164    fn se_decodes_zero_pos_neg() {
165        // ue codes: 0, 1, 2 → se: 0, +1, -1
166        let bytes = [0b1010_0110, 0b0000_0000];
167        let mut r = BitReader::new(&bytes);
168        assert_eq!(r.se().unwrap(), 0);
169        assert_eq!(r.se().unwrap(), 1);
170        assert_eq!(r.se().unwrap(), -1);
171    }
172
173    #[test]
174    fn align_to_byte_no_op_when_aligned() {
175        let bytes = [0xff, 0x00];
176        let mut r = BitReader::new(&bytes);
177        r.u(8);
178        assert!(r.byte_aligned());
179        r.align_to_byte();
180        assert_eq!(r.bit_pos, 8);
181    }
182
183    #[test]
184    fn align_to_byte_advances_to_next_byte() {
185        let bytes = [0xff, 0x00];
186        let mut r = BitReader::new(&bytes);
187        r.u(3);
188        r.align_to_byte();
189        assert_eq!(r.bit_pos, 8);
190    }
191
192    #[test]
193    fn past_end_reads_zero() {
194        let bytes = [0xff];
195        let mut r = BitReader::new(&bytes);
196        r.u(8);
197        assert_eq!(r.u(8), 0);
198        assert!(r.at_end());
199    }
200}