// Copyright (C) 2018 Sebastian Dröge // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::fmt; use std::marker::PhantomData; use std::ops; use miniobject::MiniObject; use Buffer; use BufferRef; #[cfg(any(feature = "v1_14", feature = "dox"))] use Caps; #[cfg(any(feature = "v1_14", feature = "dox"))] use CapsRef; #[cfg(any(feature = "v1_14", feature = "dox"))] use ClockTime; use glib; #[cfg(any(feature = "v1_14", feature = "dox"))] use glib::translate::ToGlib; use glib::translate::{from_glib, from_glib_none, FromGlib, ToGlibPtr}; use glib_sys; use gst_sys; pub unsafe trait MetaAPI: Sized { type GstType; fn get_meta_api() -> glib::Type; unsafe fn from_ptr(buffer: &BufferRef, ptr: *const Self::GstType) -> MetaRef { assert!(!ptr.is_null()); let meta_api = Self::get_meta_api(); if meta_api != glib::Type::Invalid { assert_eq!( meta_api, from_glib((*(*(ptr as *const gst_sys::GstMeta)).info).api) ) } MetaRef { meta: &*(ptr as *const Self), buffer, } } unsafe fn from_mut_ptr( buffer: &mut BufferRef, ptr: *mut Self::GstType, ) -> MetaRefMut { assert!(!ptr.is_null()); let meta_api = Self::get_meta_api(); if meta_api != glib::Type::Invalid { assert_eq!( meta_api, from_glib((*(*(ptr as *const gst_sys::GstMeta)).info).api) ) } MetaRefMut { meta: &mut *(ptr as *mut Self), buffer, mode: PhantomData, } } } #[derive(Debug)] pub struct MetaRef<'a, T: MetaAPI + 'a> { meta: &'a T, buffer: &'a BufferRef, } pub enum Standalone {} pub enum Iterated {} #[derive(Debug)] pub struct MetaRefMut<'a, T: MetaAPI + 'a, U> { meta: &'a mut T, buffer: &'a mut BufferRef, mode: PhantomData, } impl<'a, T: MetaAPI> ops::Deref for MetaRef<'a, T> { type Target = T; fn deref(&self) -> &T { self.meta } } impl<'a, T: MetaAPI> AsRef> for MetaRef<'a, T> { fn as_ref(&self) -> &MetaRef<'a, T> { self } } impl<'a, T: MetaAPI, U> ops::Deref for MetaRefMut<'a, T, U> { type Target = T; fn deref(&self) -> &T { self.meta } } impl<'a, T: MetaAPI, U> ops::DerefMut for MetaRefMut<'a, T, U> { fn deref_mut(&mut self) -> &mut T { self.meta } } impl<'a, T: MetaAPI, U> AsRef> for MetaRefMut<'a, T, U> { fn as_ref(&self) -> &MetaRef<'a, T> { unsafe { &*(self as *const MetaRefMut<'a, T, U> as *const MetaRef<'a, T>) } } } impl<'a, T: MetaAPI> MetaRef<'a, T> { pub fn get_api(&self) -> glib::Type { unsafe { let meta = self.meta as *const _ as *const gst_sys::GstMeta; let info = (*meta).info; glib::Type::from_glib((*info).api) } } #[cfg(any(feature = "v1_16", feature = "dox"))] pub fn get_seqnum(&self) -> u64 { unsafe { let meta = self.meta as *const _ as *const gst_sys::GstMeta; gst_sys::gst_meta_get_seqnum(meta) } } pub fn as_ptr(&self) -> *const T::GstType { self.meta as *const _ as *const ::GstType } } impl<'a> MetaRef<'a, Meta> { pub fn downcast_ref(&self) -> Option<&MetaRef<'a, T>> { let target_type = T::get_meta_api(); let type_ = self.get_api(); if type_ == glib::Type::Invalid || target_type == type_ { Some(unsafe { &*(self as *const MetaRef<'a, Meta> as *const MetaRef<'a, T>) }) } else { None } } } impl<'a, T: MetaAPI, U> MetaRefMut<'a, T, U> { pub fn get_api(&self) -> glib::Type { unsafe { let meta = self.meta as *const _ as *const gst_sys::GstMeta; let info = (*meta).info; glib::Type::from_glib((*info).api) } } #[cfg(any(feature = "v1_16", feature = "dox"))] pub fn get_seqnum(&self) -> u64 { unsafe { let meta = self.meta as *const _ as *const gst_sys::GstMeta; gst_sys::gst_meta_get_seqnum(meta) } } pub fn as_ptr(&self) -> *const T::GstType { self.meta as *const _ as *const ::GstType } pub fn as_mut_ptr(&mut self) -> *mut T::GstType { self.meta as *mut _ as *mut ::GstType } } impl<'a, T: MetaAPI> MetaRefMut<'a, T, Standalone> { pub fn remove(mut self) { unsafe { let res = gst_sys::gst_buffer_remove_meta( self.buffer.as_mut_ptr(), self.as_mut_ptr() as *mut gst_sys::GstMeta, ); assert_ne!(res, glib_sys::GFALSE); } } } impl<'a, U> MetaRefMut<'a, Meta, U> { pub fn downcast_ref(&mut self) -> Option<&MetaRefMut<'a, T, U>> { let target_type = T::get_meta_api(); let type_ = self.get_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 } } } #[repr(C)] pub struct Meta(gst_sys::GstMeta); impl Meta { fn get_api(&self) -> glib::Type { unsafe { glib::Type::from_glib((*self.0.info).api) } } } unsafe impl MetaAPI for Meta { type GstType = gst_sys::GstMeta; fn get_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", &self.get_api()) .finish() } } #[repr(C)] pub struct ParentBufferMeta(gst_sys::GstParentBufferMeta); impl ParentBufferMeta { pub fn add<'a>(buffer: &'a mut BufferRef, parent: &Buffer) -> MetaRefMut<'a, Self, Standalone> { unsafe { let meta = gst_sys::gst_buffer_add_parent_buffer_meta( buffer.as_mut_ptr(), parent.to_glib_none().0, ); Self::from_mut_ptr(buffer, meta) } } pub fn get_parent(&self) -> &BufferRef { unsafe { BufferRef::from_ptr(self.0.buffer) } } pub fn get_parent_owned(&self) -> Buffer { unsafe { from_glib_none(self.0.buffer) } } } unsafe impl MetaAPI for ParentBufferMeta { type GstType = gst_sys::GstParentBufferMeta; fn get_meta_api() -> glib::Type { unsafe { from_glib(gst_sys::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.get_parent()) .finish() } } #[cfg(any(feature = "v1_14", feature = "dox"))] #[repr(C)] pub struct ReferenceTimestampMeta(gst_sys::GstReferenceTimestampMeta); #[cfg(any(feature = "v1_14", feature = "dox"))] impl ReferenceTimestampMeta { pub fn add<'a>( buffer: &'a mut BufferRef, reference: &Caps, timestamp: ClockTime, duration: ClockTime, ) -> MetaRefMut<'a, Self, Standalone> { unsafe { let meta = gst_sys::gst_buffer_add_reference_timestamp_meta( buffer.as_mut_ptr(), reference.to_glib_none().0, timestamp.to_glib(), duration.to_glib(), ); Self::from_mut_ptr(buffer, meta) } } pub fn get_reference(&self) -> &CapsRef { unsafe { CapsRef::from_ptr(self.0.reference) } } pub fn get_parent_owned(&self) -> Caps { unsafe { from_glib_none(self.0.reference) } } pub fn get_timestamp(&self) -> ClockTime { from_glib(self.0.timestamp) } pub fn get_duration(&self) -> ClockTime { from_glib(self.0.duration) } } #[cfg(any(feature = "v1_14", feature = "dox"))] unsafe impl MetaAPI for ReferenceTimestampMeta { type GstType = gst_sys::GstReferenceTimestampMeta; fn get_meta_api() -> glib::Type { unsafe { from_glib(gst_sys::gst_reference_timestamp_meta_api_get_type()) } } } #[cfg(any(feature = "v1_14", feature = "dox"))] impl fmt::Debug for ReferenceTimestampMeta { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ReferenceTimestampMeta") .field("reference", &self.get_reference()) .field("timestamp", &self.get_timestamp()) .field("duration", &self.get_duration()) .finish() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_add_get_iterate_meta() { ::init().unwrap(); let mut buffer = ::Buffer::new(); let parent = ::Buffer::new(); { let meta = ParentBufferMeta::add(buffer.get_mut().unwrap(), &parent); unsafe { assert_eq!(meta.get_parent().as_ptr(), parent.as_ptr()); } } { let metas = buffer.iter_meta::().collect::>(); assert_eq!(metas.len(), 1); } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::() .collect::>(); assert_eq!(metas.len(), 1); } { let metas = buffer.iter_meta::().collect::>(); assert_eq!(metas.len(), 1); unsafe { assert_eq!(metas[0].get_parent().as_ptr(), parent.as_ptr()); } } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::() .collect::>(); assert_eq!(metas.len(), 1); unsafe { assert_eq!(metas[0].get_parent().as_ptr(), parent.as_ptr()); } } { let meta = buffer .get_mut() .unwrap() .get_meta_mut::() .unwrap(); unsafe { assert_eq!(meta.get_parent().as_ptr(), parent.as_ptr()); } meta.remove(); } { let metas = buffer.iter_meta::().collect::>(); assert_eq!(metas.len(), 0); } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::() .collect::>(); assert_eq!(metas.len(), 0); } { let metas = buffer.iter_meta::().collect::>(); assert_eq!(metas.len(), 0); } { let metas = buffer .get_mut() .unwrap() .iter_meta_mut::() .collect::>(); assert_eq!(metas.len(), 0); } assert!(buffer.get_meta::().is_none()); } }