add symphonia codec support for opening and exporting encoded files (not bendable since that would lead to data corruption)

This commit is contained in:
Breval Ferrari 2025-03-17 00:33:38 -04:00
parent 2733cd9345
commit 4d80833bbd
No known key found for this signature in database
GPG key ID: F71E304D6400AB8E

View file

@ -1,31 +1,40 @@
use std::io; use std::io::{self, Read};
use derive_new::new;
use symphonia::{ use symphonia::{
core::{ core::{
audio::{RawSample, RawSampleBuffer}, audio::Signal,
codecs::Decoder,
conv::FromSample,
errors::Error,
formats::FormatReader,
io::MediaSourceStream, io::MediaSourceStream,
probe::Hint, probe::Hint,
sample::Sample, sample::{i24, u24},
}, },
default, default,
}; };
use crate::TryFromDataBytes; use crate::{IntoDataBytes, TryFromDataBytes};
pub struct Audio<S>(RawSampleBuffer<S>) use super::{RawSamples, Sample};
where
S: Sample + RawSample;
impl<S> TryFromDataBytes for Audio<S> /// The new hot thing: this represents audio in any format. You can open any file and make this thing with the file's bytes.
where /// You can then modify its bytes and see what it gives. Maybe it won't work anymore.
S: Sample + RawSample, /// You can also decode it to raw samples and play with it freely without corrupting anything.
{ #[derive(new)]
type Error = symphonia::core::errors::Error; pub struct Audio {
reader: Box<dyn FormatReader>,
decoder: Box<dyn Decoder>,
}
impl TryFromDataBytes for Audio {
type Error = Error;
type Format = Hint; type Format = Hint;
fn try_from_data_bytes( fn try_from_data_bytes(
bytes: crate::Bytes, bytes: crate::Bytes,
format: Self::Format, format: Self::Format,
crop: crate::Crop, _crop: crate::Crop,
) -> Result<Self, Self::Error> ) -> Result<Self, Self::Error>
where where
Self: Sized, Self: Sized,
@ -37,6 +46,84 @@ where
let reader = probe let reader = probe
.format(&format, mss, &Default::default(), &Default::default())? .format(&format, mss, &Default::default(), &Default::default())?
.format; .format;
todo!() let decoder = registry.make(&Default::default(), &Default::default())?;
Ok(Audio::new(reader, decoder))
}
}
impl IntoDataBytes for Audio {
fn into_data_bytes(self) -> crate::Bytes {
self.reader.into_inner().bytes().flatten().collect()
}
}
macro_rules! dynamic_map(
($dynimage: expr, $image: pat => $action: expr) => ({
match $dynimage {
symphonia::core::audio::AudioBufferRef::U8($image) => symphonia::core::audio::AudioBufferRef::U8($action),
symphonia::core::audio::AudioBufferRef::U16($image) => symphonia::core::audio::AudioBufferRef::U16($action),
symphonia::core::audio::AudioBufferRef::U24($image) => symphonia::core::audio::AudioBufferRef::U24($action),
symphonia::core::audio::AudioBufferRef::U32($image) => symphonia::core::audio::AudioBufferRef::U32($action),
symphonia::core::audio::AudioBufferRef::S8($image) => symphonia::core::audio::AudioBufferRef::S8($action),
symphonia::core::audio::AudioBufferRef::S16($image) => symphonia::core::audio::AudioBufferRef::S16($action),
symphonia::core::audio::AudioBufferRef::S24($image) => symphonia::core::audio::AudioBufferRef::S24($action),
symphonia::core::audio::AudioBufferRef::S32($image) => symphonia::core::audio::AudioBufferRef::S32($action),
symphonia::core::audio::AudioBufferRef::F32($image) => symphonia::core::audio::AudioBufferRef::F32($action),
symphonia::core::audio::AudioBufferRef::F64($image) => symphonia::core::audio::AudioBufferRef::F64($action),
}
});
($dynimage: expr, $image:pat_param, $action: expr) => (
match $dynimage {
symphonia::core::audio::AudioBufferRef::U8($image) => $action,
symphonia::core::audio::AudioBufferRef::U16($image) => $action,
symphonia::core::audio::AudioBufferRef::U24($image) => $action,
symphonia::core::audio::AudioBufferRef::U32($image) => $action,
symphonia::core::audio::AudioBufferRef::S8($image) => $action,
symphonia::core::audio::AudioBufferRef::S16($image) => $action,
symphonia::core::audio::AudioBufferRef::S24($image) => $action,
symphonia::core::audio::AudioBufferRef::S32($image) => $action,
symphonia::core::audio::AudioBufferRef::F32($image) => $action,
symphonia::core::audio::AudioBufferRef::F64($image) => $action,
}
);
);
impl<S> From<Audio> for RawSamples<S>
where
S: Sample
+ FromSample<u8>
+ FromSample<u16>
+ FromSample<u24>
+ FromSample<u32>
+ FromSample<i8>
+ FromSample<i16>
+ FromSample<i24>
+ FromSample<i32>
+ FromSample<f32>
+ FromSample<f64>,
{
fn from(mut value: Audio) -> Self {
RawSamples::from({
let mut result = Vec::new();
while let Ok(packet) = value.reader.next_packet() {
if let Ok(src) = value.decoder.decode(&packet) {
dynamic_map!(
src,
ref audio_buffer,
result.append(
&mut (0usize..src.spec().channels.count())
.flat_map(|ch| audio_buffer
.chan(ch)
.iter()
.map(|s| S::from_sample(s.clone()))
.collect::<Vec<S>>())
.collect::<Vec<S>>()
)
)
}
}
result
})
} }
} }