use crate::{ffi, shared::*};
use std::{
ffi::CStr,
num::NonZeroI32,
ptr::{self, NonNull},
};
pub use ffi::AVSampleFormat;
pub fn get_sample_fmt_name(sample_fmt: AVSampleFormat) -> Option<&'static CStr> {
unsafe {
ffi::av_get_sample_fmt_name(sample_fmt)
.upgrade()
.map(|x| CStr::from_ptr(x.as_ptr()))
}
}
pub fn get_sample_fmt(name: &CStr) -> Option<AVSampleFormat> {
let sample_fmt = unsafe { ffi::av_get_sample_fmt(name.as_ptr()) };
match sample_fmt {
ffi::AV_SAMPLE_FMT_NONE => None,
_ => Some(sample_fmt),
}
}
pub fn get_packed_sample_fmt(sample_fmt: AVSampleFormat) -> Option<AVSampleFormat> {
let sample_fmt = unsafe { ffi::av_get_packed_sample_fmt(sample_fmt) };
match sample_fmt {
ffi::AV_SAMPLE_FMT_NONE => None,
_ => Some(sample_fmt),
}
}
pub fn get_planar_sample_fmt(sample_fmt: AVSampleFormat) -> Option<AVSampleFormat> {
let sample_fmt = unsafe { ffi::av_get_planar_sample_fmt(sample_fmt) };
match sample_fmt {
ffi::AV_SAMPLE_FMT_NONE => None,
_ => Some(sample_fmt),
}
}
pub fn get_bytes_per_sample(sample_fmt: AVSampleFormat) -> Option<usize> {
NonZeroI32::new(unsafe { ffi::av_get_bytes_per_sample(sample_fmt) })
.map(NonZeroI32::get)
.and_then(|x| x.try_into().ok())
}
pub fn sample_fmt_is_planar(sample_fmt: AVSampleFormat) -> bool {
unsafe { ffi::av_sample_fmt_is_planar(sample_fmt) == 1 }
}
wrap! {
AVSamples: Box<[u8]>,
audio_data: Box<[*mut u8]> = Vec::new().into_boxed_slice(),
linesize: i32 = 0,
nb_channels: i32 = 0,
nb_samples: i32 = 0,
sample_fmt: AVSampleFormat = ffi::AV_SAMPLE_FMT_NONE,
align: i32 = 0,
}
impl AVSamples {
pub fn get_buffer_size(
nb_channels: i32,
nb_samples: i32,
sample_fmt: i32,
align: i32,
) -> Option<(i32, i32)> {
let mut linesize = 0;
unsafe {
ffi::av_samples_get_buffer_size(
&mut linesize,
nb_channels,
nb_samples,
sample_fmt,
align,
)
}
.upgrade()
.ok()
.map(|buffer_size| (linesize, buffer_size))
}
pub fn new(
nb_channels: i32,
nb_samples: i32,
sample_fmt: AVSampleFormat,
align: i32,
) -> Option<Self> {
let (_, buffer_size) =
AVSamples::get_buffer_size(nb_channels, nb_samples, sample_fmt, align)?;
let buffer = vec![0u8; buffer_size as usize].into_boxed_slice();
let nb_planes = if sample_fmt_is_planar(sample_fmt) {
nb_channels
} else {
1
};
let mut audio_data = vec![ptr::null_mut(); nb_planes as usize].into_boxed_slice();
let mut linesize = 0;
unsafe {
ffi::av_samples_fill_arrays(
audio_data.as_mut_ptr(),
&mut linesize,
buffer.as_ptr(),
nb_channels,
nb_samples,
sample_fmt,
align,
)
}
.upgrade()
.unwrap();
let buffer = Box::leak(Box::new(buffer));
let mut samples = unsafe { AVSamples::from_raw(NonNull::new(buffer).unwrap()) };
samples.audio_data = audio_data;
samples.linesize = linesize;
samples.nb_channels = nb_channels;
samples.nb_samples = nb_samples;
samples.sample_fmt = sample_fmt;
samples.align = align;
Some(samples)
}
pub fn set_silence(&mut self, offset: i32, nb_samples: i32) {
let x = unsafe {
ffi::av_samples_set_silence(
self.audio_data.as_mut_ptr(),
offset,
nb_samples,
self.nb_channels,
self.sample_fmt,
)
};
debug_assert!(x == 0);
}
}
impl Drop for AVSamples {
fn drop(&mut self) {
let _linear = unsafe { Box::from_raw(self.as_mut_ptr()) };
}
}