Have symphonia handle the conversion
This commit is contained in:
parent
b030c79971
commit
3bf3c38a77
|
@ -1,18 +1,9 @@
|
||||||
mod raw_audio;
|
mod raw_audio;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use symphonia::core::audio::SampleBuffer;
|
|
||||||
use tool_helper::{Error, Input};
|
use tool_helper::{Error, Input};
|
||||||
|
|
||||||
use symphonia::core::codecs::{DecoderOptions, CODEC_TYPE_NULL};
|
|
||||||
use symphonia::core::errors::Error as SymError;
|
|
||||||
use symphonia::core::formats::FormatOptions;
|
|
||||||
use symphonia::core::io::MediaSourceStream;
|
|
||||||
use symphonia::core::meta::MetadataOptions;
|
|
||||||
use symphonia::core::probe::Hint;
|
|
||||||
|
|
||||||
pub fn convert(input: Input, _output: &mut dyn Write) -> Result<(), Error> {
|
pub fn convert(input: Input, _output: &mut dyn Write) -> Result<(), Error> {
|
||||||
raw_audio::load_raw_audio(input)?;
|
let _prepared_xa_audio = raw_audio::load_for_xa_audio(input)?;
|
||||||
|
|
||||||
Err(Error::not_implemented("XA conversion"))
|
Err(Error::not_implemented("XA conversion"))
|
||||||
}
|
}
|
|
@ -1,80 +0,0 @@
|
||||||
use std::io::Write;
|
|
||||||
use clap::error::ErrorKind;
|
|
||||||
use symphonia::core::audio::SampleBuffer;
|
|
||||||
use tool_helper::{Error, Input};
|
|
||||||
|
|
||||||
use symphonia::core::codecs::{DecoderOptions, CODEC_TYPE_NULL};
|
|
||||||
use symphonia::core::errors::Error as SymError;
|
|
||||||
use symphonia::core::formats::FormatOptions;
|
|
||||||
use symphonia::core::io::MediaSourceStream;
|
|
||||||
use symphonia::core::meta::MetadataOptions;
|
|
||||||
use symphonia::core::probe::Hint;
|
|
||||||
|
|
||||||
pub struct RawAudio {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_raw_audio(input: Input) -> Result<RawAudio, Error> {
|
|
||||||
let media_stream = MediaSourceStream::new(Box::new(load_to_ram(input)?), Default::default());
|
|
||||||
let probed = symphonia::default::get_probe().format(&Hint::new(), media_stream, &FormatOptions::default(), &MetadataOptions::default()).expect("unsupported format");
|
|
||||||
let mut format = probed.format;
|
|
||||||
let track = format.tracks().iter().find(|t| t.codec_params.codec != CODEC_TYPE_NULL).expect("no supported audio tracks");
|
|
||||||
|
|
||||||
// Use the default options for the decoder.
|
|
||||||
let dec_opts: DecoderOptions = Default::default();
|
|
||||||
|
|
||||||
// Create a decoder for the track.
|
|
||||||
let mut decoder = symphonia::default::get_codecs().make(&track.codec_params, &dec_opts).expect("unsupported codec");
|
|
||||||
|
|
||||||
// Store the track identifier, it will be used to filter packets.
|
|
||||||
let track_id = track.id;
|
|
||||||
|
|
||||||
// The decode loop.
|
|
||||||
loop {
|
|
||||||
// Get the next packet from the media format.
|
|
||||||
let packet = match format.next_packet() {
|
|
||||||
Ok(packet) => packet,
|
|
||||||
Err(SymError::ResetRequired) => {
|
|
||||||
return Err(Error::not_implemented("Miau"));
|
|
||||||
}
|
|
||||||
Err(SymError::IoError(err)) => {
|
|
||||||
// A unrecoverable error occurred, halt decoding.
|
|
||||||
if err.kind() == std::io::ErrorKind::UnexpectedEof {
|
|
||||||
return Err(Error::not_implemented("Miau2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
panic!("{}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// A unrecoverable error occurred, halt decoding.
|
|
||||||
panic!("{}", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Consume any new metadata that has been read since the last packet.
|
|
||||||
while !format.metadata().is_latest() {
|
|
||||||
// Pop the old head of the metadata queue.
|
|
||||||
format.metadata().pop();
|
|
||||||
|
|
||||||
// Consume the new metadata at the head of the metadata queue.
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the packet does not belong to the selected track, skip over it.
|
|
||||||
if packet.track_id() != track_id {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode the packet into audio samples.
|
|
||||||
let packet = decoder.decode(&packet).expect("Urgh");
|
|
||||||
println!(">>>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_to_ram(mut input: Input) -> Result<std::io::Cursor<Vec<u8>>, Error> {
|
|
||||||
let mut buffer = Vec::default();
|
|
||||||
|
|
||||||
input.read_to_end(&mut buffer)?;
|
|
||||||
Ok(std::io::Cursor::new(buffer))
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
use super::Error;
|
||||||
|
use symphonia::core::errors::Error as SymError;
|
||||||
|
|
||||||
|
fn generic_map_error(action: &str, error: SymError) -> Error {
|
||||||
|
Error::from_text(format!("symphonia error: {} during {}", error, action))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn probe(error: SymError) -> Error {
|
||||||
|
generic_map_error("probing of input", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decoder(error: SymError) -> Error {
|
||||||
|
generic_map_error("finding codec", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_packet(error: SymError) -> Error {
|
||||||
|
generic_map_error("getting next raw packet", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(error: SymError) -> Error {
|
||||||
|
generic_map_error("decoding of raw packet", error)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_track() -> Error {
|
||||||
|
Error::from_str("symphonia error: No audio track located")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn no_buffer_created() -> Error {
|
||||||
|
Error::from_str("No packets found for XA conversion")
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
mod error;
|
||||||
|
|
||||||
|
use symphonia::core::audio::{RawSampleBuffer, SignalSpec};
|
||||||
|
use symphonia::core::codecs::{Decoder, DecoderOptions, CODEC_TYPE_NULL};
|
||||||
|
use symphonia::core::errors::Error as SymError;
|
||||||
|
use symphonia::core::formats::{FormatReader, FormatOptions};
|
||||||
|
use symphonia::core::io::MediaSourceStream;
|
||||||
|
use symphonia::core::meta::MetadataOptions;
|
||||||
|
use symphonia::core::probe::Hint;
|
||||||
|
use tool_helper::{Error, Input};
|
||||||
|
|
||||||
|
type XASamples = RawSampleBuffer::<i16>;
|
||||||
|
|
||||||
|
pub fn load_for_xa_audio(input: Input) -> Result<XASamples, Error> {
|
||||||
|
let media_stream = MediaSourceStream::new(Box::new(load_to_ram(input)?), Default::default());
|
||||||
|
let format = symphonia::default::get_probe().format(&Hint::new(), media_stream, &FormatOptions::default(), &MetadataOptions::default()).map_err(error::probe)?.format;
|
||||||
|
let track = format.tracks().iter().find(|t| t.codec_params.codec != CODEC_TYPE_NULL).ok_or_else(error::find_track)?;
|
||||||
|
|
||||||
|
// Create a decoder for the track.
|
||||||
|
let decoder = symphonia::default::get_codecs().make(&track.codec_params, &DecoderOptions::default()).map_err(error::decoder)?;
|
||||||
|
let track_id = track.id;
|
||||||
|
|
||||||
|
decode(format, decoder, track_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(mut format: Box<dyn FormatReader>, mut decoder: Box<dyn Decoder>, track_id: u32) -> Result<XASamples, Error> {
|
||||||
|
let mut xa_audio = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Get the next packet from the media format.
|
||||||
|
let packet = match format.next_packet() {
|
||||||
|
Ok(packet) => packet,
|
||||||
|
Err(err) => {
|
||||||
|
if let SymError::IoError(io_err) = &err {
|
||||||
|
if io_err.kind() == std::io::ErrorKind::UnexpectedEof {
|
||||||
|
return xa_audio.ok_or_else(error::no_buffer_created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(error::next_packet(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Consume any new metadata that has been read since the last packet.
|
||||||
|
format.metadata().skip_to_latest();
|
||||||
|
|
||||||
|
// If the packet does not belong to the selected track, skip over it.
|
||||||
|
if packet.track_id() != track_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the packet into audio samples.
|
||||||
|
let packet = decoder.decode(&packet).map_err(error::decode)?;
|
||||||
|
if xa_audio.is_none() {
|
||||||
|
let duration = packet.capacity() as u64;
|
||||||
|
|
||||||
|
xa_audio = Some(XASamples::new(duration, SignalSpec::new_with_layout(44_100, symphonia::core::audio::Layout::Stereo)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(xa_audio) = &mut xa_audio {
|
||||||
|
xa_audio.copy_interleaved_ref(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_to_ram(mut input: Input) -> Result<std::io::Cursor<Vec<u8>>, Error> {
|
||||||
|
let mut buffer = Vec::default();
|
||||||
|
|
||||||
|
input.read_to_end(&mut buffer)?;
|
||||||
|
Ok(std::io::Cursor::new(buffer))
|
||||||
|
}
|
Loading…
Reference in New Issue