summaryrefslogtreecommitdiff
path: root/src/flac/decoder.rs
diff options
context:
space:
mode:
authorjakka <jakkadoujin@gmail.com>2025-06-25 00:54:46 +0300
committerjakka <jakkadoujin@gmail.com>2025-06-25 00:54:46 +0300
commit715b53059b73d762348b8c1f54d9aa5f65f5262f (patch)
tree61700cd7aacfc56a464e3aa022c40d9d0a2b22ed /src/flac/decoder.rs
parent014b75b04e15a8e2e1609ae25cbe393e4e8dbb1d (diff)
started working on my own libflac decoder
Diffstat (limited to 'src/flac/decoder.rs')
-rw-r--r--src/flac/decoder.rs139
1 files changed, 139 insertions, 0 deletions
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<FlacDecoderInitError> for FLAC__StreamDecoderInitStatus {
+ fn from(val: FlacDecoderInitError) -> Self {
+ val as FLAC__StreamDecoderInitStatus
+ }
+}
+
+impl TryFrom<FLAC__StreamDecoderInitStatus> for FlacDecoderInitError {
+ type Error = ();
+
+ #[allow(non_upper_case_globals)]
+ fn try_from(raw: FLAC__StreamDecoderInitStatus) -> Result<FlacDecoderInitError, ()> {
+ 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<P: AsRef<Path>>(
+ &self,
+ file: &P,
+ buf: &mut Vec<i32>,
+ ) -> 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) };
+ }
+ }
+}