use crate::packet;
pub const MAX_PACKET: usize = 15000;
pub const MAX_FRAME_SIZE: usize = 96000;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BitPacket<'a> {
pub data: &'a [u8],
pub enc_final_range: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BitstreamError {
InvalidLength { index: usize, len: u32 },
RanOutOfInput { index: usize, expected: usize, got: usize },
}
impl core::fmt::Display for BitstreamError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match *self {
BitstreamError::InvalidLength { len, .. } => {
write!(f, "Invalid payload length: {}", len as i32)
}
BitstreamError::RanOutOfInput { expected, got, .. } => {
write!(f, "Ran out of input, expecting {expected} bytes got {got}")
}
}
}
}
impl std::error::Error for BitstreamError {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Bitstream<'a> {
pub packets: Vec<BitPacket<'a>>,
pub error: Option<BitstreamError>,
}
pub fn parse_bitstream(bytes: &[u8]) -> Bitstream<'_> {
let mut packets = Vec::new();
let mut rest = bytes;
let error = loop {
let index = packets.len();
let Some((len, tail)) = read_u32(rest) else {
break None;
};
if len as usize > MAX_PACKET || (len as i32) < 0 {
break Some(BitstreamError::InvalidLength { index, len });
}
let Some((enc_final_range, tail)) = read_u32(tail) else {
break None;
};
let len = len as usize;
if tail.len() < len {
break Some(BitstreamError::RanOutOfInput { index, expected: len, got: tail.len() });
}
let (data, tail) = tail.split_at(len);
packets.push(BitPacket { data, enc_final_range });
rest = tail;
};
Bitstream { packets, error }
}
fn read_u32(bytes: &[u8]) -> Option<(u32, &[u8])> {
let (head, tail) = bytes.split_first_chunk::<4>()?;
Some((u32::from_be_bytes(*head), tail))
}
pub fn write_record(out: &mut Vec<u8>, data: &[u8], enc_final_range: u32) {
out.extend_from_slice(&(data.len() as u32).to_be_bytes());
out.extend_from_slice(&enc_final_range.to_be_bytes());
out.extend_from_slice(data);
}
pub trait DemoDecoder {
fn channels(&self) -> usize;
fn decode24(
&mut self,
data: &[u8],
frame_size: usize,
decode_fec: bool,
out: &mut [i32],
) -> Result<usize, &'static str>;
fn last_packet_duration(&self) -> usize;
fn final_range(&self) -> u32;
}
impl DemoDecoder for crate::OpusDecoder {
fn channels(&self) -> usize {
crate::OpusDecoder::channels(self).count()
}
fn decode24(
&mut self,
data: &[u8],
frame_size: usize,
decode_fec: bool,
out: &mut [i32],
) -> Result<usize, &'static str> {
if frame_size == 0 {
return Err(crate::Error::INVALID_FRAME_SIZE.message());
}
let frame_size = if !data.is_empty() && !decode_fec {
frame_size.min(packet::nb_samples(data, self.sampling_rate()).map_err(|e| e.message())?)
} else {
frame_size
};
let channels = crate::OpusDecoder::channels(self).count();
let mut pcm = vec![0.0f32; frame_size * channels];
let n = if decode_fec {
self.decode_fec(data, frame_size, &mut pcm)
} else {
self.decode(data, frame_size, &mut pcm)
}
.map_err(|e| e.message())?;
for (o, &x) in out.iter_mut().zip(&pcm[..n * channels]) {
*o = res2int24(x);
}
Ok(n)
}
fn last_packet_duration(&self) -> usize {
crate::OpusDecoder::last_packet_duration(self)
}
fn final_range(&self) -> u32 {
crate::OpusDecoder::final_range(self)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RangeMismatch {
pub packet: usize,
pub encoder: u32,
pub decoder: u32,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct DemoOutput {
pub pcm: Vec<i16>,
pub packets: usize,
pub lost: usize,
pub fec_calls: usize,
pub decode_errors: usize,
pub range_checks: usize,
pub range_mismatch: Option<RangeMismatch>,
}
pub fn decode_bitstream<D: DemoDecoder + ?Sized>(
decoder: &mut D,
packets: &[BitPacket<'_>],
) -> DemoOutput {
let channels = decoder.channels();
let mut out = vec![0i32; MAX_FRAME_SIZE * channels];
let mut result = DemoOutput::default();
let mut lost_prev = true;
let mut lost_count = 0usize;
for (index, packet) in packets.iter().enumerate() {
let data = packet.data;
let lost = data.is_empty();
result.packets += 1;
let run_decoder = if lost {
lost_count += 1;
result.lost += 1;
0
} else {
1 + lost_count
};
for fr in 0..run_decoder {
let decoded = if fr + 1 == lost_count && packet::has_lbrr(data).unwrap_or(true) {
result.fec_calls += 1;
let n = decoder.last_packet_duration();
decoder.decode24(data, n, true, &mut out)
} else if fr < lost_count {
let n = decoder.last_packet_duration();
decoder.decode24(&[], n, false, &mut out)
} else {
decoder.decode24(data, MAX_FRAME_SIZE, false, &mut out)
};
match decoded {
Ok(n) if n > 0 => {
result.pcm.extend(out[..n * channels].iter().map(|&s| s24_to_s16(s)));
}
_ => result.decode_errors += 1,
}
}
if packet.enc_final_range != 0 && !lost && !lost_prev {
result.range_checks += 1;
let decoder_range = decoder.final_range();
if decoder_range != packet.enc_final_range {
result.range_mismatch = Some(RangeMismatch {
packet: index,
encoder: packet.enc_final_range,
decoder: decoder_range,
});
break;
}
}
lost_prev = lost;
if !lost {
lost_count = 0;
}
}
result
}
pub fn res2int24(x: f32) -> i32 {
let v = x * 8_388_608.0;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
if !(-2_147_483_648.0..2_147_483_648.0).contains(&v) {
return i32::MIN;
}
v.round_ties_even() as i32
}
fn s24_to_s16(s: i32) -> i16 {
let s = s.clamp(-0x7fff00, 0x7fff00);
((s + 128) >> 8) as i16
}
pub fn opus_demo_s16(x: f32) -> i16 {
s24_to_s16(res2int24(x))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn records_round_trip() {
let mut bytes = Vec::new();
write_record(&mut bytes, &[1, 2, 3], 0xdead_beef);
write_record(&mut bytes, &[], 0);
write_record(&mut bytes, &[9; 300], 7);
let parsed = parse_bitstream(&bytes);
assert_eq!(parsed.error, None);
assert_eq!(parsed.packets.len(), 3);
assert_eq!(parsed.packets[0], BitPacket { data: &[1, 2, 3], enc_final_range: 0xdead_beef });
assert_eq!(parsed.packets[1].data, &[] as &[u8]);
assert_eq!(parsed.packets[2].enc_final_range, 7);
let cut = parse_bitstream(&bytes[..25]);
assert_eq!(cut.error, None);
assert_eq!(cut.packets.len(), 2);
}
#[test]
fn bad_records_keep_the_prefix() {
let mut bytes = Vec::new();
write_record(&mut bytes, &[1, 2, 3], 1);
let good = bytes.len();
write_record(&mut bytes, &[5; 10], 2);
let cut = parse_bitstream(&bytes[..bytes.len() - 4]);
assert_eq!(cut.packets.len(), 1);
assert_eq!(cut.error, Some(BitstreamError::RanOutOfInput { index: 1, expected: 10, got: 6 }));
assert_eq!(cut.error.unwrap().to_string(), "Ran out of input, expecting 10 bytes got 6");
let mut bad = bytes[..good].to_vec();
bad.extend_from_slice(&15001u32.to_be_bytes());
bad.extend_from_slice(&[0; 8]);
let parsed = parse_bitstream(&bad);
assert_eq!(parsed.packets.len(), 1);
assert_eq!(parsed.error, Some(BitstreamError::InvalidLength { index: 1, len: 15001 }));
let mut negative = bytes[..good].to_vec();
negative.extend_from_slice(&0xffff_fff0u32.to_be_bytes());
assert_eq!(parse_bitstream(&negative).error.unwrap().to_string(), "Invalid payload length: -16");
}
#[test]
fn sixteen_bit_conversion() {
assert_eq!(opus_demo_s16(1.0), 32767);
assert_eq!(opus_demo_s16(-1.0), -32767);
assert_eq!(opus_demo_s16(0.0), 0);
assert_eq!(opus_demo_s16(0.5 / 32768.0), 1);
assert_eq!(opus_demo_s16(-0.5 / 32768.0), 0);
assert_eq!(opus_demo_s16(1.5 / 32768.0), 2);
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
{
assert_eq!(opus_demo_s16(f32::NAN), 0);
assert_eq!(opus_demo_s16(1e30), 32767);
assert_eq!(opus_demo_s16(-1e30), -32767);
}
assert_eq!(res2int24(0.5 / 8_388_608.0), 0);
assert_eq!(res2int24(1.5 / 8_388_608.0), 2);
}
}