use std::marker::PhantomData;
use crate::error::{check, null_handle_error, to_cstring, Result};
use crate::ffi;
use crate::metadata::Metadata;
use crate::options::StreamOptions;
use crate::samples::OwnedSamples;
pub struct Frame<'a> {
channels: Vec<&'a [f32]>,
}
impl<'a> Frame<'a> {
pub fn num_channels(&self) -> usize {
self.channels.len()
}
pub fn num_samples(&self) -> usize {
self.channels.first().map_or(0, |c| c.len())
}
pub fn channel(&self, channel: usize) -> Option<&'a [f32]> {
self.channels.get(channel).copied()
}
pub fn channels(&self) -> &[&'a [f32]] {
&self.channels
}
pub fn to_vecs(&self) -> Vec<Vec<f32>> {
self.channels.iter().map(|c| c.to_vec()).collect()
}
}
impl std::fmt::Debug for Frame<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Frame")
.field("num_channels", &self.num_channels())
.field("num_samples", &self.num_samples())
.finish()
}
}
pub struct AudioDecoder {
handle: *mut ffi::AvfDecoder,
_not_sync: PhantomData<std::cell::Cell<()>>,
}
impl AudioDecoder {
pub fn new(options: &StreamOptions) -> Result<Self> {
let (raw, _format) = options.to_ffi()?;
let handle = unsafe { ffi::avf_decoder_new(&raw) };
if handle.is_null() {
return Err(null_handle_error());
}
Ok(Self {
handle,
_not_sync: PhantomData,
})
}
pub fn load_file(&mut self, source: &str) -> Result<Metadata> {
let source = to_cstring(source)?;
let mut raw = ffi::AvfMetadata::default();
check(unsafe { ffi::avf_decoder_load_file(self.handle, source.as_ptr(), &mut raw) })?;
Ok(Metadata::from_ffi(&raw))
}
pub fn load_buffer(&mut self, data: &[u8]) -> Result<Metadata> {
let mut raw = ffi::AvfMetadata::default();
check(unsafe {
ffi::avf_decoder_load_buffer(self.handle, data.as_ptr(), data.len(), &mut raw)
})?;
Ok(Metadata::from_ffi(&raw))
}
pub fn feed(&mut self, data: &[u8]) -> Result<()> {
check(unsafe { ffi::avf_decoder_feed(self.handle, data.as_ptr(), data.len()) })
}
pub fn flush(&mut self) -> Result<()> {
check(unsafe { ffi::avf_decoder_flush(self.handle) })
}
pub fn get_frame(&mut self) -> Result<Option<Frame<'_>>> {
let mut raw = ffi::AvfFrame::default();
check(unsafe { ffi::avf_decoder_get_frame(self.handle, &mut raw) })?;
if raw.data.is_null() || raw.num_samples <= 0 || raw.num_channels <= 0 {
return Ok(None);
}
let channels = unsafe {
let pointers = std::slice::from_raw_parts(raw.data, raw.num_channels as usize);
pointers
.iter()
.map(|&p| std::slice::from_raw_parts(p, raw.num_samples as usize))
.collect()
};
Ok(Some(Frame { channels }))
}
pub fn get_samples(&mut self) -> Result<Vec<Vec<f32>>> {
self.get_samples_range(0.0, None)
}
pub fn get_samples_range(
&mut self,
start_seconds: f64,
stop_seconds: Option<f64>,
) -> Result<Vec<Vec<f32>>> {
let owned = OwnedSamples::from_call(|out| {
unsafe {
ffi::avf_decoder_get_samples(
self.handle,
start_seconds,
stop_seconds.unwrap_or(0.0),
i32::from(stop_seconds.is_some()),
out,
)
}
})?;
Ok(owned.to_vecs())
}
pub fn is_finished(&self) -> Result<bool> {
let mut finished = 0;
check(unsafe { ffi::avf_decoder_is_finished(self.handle, &mut finished) })?;
Ok(finished != 0)
}
pub fn metadata(&self) -> Result<Metadata> {
let mut raw = ffi::AvfMetadata::default();
check(unsafe { ffi::avf_decoder_get_metadata(self.handle, &mut raw) })?;
Ok(Metadata::from_ffi(&raw))
}
}
impl std::fmt::Debug for AudioDecoder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioDecoder")
.field("metadata", &self.metadata().ok())
.field("finished", &self.is_finished().ok())
.finish()
}
}
impl Drop for AudioDecoder {
fn drop(&mut self) {
unsafe { ffi::avf_decoder_free(self.handle) };
}
}
unsafe impl Send for AudioDecoder {}