Skip to main content

zvidlib_vorbis_syntax/
lib.rs

1//! Vorbis configuration records and packet timing, shared by zvidlib's
2//! containers and its Vorbis codecs.
3//!
4//! A Vorbis stream is described by three header packets - identification,
5//! comment and setup - which Matroska and WebM carry Xiph-laced as
6//! `CodecPrivate` and a `WebCodecs` `AudioDecoderConfig.description` takes in
7//! the same form. [`VorbisConfig`] parses and writes them, and reads from the
8//! setup header the one thing a container does not record exactly: how many
9//! samples each audio packet decodes to.
10//!
11//! This is an internal crate of [zvidlib](https://crates.io/crates/zvidlib),
12//! which re-exports its public items under the paths documented there. Depend
13//! on `zvidlib` rather than on this crate directly.
14
15#[allow(unused_imports)]
16use zvidlib_core::*;
17
18use crate::{EncodedAudioSample, Error, ErrorKind, Result, SampleRange};
19
20/// How many packets an [`crate::AudioSampleReader`] must decode ahead of the
21/// first one a request needs: a Vorbis packet's samples are the overlap of its
22/// block with the previous packet's, so the previous packet has to be decoded
23/// first.
24pub const VORBIS_PREROLL_PACKETS: usize = 1;
25
26/// The three Vorbis I header packets and what zvidlib reads from them.
27#[derive(Clone, Debug, Eq, PartialEq)]
28pub struct VorbisConfig {
29    pub channels: u8,
30    pub sample_rate: u32,
31    /// The identification header's maximum, nominal and minimum bit rates,
32    /// in bits a second; zero where the stream does not say.
33    pub bitrate_maximum: i32,
34    pub bitrate_nominal: i32,
35    pub bitrate_minimum: i32,
36    /// The short and long block sizes, in samples.
37    pub block_sizes: (u16, u16),
38    pub identification_header: Vec<u8>,
39    pub comment_header: Vec<u8>,
40    pub setup_header: Vec<u8>,
41    /// Whether each mode the setup header defines codes a long block.
42    mode_block_flags: Vec<bool>,
43}
44
45impl VorbisConfig {
46    /// Validates and parses the three header packets.
47    pub fn from_headers(
48        identification_header: Vec<u8>,
49        comment_header: Vec<u8>,
50        setup_header: Vec<u8>,
51    ) -> Result<Self> {
52        let ident = &identification_header;
53        if ident.len() != 30 || ident[0] != 1 || &ident[1..7] != b"vorbis" {
54            return Err(malformed(
55                "Vorbis identification header is not a 30-byte type 1 packet",
56            ));
57        }
58        if u32::from_le_bytes(ident[7..11].try_into().expect("fixed")) != 0 {
59            return Err(unsupported("only Vorbis I streams are supported"));
60        }
61        let channels = ident[11];
62        let sample_rate = u32::from_le_bytes(ident[12..16].try_into().expect("fixed"));
63        let bitrate = |at: usize| i32::from_le_bytes(ident[at..at + 4].try_into().expect("fixed"));
64        let short_exponent = ident[28] & 0x0f;
65        let long_exponent = ident[28] >> 4;
66        if channels == 0 || sample_rate == 0 {
67            return Err(malformed(
68                "Vorbis identification header has no channels or sample rate",
69            ));
70        }
71        if !(6..=13).contains(&short_exponent)
72            || !(6..=13).contains(&long_exponent)
73            || short_exponent > long_exponent
74        {
75            return Err(malformed(
76                "Vorbis identification header has invalid block sizes",
77            ));
78        }
79        if ident[29] & 1 == 0 {
80            return Err(malformed(
81                "Vorbis identification header framing bit is unset",
82            ));
83        }
84        if comment_header.len() < 7 || comment_header[0] != 3 || &comment_header[1..7] != b"vorbis"
85        {
86            return Err(malformed("Vorbis comment header is not a type 3 packet"));
87        }
88        let mode_block_flags = parse_setup_modes(&setup_header, channels)?;
89        Ok(Self {
90            channels,
91            sample_rate,
92            bitrate_maximum: bitrate(16),
93            bitrate_nominal: bitrate(20),
94            bitrate_minimum: bitrate(24),
95            block_sizes: (1 << short_exponent, 1 << long_exponent),
96            identification_header,
97            comment_header,
98            setup_header,
99            mode_block_flags,
100        })
101    }
102
103    /// Parses the three header packets Xiph-laced, the form Matroska and WebM
104    /// `CodecPrivate` use: a byte holding the packet count less one (two), the
105    /// first two packets' sizes as runs of 255 ending in a smaller byte, then
106    /// the packets.
107    pub fn from_codec_private(codec_private: &[u8]) -> Result<Self> {
108        let (&count, mut rest) = codec_private
109            .split_first()
110            .ok_or_else(|| malformed("Vorbis CodecPrivate is empty"))?;
111        if count != 2 {
112            return Err(malformed(
113                "Vorbis CodecPrivate must lace three header packets",
114            ));
115        }
116        let mut sizes = [0_usize; 2];
117        for size in &mut sizes {
118            loop {
119                let (&byte, tail) = rest
120                    .split_first()
121                    .ok_or_else(|| malformed("Vorbis CodecPrivate lacing is truncated"))?;
122                rest = tail;
123                *size += usize::from(byte);
124                if byte != 255 {
125                    break;
126                }
127            }
128        }
129        if sizes[0] + sizes[1] > rest.len() {
130            return Err(malformed("Vorbis CodecPrivate is shorter than its lacing"));
131        }
132        let (identification, rest) = rest.split_at(sizes[0]);
133        let (comment, setup) = rest.split_at(sizes[1]);
134        Self::from_headers(identification.to_vec(), comment.to_vec(), setup.to_vec())
135    }
136
137    /// Writes the three header packets Xiph-laced, as Matroska and WebM
138    /// `CodecPrivate` and a `WebCodecs` decoder `description` take them.
139    pub fn to_codec_private(&self) -> Vec<u8> {
140        let mut out = vec![2];
141        for size in [self.identification_header.len(), self.comment_header.len()] {
142            out.extend(std::iter::repeat_n(255, size / 255));
143            out.push((size % 255) as u8);
144        }
145        out.extend_from_slice(&self.identification_header);
146        out.extend_from_slice(&self.comment_header);
147        out.extend_from_slice(&self.setup_header);
148        out
149    }
150
151    /// The block size an audio packet codes, read from its mode number.
152    pub fn packet_block_size(&self, packet: &[u8]) -> Result<u16> {
153        let mut bits = BitReader::new(packet);
154        if bits.read(1)? != 0 {
155            return Err(malformed("Vorbis audio packet has a header packet type"));
156        }
157        let mode_bits = ilog(self.mode_block_flags.len() as u32 - 1);
158        let mode = usize::try_from(bits.read(mode_bits)?).expect("at most eight bits");
159        let long = *self
160            .mode_block_flags
161            .get(mode)
162            .ok_or_else(|| malformed("Vorbis audio packet names an undefined mode"))?;
163        Ok(if long {
164            self.block_sizes.1
165        } else {
166            self.block_sizes.0
167        })
168    }
169
170    /// Assigns each audio packet, in stream order, the interval of decoded
171    /// samples it produces: none for the first, and for every later one a
172    /// quarter of its block size plus a quarter of the previous packet's.
173    pub fn encoded_samples(&self, packets: Vec<Vec<u8>>) -> Result<Vec<EncodedAudioSample>> {
174        let mut previous = None;
175        let mut end = 0_u64;
176        packets
177            .into_iter()
178            .map(|data| {
179                let block = self.packet_block_size(&data)?;
180                let length = previous.map_or(0, |previous: u16| {
181                    (u64::from(previous) + u64::from(block)) / 4
182                });
183                previous = Some(block);
184                let start = end;
185                end += length;
186                Ok(EncodedAudioSample {
187                    decoded_range: SampleRange::new(start, end)?,
188                    data,
189                })
190            })
191            .collect()
192    }
193}
194
195/// Walks a setup header (Vorbis I specification section 4.2.4) far enough to
196/// validate its structure and read its modes' block flags, which come last.
197fn parse_setup_modes(setup: &[u8], channels: u8) -> Result<Vec<bool>> {
198    if setup.len() < 7 || setup[0] != 5 || &setup[1..7] != b"vorbis" {
199        return Err(malformed("Vorbis setup header is not a type 5 packet"));
200    }
201    let mut bits = BitReader::new(&setup[7..]);
202    let codebooks = bits.read(8)? + 1;
203    for _ in 0..codebooks {
204        skip_codebook(&mut bits)?;
205    }
206    let time_domain_transforms = bits.read(6)? + 1;
207    for _ in 0..time_domain_transforms {
208        if bits.read(16)? != 0 {
209            return Err(malformed(
210                "Vorbis setup header has a nonzero time domain type",
211            ));
212        }
213    }
214    let floors = bits.read(6)? + 1;
215    for _ in 0..floors {
216        skip_floor(&mut bits)?;
217    }
218    let residues = bits.read(6)? + 1;
219    for _ in 0..residues {
220        skip_residue(&mut bits)?;
221    }
222    let mappings = bits.read(6)? + 1;
223    for _ in 0..mappings {
224        skip_mapping(&mut bits, channels)?;
225    }
226    let modes = bits.read(6)? + 1;
227    let mut block_flags = Vec::with_capacity(modes as usize);
228    for _ in 0..modes {
229        block_flags.push(bits.read(1)? == 1);
230        if bits.read(16)? != 0 || bits.read(16)? != 0 {
231            return Err(malformed(
232                "Vorbis setup header mode has a nonzero window or transform type",
233            ));
234        }
235        if bits.read(8)? >= mappings {
236            return Err(malformed(
237                "Vorbis setup header mode names an undefined mapping",
238            ));
239        }
240    }
241    if bits.read(1)? != 1 {
242        return Err(malformed("Vorbis setup header framing bit is unset"));
243    }
244    Ok(block_flags)
245}
246
247fn skip_codebook(bits: &mut BitReader<'_>) -> Result<()> {
248    if bits.read(24)? != 0x56_4342 {
249        return Err(malformed("Vorbis codebook has an invalid sync pattern"));
250    }
251    let dimensions = bits.read(16)?;
252    let entries = bits.read(24)?;
253    if bits.read(1)? == 1 {
254        // Ordered: runs of entries sharing a length.
255        let mut current = 0;
256        bits.read(5)?;
257        while current < entries {
258            current += bits.read(ilog(entries - current))?;
259        }
260        if current > entries {
261            return Err(malformed(
262                "Vorbis codebook length runs overflow its entries",
263            ));
264        }
265    } else {
266        let sparse = bits.read(1)? == 1;
267        for _ in 0..entries {
268            if !sparse || bits.read(1)? == 1 {
269                bits.read(5)?;
270            }
271        }
272    }
273    match bits.read(4)? {
274        0 => {}
275        lookup_type @ (1 | 2) => {
276            bits.read(32)?;
277            bits.read(32)?;
278            let value_bits = bits.read(4)? + 1;
279            bits.read(1)?;
280            let values = if lookup_type == 1 {
281                lookup1_values(entries, dimensions)
282            } else {
283                u64::from(entries) * u64::from(dimensions)
284            };
285            bits.skip(values * u64::from(value_bits))?;
286        }
287        _ => return Err(malformed("Vorbis codebook has an invalid lookup type")),
288    }
289    Ok(())
290}
291
292fn skip_floor(bits: &mut BitReader<'_>) -> Result<()> {
293    match bits.read(16)? {
294        0 => {
295            bits.read(8 + 16 + 16 + 6 + 8)?;
296            let books = bits.read(4)? + 1;
297            bits.skip(u64::from(books) * 8)?;
298        }
299        1 => {
300            let partitions = bits.read(5)?;
301            let mut classes = Vec::with_capacity(partitions as usize);
302            for _ in 0..partitions {
303                classes.push(bits.read(4)?);
304            }
305            let class_count = classes.iter().max().map_or(0, |&max| max + 1);
306            let mut dimensions = Vec::with_capacity(class_count as usize);
307            for _ in 0..class_count {
308                dimensions.push(bits.read(3)? + 1);
309                let subclasses = bits.read(2)?;
310                if subclasses != 0 {
311                    bits.read(8)?;
312                }
313                bits.skip((1_u64 << subclasses) * 8)?;
314            }
315            bits.read(2)?;
316            let range_bits = bits.read(4)?;
317            for class in classes {
318                bits.skip(u64::from(dimensions[class as usize]) * u64::from(range_bits))?;
319            }
320        }
321        _ => return Err(malformed("Vorbis setup header has an invalid floor type")),
322    }
323    Ok(())
324}
325
326fn skip_residue(bits: &mut BitReader<'_>) -> Result<()> {
327    if bits.read(16)? > 2 {
328        return Err(malformed("Vorbis setup header has an invalid residue type"));
329    }
330    bits.read(24)?;
331    bits.read(24)?;
332    bits.read(24)?;
333    let classifications = bits.read(6)? + 1;
334    bits.read(8)?;
335    let mut books = 0;
336    for _ in 0..classifications {
337        let low = bits.read(3)?;
338        let high = if bits.read(1)? == 1 { bits.read(5)? } else { 0 };
339        books += (high << 3 | low).count_ones();
340    }
341    bits.skip(u64::from(books) * 8)
342}
343
344fn skip_mapping(bits: &mut BitReader<'_>, channels: u8) -> Result<()> {
345    if bits.read(16)? != 0 {
346        return Err(malformed("Vorbis setup header has an invalid mapping type"));
347    }
348    let submaps = if bits.read(1)? == 1 {
349        bits.read(4)? + 1
350    } else {
351        1
352    };
353    let channel_bits = ilog(u32::from(channels) - 1);
354    if bits.read(1)? == 1 {
355        let steps = bits.read(8)? + 1;
356        bits.skip(u64::from(steps) * 2 * u64::from(channel_bits))?;
357    }
358    if bits.read(2)? != 0 {
359        return Err(malformed(
360            "Vorbis setup header mapping reserved bits are set",
361        ));
362    }
363    if submaps > 1 {
364        bits.skip(u64::from(channels) * 4)?;
365    }
366    bits.skip(u64::from(submaps) * 24)
367}
368
369/// The number of bits needed to hold `value` (Vorbis I section 9.2.1).
370fn ilog(value: u32) -> u32 {
371    u32::BITS - value.leading_zeros()
372}
373
374/// The greatest integer whose `dimensions`th power is at most `entries`
375/// (Vorbis I section 9.2.3).
376fn lookup1_values(entries: u32, dimensions: u32) -> u64 {
377    if dimensions == 0 {
378        return 0;
379    }
380    let mut value = (f64::from(entries))
381        .powf(1.0 / f64::from(dimensions))
382        .floor() as u64;
383    while (value + 1)
384        .checked_pow(dimensions)
385        .is_some_and(|power| power <= u64::from(entries))
386    {
387        value += 1;
388    }
389    while value > 0
390        && value
391            .checked_pow(dimensions)
392            .is_none_or(|power| power > u64::from(entries))
393    {
394        value -= 1;
395    }
396    value
397}
398
399/// Reads Vorbis's least-significant-bit-first packing.
400struct BitReader<'a> {
401    bytes: &'a [u8],
402    position: u64,
403}
404
405impl<'a> BitReader<'a> {
406    fn new(bytes: &'a [u8]) -> Self {
407        Self { bytes, position: 0 }
408    }
409
410    fn read(&mut self, count: u32) -> Result<u32> {
411        debug_assert!(count <= 32);
412        let end = self.position + u64::from(count);
413        if end > self.bytes.len() as u64 * 8 {
414            return Err(malformed("Vorbis packet is truncated"));
415        }
416        let mut value = 0_u64;
417        for bit in 0..u64::from(count) {
418            let at = self.position + bit;
419            let byte = self.bytes[(at / 8) as usize];
420            value |= u64::from((byte >> (at % 8)) & 1) << bit;
421        }
422        self.position = end;
423        Ok(value as u32)
424    }
425
426    fn skip(&mut self, count: u64) -> Result<()> {
427        let end = self
428            .position
429            .checked_add(count)
430            .filter(|&end| end <= self.bytes.len() as u64 * 8)
431            .ok_or_else(|| malformed("Vorbis packet is truncated"))?;
432        self.position = end;
433        Ok(())
434    }
435}
436
437fn malformed(message: impl Into<String>) -> Error {
438    Error::new(ErrorKind::MalformedMedia, message)
439}
440
441fn unsupported(message: impl Into<String>) -> Error {
442    Error::new(ErrorKind::Unsupported, message)
443}