use std::marker::PhantomData; use ffmpeg_sys::{av_buffer_create, av_buffer_ref, av_buffer_unref}; use libc::c_void; unsafe extern "C" fn free(opaque: *mut c_void, data: *mut u8) { println!("freeing!"); Box::from_raw(data as *mut Data); if !std::ptr::eq(opaque as *const _, std::ptr::null()) { Box::from_raw(opaque as *mut Opaque); } } #[repr(C)] pub struct AVBufferRef { buffer_ref: *mut ffmpeg_sys::AVBufferRef, phantom: PhantomData, phantom_opaque: PhantomData> } pub struct AVBufferRefMut(AVBufferRef); impl AVBufferRef { pub fn new(data: Data, opaque: impl Into>) -> AVBufferRef { unsafe { let data = Box::into_raw(Box::new(data)) as *mut u8; let opaque = opaque.into().map_or(std::ptr::null_mut() as *mut u8, |opaque| Box::into_raw(Box::new(opaque)) as *mut u8) as *mut libc::c_void; //The buffer is marked as readonly to prevent C from doing bad things with data. If we knew T is Copy, then this could be enabled, but otherwise we can't let buffer_ref = av_buffer_create(data, 0, Some(free::), opaque, ffmpeg_sys::AV_BUFFER_FLAG_READONLY); AVBufferRef { buffer_ref, phantom: PhantomData, phantom_opaque: PhantomData } } } pub fn ref_count(buffer_ref: &AVBufferRef) -> i32 { unsafe { ffmpeg_sys::av_buffer_get_ref_count(&*buffer_ref.buffer_ref) } } /// Consumes an AVBufferRef, giving an AVBufferRefMut if writable. pub fn make_writable(buffer_ref: AVBufferRef) -> Option> { if AVBufferRef::ref_count(&buffer_ref) == 1 { Some(AVBufferRefMut(buffer_ref)) } else { None } } //Create an AVBufferRef from a raw struct. This does not do any checks for null pointers, so the onus is on you to prove that the reference is valid pub unsafe fn from_raw(raw_ref: *mut ffmpeg_sys::AVBufferRef) -> AVBufferRef { AVBufferRef { buffer_ref: raw_ref, phantom: PhantomData, phantom_opaque: PhantomData } } } impl AVBufferRefMut { pub fn downgrade(buffer_ref: AVBufferRefMut) -> AVBufferRef { buffer_ref.0 } } impl std::ops::Drop for AVBufferRef { fn drop(&mut self) { unsafe { av_buffer_unref(&mut self.buffer_ref) } } } impl std::ops::Deref for AVBufferRef { type Target = Data; fn deref(&self) -> &Data { unsafe { &*((*self.buffer_ref).data as *const _ as *const Data) } } } impl std::ops::Deref for AVBufferRefMut { type Target = Data; fn deref(&self) -> &Data { &*self.0 } } impl std::ops::DerefMut for AVBufferRefMut { fn deref_mut(&mut self) -> &mut Data { unsafe { &mut *((*self.0.buffer_ref).data as *mut Data) } } } impl Clone for AVBufferRef { fn clone(&self) -> Self { let buffer_ref = unsafe { av_buffer_ref(self.buffer_ref) }; AVBufferRef { buffer_ref: buffer_ref, phantom: PhantomData, phantom_opaque: PhantomData } } }