use std::{
ffi::CString,
os::raw::{c_char, c_int, c_void},
ptr,
};
use crate::{codec::CodecParameters, packet::Packet, time::TimeBase, Error};
extern "C" {
fn ffw_bsf_new(name: *const c_char, context: *mut *mut c_void) -> c_int;
fn ffw_bsf_set_input_codec_parameters(context: *mut c_void, params: *const c_void) -> c_int;
fn ffw_bsf_set_output_codec_parameters(context: *mut c_void, params: *const c_void) -> c_int;
fn ffw_bsf_init(
context: *mut c_void,
itb_num: u32,
itb_den: u32,
otb_num: u32,
otb_den: u32,
) -> c_int;
fn ffw_bsf_push(context: *mut c_void, packet: *mut c_void) -> c_int;
fn ffw_bsf_flush(context: *mut c_void) -> c_int;
fn ffw_bsf_take(context: *mut c_void, packet: *mut *mut c_void) -> c_int;
fn ffw_bsf_free(context: *mut c_void);
}
pub struct BitstreamFilterBuilder {
ptr: *mut c_void,
input_time_base: TimeBase,
output_time_base: TimeBase,
}
impl BitstreamFilterBuilder {
fn new(name: &str) -> Result<Self, Error> {
let name = CString::new(name).expect("invalid bitstream filter name");
let mut ptr = ptr::null_mut();
let ret = unsafe { ffw_bsf_new(name.as_ptr() as _, &mut ptr) };
if ret < 0 {
return Err(Error::from_raw_error_code(ret));
} else if ptr.is_null() {
panic!("unable to allocate a bitstream filter");
}
let res = BitstreamFilterBuilder {
ptr,
input_time_base: TimeBase::MICROSECONDS,
output_time_base: TimeBase::MICROSECONDS,
};
Ok(res)
}
pub fn input_time_base(mut self, time_base: TimeBase) -> Self {
self.input_time_base = time_base;
self
}
pub fn input_codec_parameters(self, codec_parameters: &CodecParameters) -> Self {
let ret =
unsafe { ffw_bsf_set_input_codec_parameters(self.ptr, codec_parameters.as_ptr()) };
if ret < 0 {
panic!("unable to set input codec parameters");
}
self
}
pub fn output_time_base(mut self, time_base: TimeBase) -> Self {
self.output_time_base = time_base;
self
}
pub fn output_codec_parameters(self, codec_parameters: &CodecParameters) -> Self {
let ret =
unsafe { ffw_bsf_set_output_codec_parameters(self.ptr, codec_parameters.as_ptr()) };
if ret < 0 {
panic!("unable to set output codec parameters");
}
self
}
pub fn build(mut self) -> Result<BitstreamFilter, Error> {
let ret = unsafe {
ffw_bsf_init(
self.ptr,
self.input_time_base.num(),
self.input_time_base.den(),
self.output_time_base.num(),
self.output_time_base.den(),
)
};
if ret < 0 {
return Err(Error::from_raw_error_code(ret));
}
let ptr = self.ptr;
self.ptr = ptr::null_mut();
let res = BitstreamFilter {
ptr,
output_time_base: self.output_time_base,
};
Ok(res)
}
}
impl Drop for BitstreamFilterBuilder {
fn drop(&mut self) {
unsafe { ffw_bsf_free(self.ptr) }
}
}
unsafe impl Send for BitstreamFilterBuilder {}
unsafe impl Sync for BitstreamFilterBuilder {}
pub struct BitstreamFilter {
ptr: *mut c_void,
output_time_base: TimeBase,
}
impl BitstreamFilter {
pub fn builder(name: &str) -> Result<BitstreamFilterBuilder, Error> {
BitstreamFilterBuilder::new(name)
}
pub fn push(&mut self, mut packet: Packet) -> Result<(), Error> {
let ret = unsafe { ffw_bsf_push(self.ptr, packet.as_mut_ptr()) };
if ret < 0 {
return Err(Error::from_raw_error_code(ret));
}
Ok(())
}
pub fn flush(&mut self) -> Result<(), Error> {
let ret = unsafe { ffw_bsf_flush(self.ptr) };
if ret < 0 {
return Err(Error::from_raw_error_code(ret));
}
Ok(())
}
pub fn take(&mut self) -> Result<Option<Packet>, Error> {
let mut pptr = ptr::null_mut();
unsafe {
let ret = ffw_bsf_take(self.ptr, &mut pptr);
if ret == crate::ffw_error_again() || ret == crate::ffw_error_eof() {
Ok(None)
} else if ret < 0 {
Err(Error::from_raw_error_code(ret))
} else if pptr.is_null() {
panic!("unable to allocate a packet");
} else {
Ok(Some(Packet::from_raw_ptr(pptr, self.output_time_base)))
}
}
}
}
impl Drop for BitstreamFilter {
fn drop(&mut self) {
unsafe { ffw_bsf_free(self.ptr) }
}
}
unsafe impl Send for BitstreamFilter {}
unsafe impl Sync for BitstreamFilter {}