From 5a39e523da7f4fe2c9c1e6c369a366162be122fa Mon Sep 17 00:00:00 2001 From: jakka Date: Wed, 4 Jun 2025 17:07:16 +0300 Subject: started rewriting --- src/flac.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/flac.rs (limited to 'src/flac.rs') diff --git a/src/flac.rs b/src/flac.rs new file mode 100644 index 0000000..8b03664 --- /dev/null +++ b/src/flac.rs @@ -0,0 +1,130 @@ +use anyhow::{Result, anyhow}; +use flac_bound::{FlacEncoder, WriteWrapper}; +use std::fs::File; +use symphonia::core::{ + audio::SampleBuffer, + codecs::{DecoderOptions, CODEC_TYPE_NULL}, + errors::Error::DecodeError, + formats::{FormatOptions, Track}, + io::MediaSourceStream, + meta::MetadataOptions, + probe::{Hint, ProbeResult}, +}; + +#[derive(Debug)] +struct StreamConfig { + channels: u32, + bits_per_sample: Bps, + sample_rate: u32, + total_samples_estimate: u64, +} + +#[derive(Debug)] +enum Bps { + _16, + _24, + _32 +} + +fn get_probe(file: &std::path::Path) -> Result { + let src = std::fs::File::open(file)?; + let mss = MediaSourceStream::new(Box::new(src), Default::default()); + let mut hint = Hint::new(); + hint.with_extension("flac"); + let meta_opts: MetadataOptions = Default::default(); + let fmt_opts: FormatOptions = Default::default(); + Ok(symphonia::default::get_probe().format(&hint, mss, &fmt_opts, &meta_opts)?) +} + +fn read_streaminfo(track: &Track) -> Result { + let params = &track.codec_params; + + Ok(StreamConfig { + channels: params.channels.unwrap().count() as u32, + bits_per_sample: match params.bits_per_sample.unwrap() { + 16 => Bps::_16, + 24 => Bps::_24, + 32 => Bps::_32, + _ => return Err(anyhow!("invalid Bps")) + }, + sample_rate: params.sample_rate.unwrap(), + total_samples_estimate: params.n_frames.unwrap(), + }) +} + +pub fn encode_file(file: &std::path::Path) -> Result<()> { + let probed = get_probe(file)?; + let mut format = probed.format; + let dec_opts: DecoderOptions = Default::default(); + let track = format + .tracks() + .iter() + .find(|t| t.codec_params.codec != CODEC_TYPE_NULL) + .unwrap(); + + let config = read_streaminfo(track)?; + + let mut outf = File::create(format!("{}.{}", file.display(), "tmp"))?; + let mut outw = WriteWrapper(&mut outf); + let mut enc = FlacEncoder::new() + .unwrap() + .channels(config.channels) + .bits_per_sample(match config.bits_per_sample { + Bps::_16 => 16, + Bps::_24 => 24, + Bps::_32 => 32 + }) + .sample_rate(config.sample_rate) + .total_samples_estimate(config.total_samples_estimate) + .compression_level(8) + .verify(true) + .init_write(&mut outw) + .unwrap(); + + let mut decoder = symphonia::default::get_codecs() + .make(&track.codec_params, &dec_opts) + .unwrap(); + let track_id = track.id; + + let mut sample_buf = None; + + loop { + let packet = format.next_packet().unwrap(); + + if packet.track_id() != track_id { + continue; + } + + match decoder.decode(&packet) { + Ok(audio_buf) => { + if sample_buf.is_none() { + let spec = *audio_buf.spec(); + + let duration = audio_buf.capacity() as u64; + sample_buf = Some(SampleBuffer::::new(duration, spec)); + + /* match config.bits_per_sample { + Bps::_16 => sample_buf = Some(SampleBuffer::::new(duration, spec)), + Bps::_24 => sample_buf = Some(SampleBuffer::::new(duration, spec)), + Bps::_32 => sample_buf = Some(SampleBuffer::::new(duration, spec)), + } */ + } + + if let Some(buf) = &mut sample_buf { + buf.copy_interleaved_ref(audio_buf); + let mut samples = Vec::new(); + _ = buf.samples().iter().map(|sample| samples.push(*sample as i32)).collect::>(); + enc.process_interleaved(samples.as_slice(), samples.iter().len() as u32 / config.channels) + .unwrap(); + } + } + Err(DecodeError(_)) => (), + Err(_) => break, + } + } + + match enc.finish() { + Ok(_) => Ok(()), + Err(enc) => Err(anyhow!("Encoding failed:\t{:?}", enc.state())), + } +} -- cgit v1.3.1