mod vorbis_decoder;
#[doc(hidden)]
pub mod vorbis_simd;
#[allow(unused_imports)]
use zvidlib_core::*;
use crate::vorbis_decoder::VorbisDecoder;
use crate::{
AudioBuffer, AudioDecoder, CancellationToken, EncodedAudioSample, Error, ErrorKind, Limits,
Result,
};
use symphonia_core::audio::{AudioBufferRef, SampleBuffer};
use symphonia_core::codecs::{CODEC_TYPE_VORBIS, CodecParameters, Decoder, DecoderOptions};
use symphonia_core::formats::Packet;
#[doc(inline)]
pub use zvidlib_vorbis_syntax::{VORBIS_PREROLL_PACKETS, VorbisConfig};
pub struct NativeVorbisDecoder {
decoder: VorbisDecoder,
channels: u16,
sample_rate: u32,
cold: bool,
limits: Limits,
}
impl NativeVorbisDecoder {
pub fn new(config: &VorbisConfig, limits: Limits) -> Result<Self> {
let channels = u16::from(config.channels);
if channels > limits.max_audio_channels || config.sample_rate > limits.max_sample_rate {
return Err(Error::new(
ErrorKind::ResourceLimit,
"Vorbis channel count or sample rate is outside configured limits",
));
}
let mut extra_data = config.identification_header.clone();
extra_data.extend_from_slice(&config.setup_header);
let mut parameters = CodecParameters::new();
parameters
.for_codec(CODEC_TYPE_VORBIS)
.with_extra_data(extra_data.into_boxed_slice());
let decoder =
VorbisDecoder::try_new(¶meters, &DecoderOptions::default()).map_err(|error| {
unsupported(format!("Vorbis configuration is unsupported: {error}"))
})?;
Ok(Self {
decoder,
channels,
sample_rate: config.sample_rate,
cold: true,
limits,
})
}
}
impl AudioDecoder for NativeVorbisDecoder {
fn decode(
&mut self,
sample: &EncodedAudioSample,
cancellation: &CancellationToken,
) -> Result<AudioBuffer> {
if cancellation.is_canceled() {
return Err(Error::new(ErrorKind::Canceled, "Vorbis decode canceled"));
}
let cold = std::mem::replace(&mut self.cold, false);
let channels = usize::from(self.channels);
let decoded = self
.decoder
.decode(&Packet::new_from_slice(
0,
sample.decoded_range.start,
sample.decoded_range.len(),
&sample.data,
))
.map_err(|error| codec(format!("malformed Vorbis packet: {error}")))?;
let frames = decoded.frames();
let expected = sample.decoded_range.len();
let samples = if frames as u64 == expected {
interleave(decoded)
} else if frames == 0 && cold {
vec![
0.0;
usize::try_from(expected)
.unwrap_or(usize::MAX)
.saturating_mul(channels)
]
} else {
return Err(codec(format!(
"Vorbis decoder produced {frames} frames for an indexed {expected}-frame interval"
)));
};
AudioBuffer::new(
sample.decoded_range,
self.sample_rate,
self.channels,
samples,
&self.limits,
)
}
fn reset(&mut self) -> Result<()> {
self.decoder.reset();
self.cold = true;
Ok(())
}
}
fn interleave(decoded: AudioBufferRef<'_>) -> Vec<f32> {
if decoded.frames() == 0 {
return Vec::new();
}
let mut interleaved = SampleBuffer::<f32>::new(decoded.frames() as u64, *decoded.spec());
interleaved.copy_interleaved_ref(decoded);
interleaved.samples().to_vec()
}
fn codec(message: impl Into<String>) -> Error {
Error::new(ErrorKind::Codec, message)
}
fn unsupported(message: impl Into<String>) -> Error {
Error::new(ErrorKind::Unsupported, message)
}
#[doc(hidden)]
#[must_use]
pub fn simd_sites() -> Vec<(&'static str, zvidlib_core::SimdIsa)> {
vec![("vorbis_decode", vorbis_simd::active_isa())]
}