// Take a look at the license at the top of the repository in the LICENSE file. #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] use std::ptr; use std::{ fmt, marker::PhantomData, ops::{self, Bound, RangeBounds}, }; use glib::translate::*; use crate::{Buffer, BufferRef, Caps, CapsRef, ClockTime}; pub unsafe trait MetaAPI: Sync + Send + Sized { type GstType; #[doc(alias = "get_meta_api")] fn meta_api() -> glib::Type; } pub trait MetaAPIExt: MetaAPI { #[inline] unsafe fn from_ptr(buffer: &BufferRef, ptr: *const Self::GstType) -> MetaRef { debug_assert!(!ptr.is_null()); let meta_api = Self::meta_api(); if meta_api != glib::Type::INVALID { debug_assert_eq!( meta_api, from_glib((*(*(ptr as *const ffi::GstMeta)).info).api) ) } MetaRef { meta: &*(ptr as *const Self), buffer, } } #[inline] unsafe fn from_mut_ptr( buffer: &mut BufferRef, ptr: *mut Self::GstType, ) -> MetaRefMut { debug_assert!(!ptr.is_null()); let meta_api = Self::meta_api(); if meta_api != glib::Type::INVALID { debug_assert_eq!( meta_api, from_glib((*(*(ptr as *const ffi::GstMeta)).info).api) ) } MetaRefMut { meta: &mut *(ptr as *mut Self), buffer, mode: PhantomData, } } } impl MetaAPIExt for A {} #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] pub struct MetaSeqnum(u64); pub struct MetaRef<'a, T: 'a> { meta: &'a T, buffer: &'a BufferRef, } pub enum Standalone {} pub enum Iterated {} pub struct MetaRefMut<'a, T: 'a, U> { meta: &'a mut T, buffer: &'a mut BufferRef, mode: PhantomData, } impl<'a, T: fmt::Debug + 'a> fmt::Debug for MetaRef<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MetaRef") .field("meta", &self.meta) .field("buffer", &self.buffer) .finish() } } impl<'a, T: fmt::Debug + 'a, U> fmt::Debug for MetaRefMut<'a, T, U> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MetaRef") .field("meta", &self.meta) .field("buffer", &self.buffer) .field("mode", &self.mode) .finish() } } impl<'a, T> ops::Deref for MetaRef<'a, T> { type Target = T; #[inline] fn deref(&self) -> &T { self.meta } } impl<'a, T> AsRef> for MetaRef<'a, T> { #[inline] fn as_ref(&self) -> &MetaRef<'a, T> { self } } impl<'a, T> AsRef for MetaRef<'a, T> { #[inline] fn as_ref(&self) -> &T { self.meta } } impl<'a, T: 'a> Clone for MetaRef<'a, T> { fn clone(&self) -> Self { MetaRef { meta: self.meta, buffer: self.buffer, } } } impl<'a, T, U> ops::Deref for MetaRefMut<'a, T, U> { type Target = T; #[inline] fn deref(&self) -> &T { self.meta } } impl<'a, T, U> ops::DerefMut for MetaRefMut<'a, T, U> { #[inline] fn deref_mut(&mut self) -> &mut T { self.meta } } impl<'a, T, U> AsRef> for MetaRefMut<'a, T, U> { #[inline] fn as_ref(&self) -> &MetaRef<'a, T> { unsafe { &*(self as *const MetaRefMut<'a, T, U> as *const MetaRef<'a, T>) } } } impl<'a, T, U> AsMut for MetaRefMut<'a, T, U> { #[inline] fn as_mut(&mut self) -> &mut T { self.meta } } impl<'a, T> MetaRef<'a, T> { #[doc(alias = "get_api")] #[inline] pub fn api(&self) -> glib::Type { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; let info = (*meta).info; glib::Type::from_glib((*info).api) } } #[inline] pub fn flags(&self) -> crate::MetaFlags { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; from_glib((*meta).flags) } } #[inline] pub fn type_(&self) -> glib::Type { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; let info = (*meta).info; glib::Type::from_glib((*info).type_) } } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "get_seqnum")] #[doc(alias = "gst_meta_get_seqnum")] #[inline] pub fn seqnum(&self) -> MetaSeqnum { unsafe { let meta = self.meta as *const _ as *const ffi::GstMeta; MetaSeqnum(ffi::gst_meta_get_seqnum(meta)) } } #[inline] #[doc(alias = "gst_meta_api_type_has_tag")] pub fn has_tag(&self) -> bool { self.has_tag_by_quark(MT::quark()) } #[inline] pub fn has_tag_by_quark(&self, tag: glib::Quark) -> bool { unsafe { from_glib(ffi::gst_meta_api_type_has_tag( self.api().into_glib(), tag.into_glib(), )) } } #[inline] #[doc(alias = "gst_meta_api_type_get_tags")] pub fn tags<'b>(&self) -> &'b [glib::GStringPtr] { unsafe { glib::StrV::from_glib_borrow(ffi::gst_meta_api_type_get_tags(self.api().into_glib())) } } #[inline] pub fn upcast_ref(&self) -> &MetaRef<'a, Meta> { unsafe { &*(self as *const MetaRef<'a, T> as *const MetaRef<'a, Meta>) } } pub fn transform(&self, buffer: &mut BufferRef, data: &'a MT) -> Result<(), glib::BoolError> where T: MetaAPI, MT: MetaTransform<'a>, { unsafe { let info = *(*self.upcast_ref().as_ptr()).info; let Some(transform_func) = info.transform_func else { return Err(glib::bool_error!( "Can't copy meta without transform function" )); }; let data = data.to_raw(self)?; glib::result_from_gboolean!( transform_func( buffer.as_mut_ptr(), mut_override(self.upcast_ref().as_ptr()), mut_override(self.buffer.as_ptr()), MT::quark().into_glib(), mut_override(&data) as *mut _, ), "Failed to transform meta" ) } } #[inline] pub fn as_ptr(&self) -> *const T::GstType where T: MetaAPI, { self.meta as *const _ as *const ::GstType } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_meta_serialize")] pub fn serialize( &self, writer: &mut B, ) -> Result { unsafe { #[repr(C)] struct Writer<'a, B: ?Sized> { iface_: ffi::GstByteArrayInterface, writer: &'a mut B, } unsafe extern "C" fn resize( iface_: *mut ffi::GstByteArrayInterface, size: usize, ) -> glib::ffi::gboolean { let iface_ = &mut *(iface_ as *mut Writer); match iface_.writer.resize(size) { Some(new_data) => { iface_.iface_.data = new_data.as_mut_ptr(); iface_.iface_.len = size; glib::ffi::GTRUE } None => glib::ffi::GFALSE, } } let initial_len = writer.initial_len(); let mut iface_ = Writer { iface_: ffi::GstByteArrayInterface { data: writer.as_mut().as_mut_ptr(), len: initial_len, resize: Some(resize::), _gst_reserved: [ptr::null_mut(); 4], }, writer: &mut *writer, }; let res = bool::from_glib(ffi::gst_meta_serialize( self.meta as *const T as *const ffi::GstMeta, &mut iface_.iface_, )); if !res { return Err(glib::bool_error!("Failed to serialize meta")); } assert!(iface_.iface_.len >= initial_len); Ok(iface_.iface_.len - initial_len) } } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] pub trait ByteArrayInterface: AsMut<[u8]> { fn initial_len(&self) -> usize; fn resize(&mut self, size: usize) -> Option<&mut [u8]>; } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl ByteArrayInterface for Vec { fn initial_len(&self) -> usize { self.len() } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { self.resize(size, 0); Some(&mut self[0..size]) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl> ByteArrayInterface for smallvec::SmallVec { fn initial_len(&self) -> usize { self.len() } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { self.resize(size, 0); Some(&mut self[0..size]) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl ByteArrayInterface for &mut [u8] { fn initial_len(&self) -> usize { 0 } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { if self.len() < size { return None; } Some(&mut self[0..size]) } } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] impl ByteArrayInterface for [u8; N] { fn initial_len(&self) -> usize { 0 } fn resize(&mut self, size: usize) -> Option<&mut [u8]> { if N < size { return None; } Some(&mut self[0..size]) } } impl<'a> MetaRef<'a, Meta> { #[inline] pub fn downcast_ref(&self) -> Option<&MetaRef<'a, T>> { let target_type = T::meta_api(); let type_ = self.api(); if type_ == glib::Type::INVALID || target_type == type_ { Some(unsafe { &*(self as *const MetaRef<'a, Meta> as *const MetaRef<'a, T>) }) } else { None } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[inline] pub fn try_as_custom_meta(&self) -> Option<&MetaRef<'a, CustomMeta>> { unsafe { if ffi::gst_meta_info_is_custom(&*self.0.info) == glib::ffi::GFALSE { return None; } Some(&*(self as *const MetaRef<'a, Meta> as *const MetaRef<'a, CustomMeta>)) } } } impl<'a, T, U> MetaRefMut<'a, T, U> { #[doc(alias = "get_api")] #[inline] pub fn api(&self) -> glib::Type { self.as_meta_ref().api() } #[inline] pub fn flags(&self) -> crate::MetaFlags { self.as_meta_ref().flags() } #[inline] pub fn type_(&self) -> glib::Type { self.as_meta_ref().type_() } #[cfg(feature = "v1_16")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))] #[doc(alias = "get_seqnum")] #[doc(alias = "gst_meta_get_seqnum")] #[inline] pub fn seqnum(&self) -> MetaSeqnum { self.as_meta_ref().seqnum() } #[inline] #[doc(alias = "gst_meta_api_type_has_tag")] pub fn has_tag(&self) -> bool { self.as_meta_ref().has_tag::() } #[inline] pub fn has_tag_by_quark(&self, tag: glib::Quark) -> bool { self.as_meta_ref().has_tag_by_quark(tag) } #[inline] #[doc(alias = "gst_meta_api_type_get_tags")] pub fn tags<'b>(&self) -> &'b [glib::GStringPtr] { self.as_meta_ref().tags() } #[inline] pub fn upcast_ref(&self) -> &MetaRef<'a, Meta> { unsafe { &*(self as *const MetaRefMut<'a, T, U> as *const MetaRef<'a, Meta>) } } #[inline] pub fn upcast_mut(&mut self) -> &mut MetaRefMut<'a, Meta, U> { unsafe { &mut *(self as *mut MetaRefMut<'a, T, U> as *mut MetaRefMut<'a, Meta, U>) } } #[inline] pub fn as_meta_ref(&self) -> MetaRef { MetaRef { meta: self.meta, buffer: self.buffer, } } pub fn transform( &'a self, buffer: &mut BufferRef, data: &'a MT, ) -> Result<(), glib::BoolError> where T: MetaAPI, MT: MetaTransform<'a>, { self.as_meta_ref().transform(buffer, data) } #[inline] pub fn as_ptr(&self) -> *const T::GstType where T: MetaAPI, { self.meta as *const _ as *const ::GstType } #[inline] pub fn as_mut_ptr(&mut self) -> *mut T::GstType where T: MetaAPI, { self.meta as *mut _ as *mut ::GstType } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_meta_serialize")] pub fn serialize( &self, writer: &mut B, ) -> Result { self.as_meta_ref().serialize(writer) } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] pub fn clear(&mut self) -> Result<(), glib::BoolError> where T: MetaAPI, { unsafe { let info = *(*self.upcast_ref().as_ptr()).info; if let Some(clear_func) = info.clear_func { clear_func(self.buffer.as_mut_ptr(), self.upcast_mut().as_mut_ptr()); Ok(()) } else { Err(glib::bool_error!("Failed to clear meta")) } } } } impl<'a, T> MetaRefMut<'a, T, Standalone> { #[doc(alias = "gst_buffer_remove_meta")] pub fn remove(self) -> Result<(), glib::BoolError> { if self.flags().contains(crate::MetaFlags::LOCKED) { return Err(glib::bool_error!("Can't remove locked meta")); } unsafe { let res = ffi::gst_buffer_remove_meta( self.buffer.as_mut_ptr(), self.meta as *mut T as *mut ffi::GstMeta, ); debug_assert_ne!(res, glib::ffi::GFALSE); Ok(()) } } } impl<'a, U> MetaRefMut<'a, Meta, U> { #[inline] pub fn downcast_ref(&mut self) -> Option<&MetaRefMut<'a, T, U>> { let target_type = T::meta_api(); let type_ = self.api(); if type_ == glib::Type::INVALID || target_type == type_ { Some(unsafe { &*(self as *mut MetaRefMut<'a, Meta, U> as *const MetaRefMut<'a, T, U>) }) } else { None } } #[inline] pub fn downcast_mut(&mut self) -> Option<&mut MetaRefMut<'a, T, U>> { let target_type = T::meta_api(); let type_ = self.api(); if type_ == glib::Type::INVALID || target_type == type_ { Some(unsafe { &mut *(self as *mut MetaRefMut<'a, Meta, U> as *mut MetaRefMut<'a, T, U>) }) } else { None } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[inline] pub fn try_as_custom_meta(&self) -> Option<&MetaRefMut<'a, CustomMeta, U>> { unsafe { if ffi::gst_meta_info_is_custom(&*self.0.info) == glib::ffi::GFALSE { return None; } Some(&*(self as *const MetaRefMut<'a, Meta, U> as *const MetaRefMut<'a, CustomMeta, U>)) } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[inline] pub fn try_as_mut_custom_meta(&mut self) -> Option<&mut MetaRefMut<'a, CustomMeta, U>> { unsafe { if ffi::gst_meta_info_is_custom(&*self.0.info) == glib::ffi::GFALSE { return None; } Some(&mut *(self as *mut MetaRefMut<'a, Meta, U> as *mut MetaRefMut<'a, CustomMeta, U>)) } } } #[repr(transparent)] #[doc(alias = "GstMeta")] pub struct Meta(ffi::GstMeta); unsafe impl Send for Meta {} unsafe impl Sync for Meta {} unsafe impl MetaAPI for Meta { type GstType = ffi::GstMeta; #[inline] fn meta_api() -> glib::Type { glib::Type::INVALID } } impl fmt::Debug for Meta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Meta") .field("api", &unsafe { glib::Type::from_glib((*self.0.info).api) }) .field("type", &unsafe { glib::Type::from_glib((*self.0.info).type_) }) .field("flags", &unsafe { crate::MetaFlags::from_glib(self.0.flags) }) .finish() } } impl Meta { #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[doc(alias = "gst_meta_deserialize")] pub fn deserialize<'a>( buffer: &'a mut BufferRef, data: &[u8], consumed: &mut usize, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { use std::mem; let mut consumed_u32 = mem::MaybeUninit::uninit(); let res = ffi::gst_meta_deserialize( buffer.as_mut_ptr(), data.as_ptr(), data.len(), consumed_u32.as_mut_ptr(), ); *consumed = consumed_u32.assume_init() as usize; if res.is_null() { return Err(glib::bool_error!("Failed to deserialize meta")); } Ok(MetaRefMut { meta: &mut *(res as *mut Self), buffer, mode: PhantomData, }) } } } #[repr(transparent)] #[doc(alias = "GstParentBufferMeta")] pub struct ParentBufferMeta(ffi::GstParentBufferMeta); unsafe impl Send for ParentBufferMeta {} unsafe impl Sync for ParentBufferMeta {} impl ParentBufferMeta { #[doc(alias = "gst_buffer_add_parent_buffer_meta")] pub fn add<'a>(buffer: &'a mut BufferRef, parent: &Buffer) -> MetaRefMut<'a, Self, Standalone> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_parent_buffer_meta( buffer.as_mut_ptr(), parent.to_glib_none().0, ); Self::from_mut_ptr(buffer, meta) } } #[doc(alias = "get_parent")] #[inline] pub fn parent(&self) -> &BufferRef { unsafe { BufferRef::from_ptr(self.0.buffer) } } #[doc(alias = "get_parent_owned")] #[inline] pub fn parent_owned(&self) -> Buffer { unsafe { from_glib_none(self.0.buffer) } } } unsafe impl MetaAPI for ParentBufferMeta { type GstType = ffi::GstParentBufferMeta; #[doc(alias = "gst_parent_buffer_meta_api_get_type")] #[inline] fn meta_api() -> glib::Type { unsafe { from_glib(ffi::gst_parent_buffer_meta_api_get_type()) } } } impl fmt::Debug for ParentBufferMeta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ParentBufferMeta") .field("parent", &self.parent()) .finish() } } #[repr(transparent)] #[doc(alias = "GstProtectionMeta")] pub struct ProtectionMeta(ffi::GstProtectionMeta); unsafe impl Send for ProtectionMeta {} unsafe impl Sync for ProtectionMeta {} impl ProtectionMeta { #[doc(alias = "gst_buffer_add_protection_meta")] pub fn add(buffer: &mut BufferRef, info: crate::Structure) -> MetaRefMut { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_protection_meta(buffer.as_mut_ptr(), info.into_glib_ptr()); Self::from_mut_ptr(buffer, meta) } } #[doc(alias = "get_info")] #[inline] pub fn info(&self) -> &crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow(self.0.info) } } #[doc(alias = "get_info_mut")] #[inline] pub fn info_mut(&mut self) -> &mut crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow_mut(self.0.info) } } } unsafe impl MetaAPI for ProtectionMeta { type GstType = ffi::GstProtectionMeta; #[doc(alias = "gst_protection_meta_api_get_type")] #[inline] fn meta_api() -> glib::Type { unsafe { from_glib(ffi::gst_protection_meta_api_get_type()) } } } impl fmt::Debug for ProtectionMeta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ProtectionMeta") .field("info", &self.info()) .finish() } } #[repr(transparent)] #[doc(alias = "GstReferenceTimestampMeta")] pub struct ReferenceTimestampMeta(ffi::GstReferenceTimestampMeta); unsafe impl Send for ReferenceTimestampMeta {} unsafe impl Sync for ReferenceTimestampMeta {} impl ReferenceTimestampMeta { #[doc(alias = "gst_buffer_add_reference_timestamp_meta")] pub fn add<'a>( buffer: &'a mut BufferRef, reference: &Caps, timestamp: ClockTime, duration: impl Into>, ) -> MetaRefMut<'a, Self, Standalone> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_reference_timestamp_meta( buffer.as_mut_ptr(), reference.to_glib_none().0, timestamp.into_glib(), duration.into().into_glib(), ); Self::from_mut_ptr(buffer, meta) } } #[doc(alias = "get_reference")] #[inline] pub fn reference(&self) -> &CapsRef { unsafe { CapsRef::from_ptr(self.0.reference) } } #[doc(alias = "get_reference_owned")] #[inline] pub fn reference_owned(&self) -> Caps { unsafe { from_glib_none(self.0.reference) } } #[doc(alias = "get_timestamp")] #[inline] pub fn timestamp(&self) -> ClockTime { unsafe { try_from_glib(self.0.timestamp).expect("undefined timestamp") } } #[doc(alias = "get_duration")] #[inline] pub fn duration(&self) -> Option { unsafe { from_glib(self.0.duration) } } } unsafe impl MetaAPI for ReferenceTimestampMeta { type GstType = ffi::GstReferenceTimestampMeta; #[doc(alias = "gst_reference_timestamp_meta_api_get_type")] #[inline] fn meta_api() -> glib::Type { unsafe { from_glib(ffi::gst_reference_timestamp_meta_api_get_type()) } } } impl fmt::Debug for ReferenceTimestampMeta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use crate::utils::Displayable; f.debug_struct("ReferenceTimestampMeta") .field("reference", &self.reference()) .field("timestamp", &self.timestamp().display()) .field("duration", &self.duration().display()) .finish() } } #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] #[repr(transparent)] #[doc(alias = "GstCustomMeta")] pub struct CustomMeta(ffi::GstCustomMeta); #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] unsafe impl Send for CustomMeta {} #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] unsafe impl Sync for CustomMeta {} #[cfg(feature = "v1_20")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))] impl CustomMeta { #[doc(alias = "gst_meta_register_custom")] pub fn register(name: &str, tags: &[&str]) { assert_initialized_main_thread!(); unsafe { ffi::gst_meta_register_custom( name.to_glib_none().0, tags.to_glib_none().0, None, ptr::null_mut(), None, ); } } #[doc(alias = "gst_meta_register_custom")] pub fn register_with_transform< F: Fn(&mut BufferRef, &CustomMeta, &BufferRef, glib::Quark) -> bool + Send + Sync + 'static, >( name: &str, tags: &[&str], transform_func: F, ) { assert_initialized_main_thread!(); unsafe extern "C" fn transform_func_trampoline< F: Fn(&mut BufferRef, &CustomMeta, &BufferRef, glib::Quark) -> bool + Send + Sync + 'static, >( dest: *mut ffi::GstBuffer, meta: *mut ffi::GstCustomMeta, src: *mut ffi::GstBuffer, type_: glib::ffi::GQuark, _data: glib::ffi::gpointer, user_data: glib::ffi::gpointer, ) -> glib::ffi::gboolean { let func = &*(user_data as *const F); let res = func( BufferRef::from_mut_ptr(dest), &*(meta as *const CustomMeta), BufferRef::from_ptr(src), from_glib(type_), ); res.into_glib() } unsafe extern "C" fn transform_func_free(ptr: glib::ffi::gpointer) { let _ = Box::from_raw(ptr as *mut F); } unsafe { ffi::gst_meta_register_custom( name.to_glib_none().0, tags.to_glib_none().0, Some(transform_func_trampoline::), Box::into_raw(Box::new(transform_func)) as glib::ffi::gpointer, Some(transform_func_free::), ); } } #[doc(alias = "gst_meta_register_simple")] pub fn register_simple(name: &str) { assert_initialized_main_thread!(); unsafe { ffi::gst_meta_register_custom( name.to_glib_none().0, ptr::null_mut(), None, ptr::null_mut(), None, ); } } pub fn is_registered(name: &str) -> bool { assert_initialized_main_thread!(); unsafe { name.run_with_gstr(|name| !ffi::gst_meta_get_info(name.as_ptr()).is_null()) } } #[doc(alias = "gst_buffer_add_custom_meta")] pub fn add<'a>( buffer: &'a mut BufferRef, name: &str, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_add_custom_meta(buffer.as_mut_ptr(), name.to_glib_none().0); if meta.is_null() { return Err(glib::bool_error!("Failed to add custom meta")); } Ok(MetaRefMut { meta: &mut *(meta as *mut Self), buffer, mode: PhantomData, }) } } #[doc(alias = "gst_buffer_get_custom_meta")] pub fn from_buffer<'a>( buffer: &'a BufferRef, name: &str, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_get_custom_meta(buffer.as_mut_ptr(), name.to_glib_none().0); if meta.is_null() { return Err(glib::bool_error!("Failed to get custom meta")); } Ok(MetaRef { meta: &*(meta as *const Self), buffer, }) } } #[doc(alias = "gst_buffer_get_custom_meta")] pub fn from_mut_buffer<'a>( buffer: &'a mut BufferRef, name: &str, ) -> Result, glib::BoolError> { skip_assert_initialized!(); unsafe { let meta = ffi::gst_buffer_get_custom_meta(buffer.as_mut_ptr(), name.to_glib_none().0); if meta.is_null() { return Err(glib::bool_error!("Failed to get custom meta")); } Ok(MetaRefMut { meta: &mut *(meta as *mut Self), buffer, mode: PhantomData, }) } } #[doc(alias = "gst_custom_meta_get_structure")] #[inline] pub fn structure(&self) -> &crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow(ffi::gst_custom_meta_get_structure(mut_override( &self.0, ))) } } #[doc(alias = "gst_custom_meta_get_structure")] #[inline] pub fn mut_structure(&mut self) -> &mut crate::StructureRef { unsafe { crate::StructureRef::from_glib_borrow_mut(ffi::gst_custom_meta_get_structure( &mut self.0, )) } } #[doc(alias = "gst_custom_meta_has_name")] #[inline] pub fn has_name(&self, name: &str) -> bool { unsafe { from_glib(ffi::gst_custom_meta_has_name( mut_override(&self.0), name.to_glib_none().0, )) } } } pub trait MetaTag { const TAG_NAME: &'static glib::GStr; fn quark() -> glib::Quark; } #[macro_export] macro_rules! impl_meta_tag( ($name:ident, $gst_tag:ident) => { pub enum $name {} impl $crate::meta::MetaTag for $name { const TAG_NAME: &'static glib::GStr = unsafe { glib::GStr::from_utf8_with_nul_unchecked(ffi::$gst_tag) }; fn quark() -> glib::Quark { static QUARK: std::sync::OnceLock = std::sync::OnceLock::new(); *QUARK.get_or_init(|| glib::Quark::from_static_str(Self::TAG_NAME)) } } }; ); pub mod tags { impl_meta_tag!(Memory, GST_META_TAG_MEMORY_STR); impl_meta_tag!(MemoryReference, GST_META_TAG_MEMORY_REFERENCE_STR); } pub unsafe trait MetaTransform<'a> { type GLibType; fn quark() -> glib::Quark; fn to_raw(&self, meta: &MetaRef) -> Result; } #[derive(Debug, Clone, PartialEq, Eq)] pub struct MetaTransformCopy { range: (Bound, Bound), region: bool, } impl MetaTransformCopy { pub fn new(region: bool, range: impl RangeBounds) -> Self { skip_assert_initialized!(); MetaTransformCopy { range: (range.start_bound().cloned(), range.end_bound().cloned()), region, } } } unsafe impl<'a> MetaTransform<'a> for MetaTransformCopy { type GLibType = ffi::GstMetaTransformCopy; fn quark() -> glib::Quark { static QUARK: std::sync::OnceLock = std::sync::OnceLock::new(); *QUARK.get_or_init(|| glib::Quark::from_static_str(glib::gstr!("gst-copy"))) } fn to_raw( &self, meta: &MetaRef, ) -> Result { let (offset, size) = meta.buffer.byte_range_into_offset_len(self.range)?; Ok(ffi::GstMetaTransformCopy { region: self.region.into_glib(), offset, size, }) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_add_get_iterate_meta() { crate::init().unwrap(); let mut buffer = crate::Buffer::new(); let parent = crate::Buffer::new(); { let meta = ParentBufferMeta::add(buffer.get_mut().unwrap(), &parent); assert_eq!(meta.parent().as_ptr(), parent.as_ptr()); } { let metas = buffer.iter_meta::(); assert_eq!(metas.count(), 1); } { let metas = buffer.get_mut().unwrap().iter_meta_mut::(); assert_eq!(metas.count(), 1); } { let metas = buffer.iter_meta::().collect::>(); assert_eq!(metas.len(), 1); assert_eq!(metas[0].parent().as_ptr(), parent.as_ptr()); } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::() .collect::>(); assert_eq!(metas.len(), 1); assert_eq!(metas[0].parent().as_ptr(), parent.as_ptr()); assert!(!metas[0].has_tag_by_quark(glib::Quark::from_str("video"))); assert!(metas[0].has_tag::()); assert_eq!(metas[0].tags().len(), 1); assert_eq!(metas[0].tags(), metas[0].upcast_ref().tags()); } { let meta = buffer .get_mut() .unwrap() .meta_mut::() .unwrap(); assert_eq!(meta.parent().as_ptr(), parent.as_ptr()); meta.remove().unwrap(); } { let metas = buffer.iter_meta::(); assert_eq!(metas.count(), 0); } { let metas = buffer.get_mut().unwrap().iter_meta_mut::(); assert_eq!(metas.count(), 0); } { let metas = buffer.iter_meta::(); assert_eq!(metas.count(), 0); } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::(); assert_eq!(metas.count(), 0); } assert!(buffer.meta::().is_none()); } #[test] fn test_copy_reference_timestamp_meta() { crate::init().unwrap(); let caps = crate::Caps::new_empty_simple("timestamp/x-ntp"); let mut buffer = crate::Buffer::new(); { ReferenceTimestampMeta::add( buffer.get_mut().unwrap(), &caps, crate::ClockTime::from_seconds(1), crate::ClockTime::NONE, ); } let mut buffer_dest = crate::Buffer::new(); { let meta = buffer.meta::().unwrap(); let buffer_dest = buffer_dest.get_mut().unwrap(); meta.transform(buffer_dest, &MetaTransformCopy::new(false, ..)) .unwrap(); } let meta = buffer_dest.meta::().unwrap(); assert_eq!(meta.reference(), &caps); assert_eq!(meta.timestamp(), crate::ClockTime::from_seconds(1)); assert_eq!(meta.duration(), crate::ClockTime::NONE); } #[cfg(feature = "v1_24")] #[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))] #[test] fn test_meta_serialize() { use smallvec::SmallVec; crate::init().unwrap(); let caps = crate::Caps::new_empty_simple("timestamp/x-ntp"); let mut buffer = crate::Buffer::new(); let meta = ReferenceTimestampMeta::add( buffer.get_mut().unwrap(), &caps, crate::ClockTime::from_seconds(1), crate::ClockTime::NONE, ); let mut data_1 = Vec::new(); let mut data_2 = [0u8; 128]; let mut data_3 = SmallVec::<[u8; 128]>::new(); let len_1 = meta.serialize(&mut data_1).unwrap(); let len_2 = meta.serialize(&mut data_2).unwrap(); let len_3 = meta.serialize(&mut data_3).unwrap(); assert_eq!(&data_1[..len_1], &data_2[..len_2]); assert_eq!(&data_1[..len_1], &data_3[..len_3]); assert!(meta.serialize(&mut [0]).is_err()); let mut buffer_dest = crate::Buffer::new(); let mut consumed = 0; let mut meta = Meta::deserialize(buffer_dest.get_mut().unwrap(), &data_1, &mut consumed).unwrap(); assert_eq!(consumed, len_1); let meta = meta.downcast_ref::().unwrap(); assert_eq!(meta.reference(), &caps); assert_eq!(meta.timestamp(), crate::ClockTime::from_seconds(1)); assert_eq!(meta.duration(), crate::ClockTime::NONE); let mut consumed = 0; assert!( Meta::deserialize(buffer_dest.get_mut().unwrap(), &[0, 1, 2], &mut consumed).is_err() ); assert_eq!(consumed, 0); } }