use std::{
ffi::{CStr, CString},
fmt::{self, Display, Formatter},
ptr,
str::FromStr,
};
use libc::{c_char, c_int, c_void};
use crate::time::{TimeBase, Timestamp};
extern "C" {
fn ffw_get_channel_layout_by_name(name: *const c_char) -> u64;
fn ffw_get_channel_layout_channels(layout: u64) -> c_int;
fn ffw_get_default_channel_layout(channels: c_int) -> u64;
fn ffw_get_sample_format_by_name(name: *const c_char) -> c_int;
fn ffw_get_sample_format_name(format: c_int) -> *const c_char;
fn ffw_sample_format_is_none(format: c_int) -> c_int;
fn ffw_frame_new_silence(
channel_layout: u64,
sample_fmt: c_int,
sample_rate: c_int,
nb_samples: c_int,
) -> *mut c_void;
fn ffw_frame_get_format(frame: *const c_void) -> c_int;
fn ffw_frame_get_nb_samples(frame: *const c_void) -> c_int;
fn ffw_frame_get_sample_rate(frame: *const c_void) -> c_int;
fn ffw_frame_get_channels(frame: *const c_void) -> c_int;
fn ffw_frame_get_channel_layout(frame: *const c_void) -> u64;
fn ffw_frame_get_pts(frame: *const c_void) -> i64;
fn ffw_frame_set_pts(frame: *mut c_void, pts: i64);
fn ffw_frame_clone(frame: *const c_void) -> *mut c_void;
fn ffw_frame_free(frame: *mut c_void);
}
#[derive(Debug, Copy, Clone)]
pub struct UnknownChannelLayout;
impl Display for UnknownChannelLayout {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
f.write_str("unknown channel layout")
}
}
impl std::error::Error for UnknownChannelLayout {}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct ChannelLayout(u64);
impl ChannelLayout {
pub(crate) fn from_raw(v: u64) -> Self {
Self(v)
}
pub(crate) fn into_raw(self) -> u64 {
let Self(layout) = self;
layout
}
pub fn from_channels(channels: u32) -> Option<Self> {
let layout = unsafe { ffw_get_default_channel_layout(channels as _) };
if layout == 0 {
None
} else {
Some(Self(layout))
}
}
pub fn channels(self) -> u32 {
unsafe { ffw_get_channel_layout_channels(self.into_raw()) as _ }
}
}
impl FromStr for ChannelLayout {
type Err = UnknownChannelLayout;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let name = CString::new(s).expect("invalid channel layout name");
let layout = unsafe { ffw_get_channel_layout_by_name(name.as_ptr() as _) };
if layout == 0 {
Err(UnknownChannelLayout)
} else {
Ok(Self(layout))
}
}
}
pub fn get_channel_layout(name: &str) -> ChannelLayout {
ChannelLayout::from_str(name).unwrap()
}
#[derive(Debug, Copy, Clone)]
pub struct UnknownSampleFormat;
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct SampleFormat(c_int);
impl SampleFormat {
pub(crate) fn from_raw(v: c_int) -> Self {
Self(v)
}
pub(crate) fn into_raw(self) -> c_int {
let Self(format) = self;
format
}
pub fn name(self) -> &'static str {
unsafe {
let ptr = ffw_get_sample_format_name(self.into_raw());
if ptr.is_null() {
panic!("invalid sample format");
}
let name = CStr::from_ptr(ptr as _);
name.to_str().unwrap()
}
}
}
impl FromStr for SampleFormat {
type Err = UnknownSampleFormat;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let name = CString::new(s).expect("invalid sample format name");
unsafe {
let format = ffw_get_sample_format_by_name(name.as_ptr() as _);
if ffw_sample_format_is_none(format) == 0 {
Ok(Self(format))
} else {
Err(UnknownSampleFormat)
}
}
}
}
pub fn get_sample_format(name: &str) -> SampleFormat {
SampleFormat::from_str(name).unwrap()
}
pub struct AudioFrameMut {
ptr: *mut c_void,
time_base: TimeBase,
}
impl AudioFrameMut {
pub fn silence(
channel_layout: ChannelLayout,
sample_format: SampleFormat,
sample_rate: u32,
samples: usize,
) -> Self {
let ptr = unsafe {
ffw_frame_new_silence(
channel_layout.into_raw(),
sample_format.into_raw(),
sample_rate as _,
samples as _,
)
};
if ptr.is_null() {
panic!("unable to allocate an audio frame");
}
Self {
ptr,
time_base: TimeBase::MICROSECONDS,
}
}
pub fn sample_format(&self) -> SampleFormat {
unsafe { SampleFormat::from_raw(ffw_frame_get_format(self.ptr)) }
}
pub fn sample_rate(&self) -> u32 {
unsafe { ffw_frame_get_sample_rate(self.ptr) as _ }
}
pub fn samples(&self) -> usize {
unsafe { ffw_frame_get_nb_samples(self.ptr) as _ }
}
pub fn channels(&self) -> u32 {
unsafe { ffw_frame_get_channels(self.ptr) as _ }
}
pub fn channel_layout(&self) -> ChannelLayout {
unsafe { ChannelLayout::from_raw(ffw_frame_get_channel_layout(self.ptr)) }
}
pub fn time_base(&self) -> TimeBase {
self.time_base
}
pub fn with_time_base(mut self, time_base: TimeBase) -> Self {
let new_pts = self.pts().with_time_base(time_base);
unsafe {
ffw_frame_set_pts(self.ptr, new_pts.timestamp());
}
self.time_base = time_base;
self
}
pub fn pts(&self) -> Timestamp {
let pts = unsafe { ffw_frame_get_pts(self.ptr) };
Timestamp::new(pts, self.time_base)
}
pub fn with_pts(self, pts: Timestamp) -> Self {
let pts = pts.with_time_base(self.time_base);
unsafe { ffw_frame_set_pts(self.ptr, pts.timestamp()) }
self
}
pub fn freeze(mut self) -> AudioFrame {
let ptr = self.ptr;
self.ptr = ptr::null_mut();
AudioFrame {
ptr,
time_base: self.time_base,
}
}
}
impl Drop for AudioFrameMut {
fn drop(&mut self) {
unsafe { ffw_frame_free(self.ptr) }
}
}
unsafe impl Send for AudioFrameMut {}
unsafe impl Sync for AudioFrameMut {}
pub struct AudioFrame {
ptr: *mut c_void,
time_base: TimeBase,
}
impl AudioFrame {
pub(crate) unsafe fn from_raw_ptr(ptr: *mut c_void, time_base: TimeBase) -> Self {
AudioFrame { ptr, time_base }
}
pub fn sample_format(&self) -> SampleFormat {
unsafe { SampleFormat::from_raw(ffw_frame_get_format(self.ptr)) }
}
pub fn sample_rate(&self) -> u32 {
unsafe { ffw_frame_get_sample_rate(self.ptr) as _ }
}
pub fn samples(&self) -> usize {
unsafe { ffw_frame_get_nb_samples(self.ptr) as _ }
}
pub fn channels(&self) -> u32 {
unsafe { ffw_frame_get_channels(self.ptr) as _ }
}
pub fn channel_layout(&self) -> ChannelLayout {
unsafe { ChannelLayout::from_raw(ffw_frame_get_channel_layout(self.ptr)) }
}
pub fn time_base(&self) -> TimeBase {
self.time_base
}
pub fn with_time_base(mut self, time_base: TimeBase) -> Self {
let new_pts = self.pts().with_time_base(time_base);
unsafe {
ffw_frame_set_pts(self.ptr, new_pts.timestamp());
}
self.time_base = time_base;
self
}
pub fn pts(&self) -> Timestamp {
let pts = unsafe { ffw_frame_get_pts(self.ptr) };
Timestamp::new(pts, self.time_base)
}
pub fn with_pts(self, pts: Timestamp) -> Self {
let pts = pts.with_time_base(self.time_base);
unsafe { ffw_frame_set_pts(self.ptr, pts.timestamp()) }
self
}
pub(crate) fn as_ptr(&self) -> *const c_void {
self.ptr
}
}
impl Clone for AudioFrame {
fn clone(&self) -> Self {
let ptr = unsafe { ffw_frame_clone(self.ptr) };
if ptr.is_null() {
panic!("unable to clone a frame");
}
Self {
ptr,
time_base: self.time_base,
}
}
}
impl Drop for AudioFrame {
fn drop(&mut self) {
unsafe { ffw_frame_free(self.ptr) }
}
}
unsafe impl Send for AudioFrame {}
unsafe impl Sync for AudioFrame {}