use std::{
ffi::CString,
os::raw::{c_char, c_int, c_void},
};
use crate::{
codec::CodecParameters,
time::{TimeBase, Timestamp},
};
extern "C" {
fn ffw_stream_get_time_base(stream: *const c_void, num: *mut u32, den: *mut u32);
fn ffw_stream_set_time_base(stream: *mut c_void, num: u32, den: u32);
fn ffw_stream_get_start_time(stream: *const c_void) -> i64;
fn ffw_stream_get_duration(stream: *const c_void) -> i64;
fn ffw_stream_get_nb_frames(stream: *const c_void) -> i64;
fn ffw_stream_get_codec_parameters(stream: *const c_void) -> *mut c_void;
fn ffw_stream_get_id(stream: *const c_void) -> c_int;
fn ffw_stream_set_metadata(
stream: *mut c_void,
key: *const c_char,
value: *const c_char,
) -> c_int;
fn ffw_stream_set_id(stream: *mut c_void, id: c_int);
}
pub struct Stream {
ptr: *mut c_void,
time_base: TimeBase,
}
impl Stream {
pub(crate) unsafe fn from_raw_ptr(ptr: *mut c_void) -> Self {
let mut num = 0_u32;
let mut den = 0_u32;
ffw_stream_get_time_base(ptr, &mut num, &mut den);
Stream {
ptr,
time_base: TimeBase::new(num, den),
}
}
pub fn time_base(&self) -> TimeBase {
self.time_base
}
pub fn set_time_base(&mut self, time_base: TimeBase) {
self.time_base = time_base;
unsafe {
ffw_stream_set_time_base(self.ptr, self.time_base.num(), self.time_base.den());
}
}
pub fn start_time(&self) -> Timestamp {
let pts = unsafe { ffw_stream_get_start_time(self.ptr) as _ };
Timestamp::new(pts, self.time_base)
}
pub fn duration(&self) -> Timestamp {
let pts = unsafe { ffw_stream_get_duration(self.ptr) as _ };
Timestamp::new(pts, self.time_base)
}
pub fn frames(&self) -> Option<u64> {
let count = unsafe { ffw_stream_get_nb_frames(self.ptr) };
if count <= 0 {
None
} else {
Some(count as _)
}
}
pub fn codec_parameters(&self) -> CodecParameters {
unsafe {
let ptr = ffw_stream_get_codec_parameters(self.ptr);
if ptr.is_null() {
panic!("unable to allocate codec parameters");
}
CodecParameters::from_raw_ptr(ptr)
}
}
pub fn stream_id(&self) -> i32 {
unsafe { ffw_stream_get_id(self.ptr) as i32 }
}
pub fn set_metadata<V>(&mut self, key: &str, value: V)
where
V: ToString,
{
let key = CString::new(key).expect("invalid metadata key");
let value = CString::new(value.to_string()).expect("invalid metadata value");
let ret = unsafe { ffw_stream_set_metadata(self.ptr, key.as_ptr(), value.as_ptr()) };
if ret < 0 {
panic!("unable to allocate metadata");
}
}
pub fn set_stream_id(&mut self, id: i32) {
unsafe { ffw_stream_set_id(self.ptr, id as c_int) };
}
}
unsafe impl Send for Stream {}
unsafe impl Sync for Stream {}