use std::{
ffi::CStr,
os::raw::{c_char, c_int, c_void},
ptr, slice,
time::Duration,
};
use crate::time::{TimeBase, Timestamp};
extern "C" {
fn ffw_packet_alloc() -> *mut c_void;
fn ffw_packet_new(size: c_int) -> *mut c_void;
fn ffw_packet_clone(src: *const c_void) -> *mut c_void;
fn ffw_packet_free(packet: *mut c_void);
fn ffw_packet_get_size(packet: *const c_void) -> c_int;
fn ffw_packet_get_data(packet: *mut c_void) -> *mut c_void;
fn ffw_packet_get_pts(packet: *const c_void) -> i64;
fn ffw_packet_set_pts(packet: *mut c_void, pts: i64);
fn ffw_packet_get_dts(packet: *const c_void) -> i64;
fn ffw_packet_set_dts(packet: *mut c_void, pts: i64);
fn ffw_packet_get_duration(packet: *const c_void) -> i64;
fn ffw_packet_set_duration(packet: *mut c_void, duration: i64);
fn ffw_packet_is_key(packet: *const c_void) -> c_int;
fn ffw_packet_set_key(packet: *mut c_void, key: c_int);
fn ffw_packet_get_stream_index(packet: *const c_void) -> c_int;
fn ffw_packet_set_stream_index(packet: *mut c_void, index: c_int);
fn ffw_packet_is_writable(packet: *const c_void) -> c_int;
fn ffw_packet_make_writable(packet: *mut c_void) -> c_int;
fn ffw_packet_side_data_get_size(side_data: *const c_void) -> usize;
fn ffw_packet_side_data_get_data(side_data: *const c_void) -> *const u8;
fn ffw_packet_side_data_get_type(side_data: *const c_void) -> c_int;
fn ffw_packet_get_side_data_name(side_data_type: c_int) -> *const c_char;
}
pub struct PacketMut {
ptr: *mut c_void,
time_base: TimeBase,
}
impl PacketMut {
pub fn new(size: usize) -> Self {
unsafe {
let ptr = if size == 0 {
ffw_packet_alloc()
} else {
ffw_packet_new(size as c_int)
};
if ptr.is_null() {
panic!("unable to allocate a packet");
}
Self {
ptr,
time_base: TimeBase::MICROSECONDS,
}
}
}
pub fn stream_index(&self) -> usize {
unsafe { ffw_packet_get_stream_index(self.ptr) as _ }
}
pub fn with_stream_index(self, index: usize) -> Self {
unsafe { ffw_packet_set_stream_index(self.ptr, index as _) }
self
}
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);
let new_dts = self.dts().with_time_base(time_base);
unsafe {
ffw_packet_set_pts(self.ptr, new_pts.timestamp());
ffw_packet_set_dts(self.ptr, new_dts.timestamp());
}
self.time_base = time_base;
self
}
pub fn pts(&self) -> Timestamp {
let pts = unsafe { ffw_packet_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_packet_set_pts(self.ptr, pts.timestamp()) }
self
}
pub fn with_raw_pts(self, pts: i64) -> Self {
unsafe { ffw_packet_set_pts(self.ptr, pts) }
self
}
pub fn dts(&self) -> Timestamp {
let dts = unsafe { ffw_packet_get_dts(self.ptr) };
Timestamp::new(dts, self.time_base)
}
pub fn with_dts(self, dts: Timestamp) -> Self {
let dts = dts.with_time_base(self.time_base);
unsafe { ffw_packet_set_dts(self.ptr, dts.timestamp()) }
self
}
pub fn with_raw_dts(self, dts: i64) -> Self {
unsafe { ffw_packet_set_dts(self.ptr, dts) }
self
}
pub fn duration(&self) -> Option<Duration> {
let duration = self.raw_duration();
if duration > 0 {
let z = Timestamp::new(0, self.time_base);
let d = Timestamp::new(duration, self.time_base);
Some(d - z)
} else {
None
}
}
pub fn with_duration(self, duration: Duration) -> Self {
let d = Timestamp::new(0, self.time_base) + duration;
unsafe { ffw_packet_set_duration(self.ptr, d.timestamp()) }
self
}
pub fn raw_duration(&self) -> i64 {
unsafe { ffw_packet_get_duration(self.ptr) }
}
pub fn with_raw_duration(self, duration: i64) -> Self {
unsafe { ffw_packet_set_duration(self.ptr, duration) }
self
}
pub fn is_key(&self) -> bool {
unsafe { ffw_packet_is_key(self.ptr) != 0 }
}
pub fn with_key_flag(self, key: bool) -> Self {
unsafe { ffw_packet_set_key(self.ptr, key as _) }
self
}
pub fn data(&self) -> &[u8] {
unsafe {
let data = ffw_packet_get_data(self.ptr) as *const u8;
let size = ffw_packet_get_size(self.ptr) as usize;
if data.is_null() {
&[]
} else {
slice::from_raw_parts(data, size)
}
}
}
pub fn data_mut(&mut self) -> &mut [u8] {
unsafe {
let data = ffw_packet_get_data(self.ptr) as *mut u8;
let size = ffw_packet_get_size(self.ptr) as usize;
if data.is_null() {
&mut []
} else {
slice::from_raw_parts_mut(data, size)
}
}
}
pub fn freeze(mut self) -> Packet {
let ptr = self.ptr;
self.ptr = ptr::null_mut();
Packet {
ptr,
time_base: self.time_base,
}
}
}
impl Drop for PacketMut {
fn drop(&mut self) {
unsafe { ffw_packet_free(self.ptr) }
}
}
impl<T> From<T> for PacketMut
where
T: AsRef<[u8]>,
{
fn from(data: T) -> Self {
let data = data.as_ref();
let mut packet = Self::new(data.len());
packet.data_mut().copy_from_slice(data);
packet
}
}
unsafe impl Send for PacketMut {}
unsafe impl Sync for PacketMut {}
pub struct Packet {
ptr: *mut c_void,
time_base: TimeBase,
}
impl Packet {
pub(crate) unsafe fn from_raw_ptr(ptr: *mut c_void, time_base: TimeBase) -> Self {
Packet { ptr, time_base }
}
pub fn stream_index(&self) -> usize {
unsafe { ffw_packet_get_stream_index(self.ptr) as _ }
}
pub fn with_stream_index(self, index: usize) -> Packet {
unsafe { ffw_packet_set_stream_index(self.ptr, index as _) }
self
}
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);
let new_dts = self.dts().with_time_base(time_base);
unsafe {
ffw_packet_set_pts(self.ptr, new_pts.timestamp());
ffw_packet_set_dts(self.ptr, new_dts.timestamp());
}
self.time_base = time_base;
self
}
pub fn pts(&self) -> Timestamp {
let pts = unsafe { ffw_packet_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_packet_set_pts(self.ptr, pts.timestamp()) }
self
}
pub fn with_raw_pts(self, pts: i64) -> Self {
unsafe { ffw_packet_set_pts(self.ptr, pts) }
self
}
pub fn dts(&self) -> Timestamp {
let dts = unsafe { ffw_packet_get_dts(self.ptr) };
Timestamp::new(dts, self.time_base)
}
pub fn with_dts(self, dts: Timestamp) -> Self {
let dts = dts.with_time_base(self.time_base);
unsafe { ffw_packet_set_dts(self.ptr, dts.timestamp()) }
self
}
pub fn with_raw_dts(self, dts: i64) -> Self {
unsafe { ffw_packet_set_dts(self.ptr, dts) }
self
}
pub fn duration(&self) -> Option<Duration> {
let duration = self.raw_duration();
if duration > 0 {
let z = Timestamp::new(0, self.time_base);
let d = Timestamp::new(duration, self.time_base);
Some(d - z)
} else {
None
}
}
pub fn with_duration(self, duration: Duration) -> Self {
let d = Timestamp::new(0, self.time_base) + duration;
unsafe { ffw_packet_set_duration(self.ptr, d.timestamp()) }
self
}
pub fn raw_duration(&self) -> i64 {
unsafe { ffw_packet_get_duration(self.ptr) }
}
pub fn with_raw_duration(self, duration: i64) -> Self {
unsafe { ffw_packet_set_duration(self.ptr, duration) }
self
}
pub fn is_key(&self) -> bool {
unsafe { ffw_packet_is_key(self.ptr) != 0 }
}
pub(crate) fn as_ptr(&self) -> *const c_void {
self.ptr
}
pub(crate) fn as_mut_ptr(&mut self) -> *mut c_void {
self.ptr
}
pub fn data(&self) -> &[u8] {
unsafe {
let data = ffw_packet_get_data(self.ptr) as *const u8;
let size = ffw_packet_get_size(self.ptr) as usize;
if data.is_null() {
&[]
} else {
slice::from_raw_parts(data, size)
}
}
}
pub fn try_into_mut(self) -> Result<PacketMut, Self> {
let res = unsafe { ffw_packet_is_writable(self.ptr) };
if res == 0 {
Err(self)
} else {
Ok(self.into_mut())
}
}
pub fn into_mut(mut self) -> PacketMut {
let res = unsafe { ffw_packet_make_writable(self.ptr) };
if res < 0 {
panic!("unable to make the packet mutable");
}
let ptr = self.ptr;
self.ptr = ptr::null_mut();
PacketMut {
ptr,
time_base: self.time_base,
}
}
}
impl Clone for Packet {
fn clone(&self) -> Packet {
let ptr = unsafe { ffw_packet_clone(self.ptr) };
if ptr.is_null() {
panic!("unable to clone a packet");
}
Packet {
ptr,
time_base: self.time_base,
}
}
}
impl Drop for Packet {
fn drop(&mut self) {
unsafe { ffw_packet_free(self.ptr) }
}
}
unsafe impl Send for Packet {}
unsafe impl Sync for Packet {}
pub struct SideDataRef(());
impl SideDataRef {
pub(crate) unsafe fn from_raw_ptr<'a>(ptr: *const c_void) -> &'a Self {
unsafe { &*(ptr as *const Self) }
}
fn as_ptr(&self) -> *const c_void {
self as *const Self as _
}
pub fn data(&self) -> &[u8] {
unsafe {
let data = ffw_packet_side_data_get_data(self.as_ptr());
let len = ffw_packet_side_data_get_size(self.as_ptr());
std::slice::from_raw_parts(data, len)
}
}
pub fn data_type(&self) -> SideDataType {
let data_type = unsafe { ffw_packet_side_data_get_type(self.as_ptr()) };
SideDataType::from_raw(data_type)
}
}
pub struct SideDataType(c_int);
impl SideDataType {
pub(crate) fn from_raw(v: c_int) -> Self {
Self(v)
}
pub(crate) fn into_raw(self) -> c_int {
self.0
}
pub fn name(self) -> &'static str {
unsafe {
let ptr = ffw_packet_get_side_data_name(self.into_raw());
if ptr.is_null() {
panic!("invalid packet side data type");
}
let name = CStr::from_ptr(ptr as _);
name.to_str().unwrap()
}
}
}