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    /// Peek the next `n` bits MSB-first without advancing `bit_pos`.
104    /// `n` must be ≤ 32. Past-the-end bits are zero, identical to
105    /// [`BitReader::u`]'s contract. Useful for codec parsers that need
106    /// to inspect a marker bit before deciding whether to commit to a
107    /// branch.
108    pub fn peek_bits(&self, n: u32) -> u32 {
109        debug_assert!(n <= 32, "BitReader::peek_bits({n}) > 32 bits");
110        let mut value: u32 = 0;
111        let total = self.total_bits();
112        for offset in 0..n as usize {
113            let pos = self.bit_pos + offset;
114            let bit = if pos < total {
115                let byte_idx = pos / 8;
116                let shift = 7 - (pos % 8) as u32;
117                ((self.bytes[byte_idx] >> shift) & 1) as u32
118            } else {
119                0
120            };
121            value = (value << 1) | bit;
122        }
123        value
124    }
125
126    /// H.264 §7.2 / H.265 §7.2 / H.266 §7.2 `more_rbsp_data()`.
127    ///
128    /// Returns `true` if there is at least one more RBSP data bit
129    /// before the `rbsp_trailing_bits()` marker. The marker is a `1`
130    /// bit (the `rbsp_stop_one_bit`) followed by zero or more `0`
131    /// bits up to the next byte boundary, sitting at the end of the
132    /// RBSP. The algorithm: search forward from the current position
133    /// for any `1` bit after the *next* `1` — if we find one, the
134    /// next `1` was not the stop marker and there is more data.
135    ///
136    /// Returns `false` once positioned at or past the stop bit, and
137    /// at end-of-stream.
138    pub fn more_rbsp_data(&self) -> bool {
139        let total = self.total_bits();
140        if self.bit_pos >= total {
141            return false;
142        }
143        let mut saw_one = false;
144        for p in self.bit_pos..total {
145            let b = (self.bytes[p / 8] >> (7 - (p % 8))) & 1;
146            if !saw_one {
147                if b == 1 {
148                    saw_one = true;
149                }
150            } else if b == 1 {
151                return true;
152            }
153        }
154        false
155    }
156
157    /// H.264 §7.3.2.11 / H.265 §7.3.2.11 / H.266 §7.3.10
158    /// `rbsp_trailing_bits()`. Consumes a `1` (`rbsp_stop_one_bit`)
159    /// followed by zero or more `0` bits up to the next byte
160    /// boundary. Returns `Err(InvalidData)` if the next bit is not
161    /// `1`, if any of the padding bits before the boundary is not
162    /// `0`, or if the stream ends before the marker is found.
163    pub fn read_rbsp_trailing_bits(&mut self) -> Result<(), BitstreamError> {
164        if self.at_end() {
165            return Err(BitstreamError::UnexpectedEnd(
166                "rbsp_trailing_bits: no bits left for stop bit".into(),
167            ));
168        }
169        if self.read_bit() != 1 {
170            return Err(BitstreamError::InvalidData(
171                "rbsp_trailing_bits: rbsp_stop_one_bit was 0".into(),
172            ));
173        }
174        while !self.byte_aligned() {
175            if self.at_end() {
176                return Err(BitstreamError::UnexpectedEnd(
177                    "rbsp_trailing_bits: stream ended before byte alignment".into(),
178                ));
179            }
180            if self.read_bit() != 0 {
181                return Err(BitstreamError::InvalidData(
182                    "rbsp_trailing_bits: alignment_zero_bit was 1".into(),
183                ));
184            }
185        }
186        Ok(())
187    }
188
189    /// Unsigned Exp-Golomb (`ue(v)`). H.264 9.1 / H.265 9.2.
190    /// Returns an error if 32 or more leading zeros are seen: the
191    /// largest representable `ue(v)` value is `u32::MAX - 1` (31 leading
192    /// zeros), so 32 leading zeros has no valid `u32` value and the
193    /// `1 << leadingZeros` term would overflow.
194    pub fn ue(&mut self) -> Result<u32, BitstreamError> {
195        let mut leading_zeros = 0u32;
196        while !self.at_end() && self.read_bit() == 0 {
197            leading_zeros += 1;
198            if leading_zeros >= 32 {
199                return Err(BitstreamError::InvalidData(
200                    "ue(v): 32 or more leading zero bits".into(),
201                ));
202            }
203        }
204        // The loop can also exit by hitting end-of-stream after a run of
205        // zeros (every remaining bit was 0). Guard that path too so a
206        // 32-bit all-zero buffer can never reach the shift below with
207        // `leading_zeros == 32`.
208        if leading_zeros >= 32 {
209            return Err(BitstreamError::InvalidData(
210                "ue(v): 32 or more leading zero bits".into(),
211            ));
212        }
213        if leading_zeros == 0 {
214            Ok(0)
215        } else {
216            let suffix = self.u(leading_zeros);
217            Ok((1u32 << leading_zeros) - 1 + suffix)
218        }
219    }
220
221    /// Signed Exp-Golomb (`se(v)`). H.264 9.1.1 / H.265 9.2.2.
222    pub fn se(&mut self) -> Result<i32, BitstreamError> {
223        let code = self.ue()?;
224        if code == 0 {
225            Ok(0)
226        } else if code & 1 == 1 {
227            Ok(code.div_ceil(2) as i32)
228        } else {
229            Ok(-((code / 2) as i32))
230        }
231    }
232}
233
234#[cfg(test)]
235mod tests {
236    use super::*;
237
238    #[test]
239    fn u_reads_known_pattern() {
240        // 0b1010_1100 0b1111_0000
241        let bytes = [0b1010_1100, 0b1111_0000];
242        let mut r = BitReader::new(&bytes);
243        assert_eq!(r.u(4), 0b1010);
244        assert_eq!(r.u(4), 0b1100);
245        assert_eq!(r.u(8), 0b1111_0000);
246    }
247
248    #[test]
249    fn ue_decodes_known_values() {
250        // 1 010 011 00100 → ue codes 0,1,2,3 (13 bits)
251        // Packed MSB-first: 10100110 01000000
252        let bytes = [0b1010_0110, 0b0100_0000];
253        let mut r = BitReader::new(&bytes);
254        assert_eq!(r.ue().unwrap(), 0);
255        assert_eq!(r.ue().unwrap(), 1);
256        assert_eq!(r.ue().unwrap(), 2);
257        assert_eq!(r.ue().unwrap(), 3);
258    }
259
260    #[test]
261    fn se_decodes_zero_pos_neg() {
262        // ue codes: 0, 1, 2 → se: 0, +1, -1
263        let bytes = [0b1010_0110, 0b0000_0000];
264        let mut r = BitReader::new(&bytes);
265        assert_eq!(r.se().unwrap(), 0);
266        assert_eq!(r.se().unwrap(), 1);
267        assert_eq!(r.se().unwrap(), -1);
268    }
269
270    #[test]
271    fn align_to_byte_no_op_when_aligned() {
272        let bytes = [0xff, 0x00];
273        let mut r = BitReader::new(&bytes);
274        r.u(8);
275        assert!(r.byte_aligned());
276        r.align_to_byte();
277        assert_eq!(r.bit_pos, 8);
278    }
279
280    #[test]
281    fn align_to_byte_advances_to_next_byte() {
282        let bytes = [0xff, 0x00];
283        let mut r = BitReader::new(&bytes);
284        r.u(3);
285        r.align_to_byte();
286        assert_eq!(r.bit_pos, 8);
287    }
288
289    #[test]
290    fn past_end_reads_zero() {
291        let bytes = [0xff];
292        let mut r = BitReader::new(&bytes);
293        r.u(8);
294        assert_eq!(r.u(8), 0);
295        assert!(r.at_end());
296    }
297
298    #[test]
299    fn peek_bits_does_not_advance() {
300        let bytes = [0b1010_1100, 0b1111_0000];
301        let r0 = BitReader::new(&bytes);
302        assert_eq!(r0.peek_bits(4), 0b1010);
303        // Re-borrow as mutable to compare against a real read.
304        let mut r = BitReader::new(&bytes);
305        let peeked = r.peek_bits(8);
306        assert_eq!(peeked, 0b1010_1100);
307        assert_eq!(r.bit_pos(), 0);
308        assert_eq!(r.u(8), 0b1010_1100);
309    }
310
311    #[test]
312    fn peek_bits_past_end_is_zero_padded() {
313        let bytes = [0b1111_0000];
314        let mut r = BitReader::new(&bytes);
315        // Advance to bit 4; the next 4 payload bits are 0.
316        r.u(4);
317        assert_eq!(r.peek_bits(8), 0b0000_0000);
318        // Past the end entirely.
319        r.u(4);
320        assert_eq!(r.peek_bits(16), 0);
321    }
322
323    #[test]
324    fn more_rbsp_data_after_payload() {
325        // Three payload bits `101`, then `rbsp_stop_one_bit=1`, then
326        // 4 zero alignment bits = byte 0b1011_0000 = 0xB0.
327        let bytes = [0xB0];
328        let mut r = BitReader::new(&bytes);
329        assert!(r.more_rbsp_data(), "before payload there's more data");
330        r.u(1); // 1 (payload bit 0)
331        assert!(r.more_rbsp_data());
332        r.u(1); // 0 (payload bit 1)
333        assert!(r.more_rbsp_data());
334        r.u(1); // 1 (payload bit 2) — positioned at stop bit now
335        assert!(!r.more_rbsp_data());
336    }
337
338    #[test]
339    fn more_rbsp_data_minimal_stop_byte() {
340        // Just the stop byte (no payload): 0b1000_0000.
341        let bytes = [0x80];
342        let r = BitReader::new(&bytes);
343        assert!(
344            !r.more_rbsp_data(),
345            "stop-bit-only buffer has no further RBSP data"
346        );
347    }
348
349    #[test]
350    fn more_rbsp_data_at_end_is_false() {
351        let bytes = [0xff];
352        let mut r = BitReader::new(&bytes);
353        r.u(8);
354        assert!(!r.more_rbsp_data());
355    }
356
357    #[test]
358    fn read_rbsp_trailing_bits_accepts_minimal_marker() {
359        // 0b1000_0000: stop_one_bit + 7 zero alignment bits.
360        let bytes = [0x80];
361        let mut r = BitReader::new(&bytes);
362        r.read_rbsp_trailing_bits().unwrap();
363        assert!(r.byte_aligned());
364        assert!(r.at_end());
365    }
366
367    #[test]
368    fn read_rbsp_trailing_bits_after_payload() {
369        // 5 payload bits `10110`, stop bit, 2 zero pad → 0b1011_0100 = 0xB4.
370        let bytes = [0xB4];
371        let mut r = BitReader::new(&bytes);
372        // Consume the payload.
373        assert_eq!(r.u(5), 0b10110);
374        r.read_rbsp_trailing_bits().unwrap();
375        assert!(r.byte_aligned());
376        assert!(r.at_end());
377    }
378
379    #[test]
380    fn read_rbsp_trailing_bits_rejects_zero_stop_bit() {
381        let bytes = [0x00];
382        let mut r = BitReader::new(&bytes);
383        match r.read_rbsp_trailing_bits() {
384            Err(BitstreamError::InvalidData(msg)) => assert!(msg.contains("stop")),
385            other => panic!("expected InvalidData, got {other:?}"),
386        }
387    }
388
389    #[test]
390    fn read_rbsp_trailing_bits_rejects_nonzero_alignment_bit() {
391        // stop bit + 0001 alignment (bit 4 from MSB is 1).
392        let bytes = [0b1000_1000];
393        let mut r = BitReader::new(&bytes);
394        match r.read_rbsp_trailing_bits() {
395            Err(BitstreamError::InvalidData(msg)) => assert!(msg.contains("alignment")),
396            other => panic!("expected InvalidData, got {other:?}"),
397        }
398    }
399
400    #[test]
401    fn read_rbsp_trailing_bits_rejects_empty_reader() {
402        let bytes: [u8; 0] = [];
403        let mut r = BitReader::new(&bytes);
404        match r.read_rbsp_trailing_bits() {
405            Err(BitstreamError::UnexpectedEnd(_)) => {}
406            other => panic!("expected UnexpectedEnd, got {other:?}"),
407        }
408    }
409}