Skip to main content

wmv_decoder/wma/
bitstream.rs

1//! Bitstream reader.
2//!
3//! This is a simplified but semantically equivalent translation of upstream's
4//! `GetBitContext` (MSB-first bit order).
5
6use crate::error::{DecoderError, Result};
7
8#[derive(Clone)]
9pub struct GetBitContext<'a> {
10    buf: &'a [u8],
11    size_in_bits: usize,
12    size_in_bits_plus8: usize,
13    bit_pos: usize,
14}
15
16impl<'a> GetBitContext<'a> {
17    pub fn new(buf: &'a [u8]) -> Self {
18        let size_in_bits = buf.len() * 8;
19        Self {
20            buf,
21            size_in_bits,
22            size_in_bits_plus8: size_in_bits.saturating_add(8),
23            bit_pos: 0,
24        }
25    }
26
27    pub fn new_bits(buf: &'a [u8], size_in_bits: usize) -> Result<Self> {
28        if size_in_bits > buf.len() * 8 {
29            return Err(DecoderError::InvalidData(
30                "bitstream size exceeds buffer".into(),
31            ));
32        }
33        Ok(Self {
34            buf,
35            size_in_bits,
36            size_in_bits_plus8: size_in_bits.saturating_add(8),
37            bit_pos: 0,
38        })
39    }
40
41    pub fn new_window(buf: &'a [u8], bit_pos: usize, size_in_bits: usize) -> Result<Self> {
42        if bit_pos > size_in_bits || size_in_bits > buf.len() * 8 {
43            return Err(DecoderError::InvalidData("invalid bitstream window".into()));
44        }
45        Ok(Self {
46            buf,
47            size_in_bits,
48            size_in_bits_plus8: size_in_bits.saturating_add(8),
49            bit_pos,
50        })
51    }
52
53    #[inline]
54    pub fn bits_left(&self) -> isize {
55        self.size_in_bits as isize - self.bit_pos as isize
56    }
57
58    #[inline]
59    pub fn bits_read(&self) -> usize {
60        self.bit_pos
61    }
62
63    #[inline]
64    pub fn align_to_byte(&mut self) {
65        let target = self.bit_pos.saturating_add(7) & !7;
66        self.bit_pos = target.min(self.size_in_bits_plus8);
67    }
68
69    /// Advance the bit reader using FFmpeg's checked GetBitContext semantics.
70    ///
71    /// FFmpeg deliberately permits the read index to enter eight bits of zero
72    /// padding past the logical end of the bitstream.  A large amount of its
73    /// VLC code relies on that look-ahead behavior at frame boundaries.
74    #[inline]
75    pub fn skip_bits(&mut self, n: usize) -> Result<()> {
76        self.bit_pos = self.bit_pos.saturating_add(n).min(self.size_in_bits_plus8);
77        Ok(())
78    }
79
80    #[inline]
81    pub fn get_bits1(&mut self) -> Result<u32> {
82        self.get_bits(1)
83    }
84
85    /// Read up to 32 bits.
86    ///
87    /// This mirrors FFmpeg's checked GetBitContext: reads use zero-filled
88    /// padding beyond `size_in_bits`, while the stored bit index is clamped to
89    /// `size_in_bits + 8`.  It is intentionally not an EOF error by itself;
90    /// callers that require a hard boundary check use `bits_left()` exactly as
91    /// the upstream WMA decoders do.
92    #[inline]
93    pub fn get_bits(&mut self, n: usize) -> Result<u32> {
94        if n == 0 {
95            return Ok(0);
96        }
97        if n > 32 {
98            return Err(DecoderError::InvalidData("get_bits > 32".into()));
99        }
100
101        let start = self.bit_pos;
102        let mut pos = start;
103        let mut remaining = n;
104        let mut out: u32 = 0;
105        while remaining > 0 {
106            if pos >= self.size_in_bits {
107                out <<= remaining;
108                break;
109            }
110
111            let byte_idx = pos >> 3;
112            let bit_in_byte = pos & 7;
113            let byte_avail = 8 - bit_in_byte;
114            let logical_avail = self.size_in_bits - pos;
115            let take = remaining.min(byte_avail).min(logical_avail);
116            let byte = self.buf[byte_idx] as u32;
117            let shift = byte_avail - take;
118            let mask = (1u32 << take) - 1;
119            out = (out << take) | ((byte >> shift) & mask);
120            pos += take;
121            remaining -= take;
122        }
123
124        self.bit_pos = start.saturating_add(n).min(self.size_in_bits_plus8);
125        Ok(out)
126    }
127
128    #[inline]
129    pub fn show_bits(&self, n: usize) -> Result<u32> {
130        let mut tmp = self.clone();
131        tmp.get_bits(n)
132    }
133
134    #[inline]
135    pub fn get_bits_long(&mut self, n: usize) -> Result<u32> {
136        self.get_bits(n)
137    }
138
139    #[inline]
140    pub fn get_sbits(&mut self, n: usize) -> Result<i32> {
141        if n == 0 || n > 32 {
142            return Err(DecoderError::InvalidData("invalid signed bit width".into()));
143        }
144        let raw = self.get_bits(n)?;
145        let shift = 32 - n;
146        Ok(((raw << shift) as i32) >> shift)
147    }
148}