use std::ptr;
use super::Delay;
use crate::{ChannelLayout, Dictionary, Error, ffi::*, frame, util::format};
use libc::c_int;
use std::ffi::c_void;
#[derive(Eq, PartialEq, Copy, Clone)]
pub struct Definition {
pub format: format::Sample,
pub channel_layout: ChannelLayout,
pub rate: u32,
}
pub struct Context {
ptr: *mut SwrContext,
input: Definition,
output: Definition,
}
unsafe impl Send for Context {}
impl Context {
#[doc(hidden)]
pub unsafe fn as_ptr(&self) -> *const SwrContext {
self.ptr as *const _
}
#[doc(hidden)]
pub unsafe fn as_mut_ptr(&mut self) -> *mut SwrContext {
self.ptr
}
}
impl Context {
pub fn get(src_format: format::Sample, src_channel_layout: ChannelLayout, src_rate: u32, dst_format: format::Sample, dst_channel_layout: ChannelLayout, dst_rate: u32) -> Result<Self, Error> {
Self::get_with(src_format, src_channel_layout, src_rate, dst_format, dst_channel_layout, dst_rate, Dictionary::new())
}
pub fn get_with(src_format: format::Sample, src_channel_layout: ChannelLayout, src_rate: u32, dst_format: format::Sample, dst_channel_layout: ChannelLayout, dst_rate: u32, options: Dictionary) -> Result<Self, Error> {
unsafe {
#[allow(unused_assignments)]
let mut ptr = std::ptr::null_mut();
#[cfg(not(feature = "ffmpeg_7_0"))]
{
ptr = swr_alloc_set_opts(ptr::null_mut(), dst_channel_layout.bits() as i64, dst_format.into(), dst_rate as c_int, src_channel_layout.bits() as i64, src_format.into(), src_rate as c_int, 0, ptr::null_mut());
}
#[cfg(feature = "ffmpeg_7_0")]
{
let e = swr_alloc_set_opts2(&mut ptr, &dst_channel_layout.into(), dst_format.into(), dst_rate as c_int, &src_channel_layout.into(), src_format.into(), src_rate as c_int, 0, ptr::null_mut());
if e != 0 {
return Err(Error::from(e));
}
}
let mut opts = options.disown();
let res = av_opt_set_dict(ptr as *mut c_void, &mut opts);
Dictionary::own(opts);
if res != 0 {
return Err(Error::from(res));
}
if !ptr.is_null() {
match swr_init(ptr) {
e if e < 0 => Err(Error::from(e)),
_ => Ok(Context { ptr, input: Definition { format: src_format, channel_layout: src_channel_layout, rate: src_rate }, output: Definition { format: dst_format, channel_layout: dst_channel_layout, rate: dst_rate } }),
}
} else {
Err(Error::InvalidData)
}
}
}
pub fn input(&self) -> &Definition {
&self.input
}
pub fn output(&self) -> &Definition {
&self.output
}
pub fn delay(&self) -> Option<Delay> {
unsafe {
match swr_get_delay(self.as_ptr() as *mut _, 1) {
0 => None,
_ => Some(Delay::from(self)),
}
}
}
pub fn run(&mut self, input: &frame::Audio, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
unsafe {
(*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
}
unsafe {
if output.is_empty() {
output.alloc(self.output.format, input.samples(), self.output.channel_layout);
}
match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), input.as_ptr()) {
0 => Ok(self.delay()),
e => Err(Error::from(e)),
}
}
}
pub fn flush(&mut self, output: &mut frame::Audio) -> Result<Option<Delay>, Error> {
unsafe {
(*output.as_mut_ptr()).sample_rate = self.output.rate as i32;
}
unsafe {
match swr_convert_frame(self.as_mut_ptr(), output.as_mut_ptr(), ptr::null()) {
0 => Ok(self.delay()),
e => Err(Error::from(e)),
}
}
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
swr_free(&mut self.as_mut_ptr());
}
}
}