diff options
| -rw-r--r-- | Cargo.lock | 103 | ||||
| -rw-r--r-- | Cargo.toml | 3 | ||||
| -rw-r--r-- | src/flac.rs | 172 | ||||
| -rw-r--r-- | src/main.rs | 6 |
4 files changed, 193 insertions, 91 deletions
@@ -15,6 +15,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -51,12 +57,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "claxon" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" - -[[package]] name = "cmake" version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -121,6 +121,12 @@ dependencies = [ ] [[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] name = "libc" version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -137,6 +143,12 @@ dependencies = [ ] [[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] name = "md-5" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -157,6 +169,15 @@ dependencies = [ ] [[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -170,20 +191,88 @@ name = "reencoder" version = "0.1.0" dependencies = [ "anyhow", - "claxon", "flac-bound", "i24", "md-5", "metaflac", + "symphonia", ] [[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "symphonia" +version = "0.5.4" +source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#c7efbcb05dde274d13a50b4f7aac9db4c773f602" +dependencies = [ + "lazy_static", + "symphonia-bundle-flac", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-bundle-flac" +version = "0.5.4" +source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#c7efbcb05dde274d13a50b4f7aac9db4c773f602" +dependencies = [ + "log", + "symphonia-common", + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-common" +version = "0.5.4" +source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#c7efbcb05dde274d13a50b4f7aac9db4c773f602" +dependencies = [ + "symphonia-core", + "symphonia-metadata", +] + +[[package]] +name = "symphonia-core" +version = "0.5.4" +source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#c7efbcb05dde274d13a50b4f7aac9db4c773f602" +dependencies = [ + "bitflags", + "bytemuck", + "lazy_static", + "log", + "num-complex", + "smallvec", +] + +[[package]] +name = "symphonia-metadata" +version = "0.5.4" +source = "git+https://github.com/pdeljanov/Symphonia.git?branch=dev-0.6#c7efbcb05dde274d13a50b4f7aac9db4c773f602" +dependencies = [ + "lazy_static", + "log", + "regex-lite", + "smallvec", + "symphonia-core", +] + +[[package]] name = "typenum" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2,11 +2,12 @@ name = "reencoder" version = "0.1.0" edition = "2024" +repository = "https://github.com/justjakka/reencoder/" [dependencies] anyhow = "1.0.98" -claxon = "0.4.3" flac-bound = { version = "0.5.0", features = ["libflac-noogg"], default-features = false } i24 = "2.1.0" md-5 = "0.10.6" metaflac = "0.2.8" +symphonia = { git = "https://github.com/pdeljanov/Symphonia.git", branch = "dev-0.6", default-features = false, features = ["flac"] } diff --git a/src/flac.rs b/src/flac.rs index 7da93cb..af95a7a 100644 --- a/src/flac.rs +++ b/src/flac.rs @@ -1,16 +1,20 @@ use anyhow::{Result, anyhow}; -use claxon::FlacReader; use flac_bound::{FlacEncoder, WriteWrapper}; use i24::i24; use md5::{Digest, Md5}; use metaflac::{Block, Tag}; use std::fs::File; +use symphonia::core::{ + audio::{Audio, GenericAudioBufferRef}, + formats::{FormatOptions, TrackType, probe::Hint}, + io::MediaSourceStream, + meta::MetadataOptions, +}; struct StreamConfig { channels: u32, bits_per_sample: Bps, sample_rate: u32, - total_samples_estimate: u64, } enum Bps { @@ -38,85 +42,39 @@ impl Bps { } } -fn process_samples_i16( - hasher: &mut impl Digest, - mut reader: FlacReader<File>, - enc: &mut FlacEncoder, - config: &StreamConfig, -) -> Result<()> { - for samples in reader - .samples() - .map(|sample| sample.unwrap()) - .collect::<Vec<_>>() - .chunks(4096 * usize::try_from(config.channels).unwrap()) - { - enc.process_interleaved(samples, u32::try_from(samples.len()).unwrap() / config.channels) - .unwrap(); - let _ = samples - .iter() - .map(|sample| hasher.update((i16::try_from(*sample)).unwrap().to_le_bytes())) - .collect::<Vec<_>>(); - } - Ok(()) -} +pub fn encode_file(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"); -fn process_samples_i24( - hasher: &mut impl Digest, - mut reader: FlacReader<File>, - enc: &mut FlacEncoder, - config: &StreamConfig, -) -> Result<()> { - for samples in reader - .samples() - .map(|sample| sample.unwrap()) - .collect::<Vec<_>>() - .chunks(4096 * usize::try_from(config.channels).unwrap()) - { - enc.process_interleaved(samples, u32::try_from(samples.len()).unwrap() / config.channels) - .unwrap(); - let _ = samples - .iter() - .map(|sample| hasher.update((i24::try_from(*sample)).unwrap().to_le_bytes())) - .collect::<Vec<_>>(); - } - Ok(()) -} + let format_opts: FormatOptions = Default::default(); + let metadata_opts: MetadataOptions = Default::default(); -/* fn process_samples_i32( - hasher: &mut impl Digest, - mut reader: FlacReader<File>, - enc: &mut FlacEncoder, - config: &StreamConfig, -) -> Result<()> { - for samples in reader - .samples() - .map(|sample| sample.unwrap()) - .collect::<Vec<_>>() - .chunks(4096 * usize::try_from(config.channels).unwrap()) - { - enc.process_interleaved(samples, u32::try_from(samples.len()).unwrap() / config.channels) - .unwrap(); - let _ = samples - .iter() - .map(|sample| hasher.update(sample.to_le_bytes())) - .collect::<Vec<_>>(); - } - for sample in reader.samples() { - sample?; - } - Ok(()) -} */ + let mut format = symphonia::default::get_probe() + .probe(&hint, mss, format_opts, metadata_opts) + .unwrap(); + + let track = format.default_track(TrackType::Audio).unwrap(); + + let mut decoder = symphonia::default::get_codecs() + .make_audio_decoder( + track.codec_params.as_ref().unwrap().audio().unwrap(), + &Default::default(), + ) + .unwrap(); + + let track_id = track.id; + + let params = track.codec_params.as_ref().unwrap().audio().unwrap(); -pub fn encode_file(file: &std::path::Path) -> Result<()> { - let reader = claxon::FlacReader::open(file)?; let config = StreamConfig { - channels: reader.streaminfo().channels, - bits_per_sample: Bps::new(reader.streaminfo().bits_per_sample)?, - sample_rate: reader.streaminfo().sample_rate, - total_samples_estimate: reader.streaminfo().samples.unwrap(), + channels: u32::try_from(params.channels.as_ref().unwrap().count()).unwrap(), + bits_per_sample: Bps::new(params.bits_per_sample.unwrap())?, + sample_rate: params.sample_rate.unwrap(), }; - let tempname = format!("{}.{}", file.display(), "tmp"); + let tempname = format!("{}.tmp", file.display()); let mut outf = File::create(&tempname)?; let mut outw = WriteWrapper(&mut outf); @@ -125,7 +83,6 @@ pub fn encode_file(file: &std::path::Path) -> Result<()> { .channels(config.channels) .bits_per_sample(config.bits_per_sample.value()) .sample_rate(config.sample_rate) - .total_samples_estimate(config.total_samples_estimate) .compression_level(8) .verify(false) .init_write(&mut outw) @@ -133,12 +90,63 @@ pub fn encode_file(file: &std::path::Path) -> Result<()> { let mut hasher = Md5::new(); - match config.bits_per_sample { - Bps::_16 => process_samples_i16(&mut hasher, reader, &mut enc, &config)?, - Bps::_24 => process_samples_i24(&mut hasher, reader, &mut enc, &config)?, - /* Bps::_32 => process_samples_i32(&mut hasher, reader, &mut enc, &config)?, */ - Bps::_32 => unimplemented!("32bit flac isnt supported by claxon") - }; + let mut sample_buf: Vec<i32> = Vec::new(); + + loop { + let packet = match format.next_packet() { + Ok(Some(packet)) => packet, + Ok(None) => break, + Err(error) => return Err(error.into()), + }; + + if packet.track_id() != track_id { + continue; + } + + match decoder.decode(&packet) { + Ok(audio_buf) => match audio_buf { + GenericAudioBufferRef::S32(buf) => { + match config.bits_per_sample { + Bps::_16 => { + let _ = buf + .iter_interleaved() + .map(|sample| { + let real_sample = + sample >> (32 - config.bits_per_sample.value()); + hasher + .update(i16::try_from(real_sample).unwrap().to_le_bytes()); + sample_buf.push(real_sample); + }) + .collect::<Vec<_>>(); + } + Bps::_24 => { + let _ = buf + .iter_interleaved() + .map(|sample| { + let real_sample = + sample >> (32 - config.bits_per_sample.value()); + hasher.update( + i24::try_from_i32(real_sample).unwrap().to_le_bytes(), + ); + sample_buf.push(real_sample); + }) + .collect::<Vec<_>>(); + } + Bps::_32 => return Err(anyhow!("how did you get here")), + } + + enc.process_interleaved( + sample_buf.as_slice(), + u32::try_from(buf.samples_planar()).unwrap(), + ) + .unwrap(); + sample_buf.clear(); + } + _ => return Err(anyhow!("unsupported codec")), + }, + Err(err) => return Err(err.into()), + } + } if let Err(enc) = enc.finish() { return Err(anyhow!("Encoding failed:\t{:?}", enc.state())); diff --git a/src/main.rs b/src/main.rs index 4c3ba1b..5e4657e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,11 @@ mod flac; fn main() { - todo!() + let start = std::time::Instant::now(); + if let Err(err) = flac::encode_file(std::path::Path::new("16bit.flac")) { + println!("{}", err) + }; + println!("{}", start.elapsed().as_secs()) } #[cfg(test)] |
