From 715b53059b73d762348b8c1f54d9aa5f65f5262f Mon Sep 17 00:00:00 2001 From: jakka Date: Wed, 25 Jun 2025 00:54:46 +0300 Subject: started working on my own libflac decoder --- src/flac/decoder.rs | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 src/flac/decoder.rs (limited to 'src/flac/decoder.rs') diff --git a/src/flac/decoder.rs b/src/flac/decoder.rs new file mode 100644 index 0000000..99ac36e --- /dev/null +++ b/src/flac/decoder.rs @@ -0,0 +1,139 @@ +use std::{ + error::Error, + ffi::{CString, c_void}, + fmt::Display, + path::Path, +}; + +use libflac_sys::{ + FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED, + FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE, + FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS, + FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR, FLAC__STREAM_DECODER_INIT_STATUS_OK, + FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER, FLAC__StreamDecoder, + FLAC__StreamDecoderInitStatus, FLAC__bool, FLAC__stream_decoder_finish, + FLAC__stream_decoder_get_bits_per_sample, FLAC__stream_decoder_get_channels, + FLAC__stream_decoder_get_sample_rate, FLAC__stream_decoder_init_file, FLAC__stream_decoder_new, + FLAC__stream_decoder_process_single, FLAC__stream_decoder_set_md5_checking, +}; + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(u32)] +pub enum FlacDecoderInitError { + AlreadyInitialized = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED, + + ErrorOpeningFile = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE, + + InvalidCallbacks = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS, + + MemoryAllocationError = FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR, + + UnsupportedContainer = FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER, +} + +impl Error for FlacDecoderInitError {} + +impl Display for FlacDecoderInitError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +impl From for FLAC__StreamDecoderInitStatus { + fn from(val: FlacDecoderInitError) -> Self { + val as FLAC__StreamDecoderInitStatus + } +} + +impl TryFrom for FlacDecoderInitError { + type Error = (); + + #[allow(non_upper_case_globals)] + fn try_from(raw: FLAC__StreamDecoderInitStatus) -> Result { + Ok(match raw { + FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED => { + FlacDecoderInitError::AlreadyInitialized + } + FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE => { + FlacDecoderInitError::ErrorOpeningFile + } + FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS => { + FlacDecoderInitError::InvalidCallbacks + } + FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR => { + FlacDecoderInitError::MemoryAllocationError + } + FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER => { + FlacDecoderInitError::UnsupportedContainer + } + _ => return Err(()), + }) + } +} + +fn convert_path(path: &Path) -> CString { + CString::new(path.to_str().expect("non-UTF-8 filename")).expect("filename has internal NULs") +} + +pub(crate) struct FlacDecoder(pub *mut FLAC__StreamDecoder); + +impl FlacDecoder { + pub(crate) fn new() -> Self { + FlacDecoder(unsafe { FLAC__stream_decoder_new() }) + } + + pub(crate) fn init_decode_from_file>( + &self, + file: &P, + buf: &mut Vec, + ) -> Result<(), FlacDecoderInitError> { + unsafe { + FLAC__stream_decoder_set_md5_checking(self.0, true as FLAC__bool); + } + + let filename = convert_path(file.as_ref()); + unsafe { + let result: FLAC__StreamDecoderInitStatus = FLAC__stream_decoder_init_file( + self.0, + filename.as_ptr(), + None, + None, + None, + buf.as_mut_ptr() as *mut c_void, + ); + if result != FLAC__STREAM_DECODER_INIT_STATUS_OK { + return Err(FlacDecoderInitError::try_from(result).unwrap()); + } + } + + Ok(()) + } + + pub(crate) fn decode_frame(&self) -> Result<(), ()> { + if unsafe { FLAC__stream_decoder_process_single(self.0) } != 0 { + Ok(()) + } else { + Err(()) + } + } + + pub(crate) fn get_channels(&self) -> u32 { + unsafe { FLAC__stream_decoder_get_channels(self.0) } + } + + pub(crate) fn get_bps(&self) -> u32 { + unsafe { FLAC__stream_decoder_get_bits_per_sample(self.0) } + } + + pub(crate) fn get_samplerate(&self) -> u32 { + unsafe { FLAC__stream_decoder_get_sample_rate(self.0) } + } +} + +impl Drop for FlacDecoder { + fn drop(&mut self) { + if !(self.0.is_null()) { + unsafe { FLAC__stream_decoder_finish(self.0) }; + } + } +} -- cgit v1.3.1