mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Opus: validate the header in Decoder::from_head (#425)
This commit is contained in:
@@ -123,6 +123,23 @@ impl OpusHead {
|
||||
Ok(OpusHead { channels, pre_skip, input_sample_rate, output_gain, mapping_family: family, streams, coupled_streams: coupled, mapping })
|
||||
}
|
||||
|
||||
/// Checks the invariants the decoder indexes by, for headers built by hand rather than parsed.
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
if self.channels == 0 {
|
||||
return Err(Error::InvalidHeader("zero channels"));
|
||||
}
|
||||
if self.streams == 0 || self.coupled_streams > self.streams || self.streams + self.coupled_streams > 255 {
|
||||
return Err(Error::InvalidHeader("bad stream counts"));
|
||||
}
|
||||
if self.mapping.len() != self.channels {
|
||||
return Err(Error::InvalidHeader("channel mapping length differs from channel count"));
|
||||
}
|
||||
if self.mapping.iter().any(|&m| m != 255 && m as usize >= self.streams + self.coupled_streams) {
|
||||
return Err(Error::InvalidHeader("channel mapping out of range"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Linear output gain factor.
|
||||
pub fn gain_linear(&self) -> f32 {
|
||||
10f32.powf(self.output_gain as f32 / (20.0 * 256.0))
|
||||
|
||||
@@ -32,6 +32,7 @@ impl Decoder {
|
||||
|
||||
/// Creates a decoder for a parsed header at `sample_rate` (8/12/16/24/48 kHz).
|
||||
pub fn from_head(head: OpusHead, sample_rate: u32) -> Result<Decoder> {
|
||||
head.validate()?;
|
||||
let mut streams = Vec::with_capacity(head.streams);
|
||||
for s in 0..head.streams {
|
||||
let ch = if s < head.coupled_streams { 2 } else { 1 };
|
||||
@@ -169,3 +170,29 @@ fn reframe(p: &Packet) -> Vec<u8> {
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn head(channels: usize, streams: usize, coupled: usize, mapping: Vec<u8>) -> OpusHead {
|
||||
OpusHead { channels, pre_skip: 0, input_sample_rate: 48000, output_gain: 0, mapping_family: 1, streams, coupled_streams: coupled, mapping }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_head_rejects_inconsistent_headers() {
|
||||
assert!(Decoder::from_head(head(1, 0, 0, vec![0]), 48000).is_err(), "zero streams");
|
||||
assert!(Decoder::from_head(head(2, 1, 0, vec![0]), 48000).is_err(), "short mapping");
|
||||
assert!(Decoder::from_head(head(1, 1, 0, vec![1]), 48000).is_err(), "mapping index out of range");
|
||||
assert!(Decoder::from_head(head(1, 1, 2, vec![0]), 48000).is_err(), "more coupled than streams");
|
||||
assert!(Decoder::from_head(head(0, 1, 0, vec![]), 48000).is_err(), "zero channels");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_head_accepts_valid_headers() {
|
||||
assert!(Decoder::from_head(head(1, 1, 0, vec![0]), 48000).is_ok());
|
||||
assert!(Decoder::from_head(head(2, 1, 1, vec![0, 1]), 48000).is_ok());
|
||||
assert!(Decoder::from_head(head(3, 2, 1, vec![0, 1, 2]), 48000).is_ok());
|
||||
assert!(Decoder::from_head(head(2, 1, 0, vec![0, 255]), 48000).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user