6 releases
Uses new Rust 2024
new 0.0.6 | Apr 28, 2025 |
---|---|
0.0.5 | Apr 28, 2025 |
#335 in Audio
48 downloads per month
120KB
2K
SLoC
flac-rs
A rust wrap for libflac-sys
Usage
Both FlacEncoder
and FlacDecoder
need a bunch of closures to call during encoding or decoding.
These closures need you to implement as they should behave to function.
Each closure should be put into a box to pass it to the new()
method of FlacEncoder
and FlacDecoder
.
After creating FlacEncoder
, you can call insert_comments()
, insert_cue_track()
, and add_picture()
to add metadata to the FLAC file.
Then you should call initialize()
, after this, you can write samples to let it encode for you.
For FlacDecoder
, if you want to retrieve the metadata, you have to decode the whole FLAC file, then the metadata is stored in the FlacDecoder
and you have functions to read them.
Just see the example code to see how to use this.
Example code
use std::{io::{self, Read, Write, Seek, SeekFrom, BufReader, BufWriter}, cmp::Ordering, fs::File};
// Open the FLAC file for decoding using the `BufReader`
type ReaderType = BufReader<File>;
let mut reader: ReaderType = BufReader::new(File::open("test.flac").unwrap());
// Retrieve the file length
let length = {
reader.seek(SeekFrom::End(0)).unwrap();
let ret = reader.stream_position().unwrap();
reader.seek(SeekFrom::Start(0)).unwrap();
ret
};
// Open the FLAC file for encoding using the `BufWriter`
type WriterType = BufWriter<File>;
let mut writer: WriterType = BufWriter::new(File::create("output.flac").unwrap());
// Prepare to get the samples
let mut pcm_frames = Vec::<Vec<i16>>::new();
// There is an encoder to save samples to another FLAC file
// But currently we don't know the source FLAC file spec (channels, sample rate, etc.)
// So we just guess it.
// Let's create the encoder now
let mut encoder = FlacEncoder::new(
&mut writer,
// on_write
Box::new(|writer: &mut WriterType, data: &[u8]| -> Result<(), io::Error> {
writer.write_all(data)
}),
// on_seek
Box::new(|writer: &mut WriterType, position: u64| -> Result<(), io::Error> {
writer.seek(SeekFrom::Start(position))?;
Ok(())
}),
// on_tell
Box::new(|writer: &mut WriterType| -> Result<u64, io::Error> {
writer.stream_position()
}),
&FlacEncoderParams {
verify_decoded: false,
compression: FlacCompression::Level8,
channels: 2,
sample_rate: 44100,
bits_per_sample: 16,
total_samples_estimate: 0
}
).unwrap();
encoder.initialize().unwrap();
// Create a decoder to decode the test file.
let mut decoder = FlacDecoder::new(
&mut reader,
// on_read
Box::new(|reader: &mut ReaderType, data: &mut [u8]| -> (usize, FlacReadStatus) {
let to_read = data.len();
match reader.read(data) {
Ok(size) => {
match size.cmp(&to_read) {
Ordering::Equal => (size, FlacReadStatus::GoOn),
Ordering::Less => (size, FlacReadStatus::Eof),
Ordering::Greater => panic!("`reader.read()` returns a size greater than the desired size."),
}
},
Err(e) => {
eprintln!("on_read(): {:?}", e);
(0, FlacReadStatus::Abort)
}
}
}),
// on_seek
Box::new(|reader: &mut ReaderType, position: u64| -> Result<(), io::Error> {
reader.seek(SeekFrom::Start(position))?;
Ok(())
}),
// on_tell
Box::new(|reader: &mut ReaderType| -> Result<u64, io::Error> {
reader.stream_position()
}),
// on_length
Box::new(|_reader: &mut ReaderType| -> Result<u64, io::Error>{
Ok(length)
}),
// on_eof
Box::new(|reader: &mut ReaderType| -> bool {
reader.stream_position().unwrap() >= length
}),
// on_write
Box::new(|samples: &[Vec<i32>], sample_info: &SamplesInfo| -> Result<(), io::Error>{
if sample_info.bits_per_sample != 16 {
panic!("The test function only tests 16-bit per sample FLAC files.")
}
let pcm_converted: Vec<Vec<i16>> = samples.iter().map(|frame: &Vec<i32>|{
frame.into_iter().map(|x32|{*x32 as i16}).collect()
}).collect();
pcm_frames.extend(pcm_converted);
// The encoder wants the `i32` for samples to be encoded so we convert the PCM samples back to `i32` format for the encoder.
let i32pcm: Vec::<Vec<i32>> = pcm_frames.iter().map(|frame: &Vec<i16>|{
frame.into_iter().map(|x16|{*x16 as i32}).collect()
}).collect();
encoder.write_frames(&i32pcm).unwrap();
pcm_frames.clear();
Ok(())
}),
// on_error
Box::new(|error: FlacInternalDecoderError| {
panic!("{error}");
}),
true, // md5_checking
false, // scale_to_i32_range
FlacAudioForm::FrameArray
).unwrap();
// Decode all the stream, calling the closures, and end the decoding process.
decoder.decode_all().unwrap();
// Calling `finalize()` will cause them to be dropped, not necessary but you can do this if you want.
decoder.finalize();
encoder.finalize();
Dependencies
~3.5MB
~71K SLoC