use std::error::Error;
use std::io::{Read, Seek, SeekFrom};
use crate::buffer::{AudioBuffer, ChannelData};
use symphonia::core::audio::AudioBufferRef;
use symphonia::core::audio::Signal;
use symphonia::core::codecs::{Decoder, DecoderOptions};
use symphonia::core::conv::FromSample;
use symphonia::core::errors::Error as SymphoniaError;
use symphonia::core::formats::{FormatOptions, FormatReader};
use symphonia::core::meta::MetadataOptions;
use symphonia::core::probe::Hint;
struct MediaInput<R> {
input: R,
}
impl<R: Read> MediaInput<R> {
pub fn new(input: R) -> Self {
Self { input }
}
}
impl<R: Read> Read for MediaInput<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.input.read(buf)
}
}
impl<R> Seek for MediaInput<R> {
fn seek(&mut self, _pos: SeekFrom) -> std::io::Result<u64> {
panic!("MediaInput does not support seeking")
}
}
impl<R: Read + Send + Sync> symphonia::core::io::MediaSource for MediaInput<R> {
fn is_seekable(&self) -> bool {
false
}
fn byte_len(&self) -> Option<u64> {
None
}
}
pub(crate) struct MediaDecoder {
format: Box<dyn FormatReader>,
decoder: Box<dyn Decoder>,
}
impl MediaDecoder {
pub fn try_new<R: std::io::Read + Send + Sync + 'static>(
input: R,
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
let input = Box::new(MediaInput::new(input));
let mss = symphonia::core::io::MediaSourceStream::new(input, Default::default());
let hint = Hint::new();
let format_opts: FormatOptions = Default::default();
let metadata_opts: MetadataOptions = Default::default();
let decoder_opts: DecoderOptions = Default::default();
let probed =
symphonia::default::get_probe().format(&hint, mss, &format_opts, &metadata_opts)?;
let format = probed.format;
let track = format.default_track().ok_or(SymphoniaError::Unsupported(
"no default media track available",
))?;
let decoder = symphonia::default::get_codecs().make(&track.codec_params, &decoder_opts)?;
Ok(Self { format, decoder })
}
}
impl Iterator for MediaDecoder {
type Item = Result<AudioBuffer, Box<dyn Error + Send + Sync>>;
fn next(&mut self) -> Option<Self::Item> {
let format = &mut self.format;
let decoder = &mut self.decoder;
let track = format.default_track().unwrap();
let number_of_channels = track.codec_params.channels.unwrap().count();
let input_sample_rate = track.codec_params.sample_rate.unwrap() as f32;
let track_id = track.id;
loop {
let packet = match format.next_packet() {
Err(e) => {
log::error!("next packet err {:?}", e);
return None;
}
Ok(p) => p,
};
if packet.track_id() != track_id {
continue;
}
match decoder.decode(&packet) {
Ok(audio_buf) => {
let output = convert_buf(audio_buf, number_of_channels, input_sample_rate);
return Some(Ok(output));
}
Err(SymphoniaError::DecodeError(e)) => {
log::error!("Symphonia DecodeError {:?} - abort stream", e);
return Some(Err(Box::new(SymphoniaError::DecodeError(e))));
}
Err(SymphoniaError::IoError(e))
if e.kind() == std::io::ErrorKind::UnexpectedEof =>
{
}
Err(e) => {
return Some(Err(Box::new(e)));
}
};
}
}
}
fn convert_buf(
input: AudioBufferRef<'_>,
number_of_channels: usize,
input_sample_rate: f32,
) -> AudioBuffer {
let chans = 0..number_of_channels;
use symphonia::core::audio::AudioBufferRef::*;
let data: Vec<Vec<f32>> = match input {
U8(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
U16(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
U24(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
U32(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
S8(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
S16(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
S24(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
S32(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
F32(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
F64(buf) => chans
.map(|i| buf.chan(i).iter().copied().map(f32::from_sample).collect())
.collect(),
};
let channels = data.into_iter().map(ChannelData::from).collect();
AudioBuffer::from_channels(channels, input_sample_rate)
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_media_decoder() {
let input = Cursor::new(vec![0; 32]);
let media = MediaDecoder::try_new(input);
assert!(media.is_err()); }
}