// Copyright (C) 2017 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 miniobject::MiniObject; use Buffer; use BufferList; use Event; use FlowError; use FlowReturn; use Format; use FormattedValue; use GenericFormattedValue; use Pad; use PadProbeReturn; use PadProbeType; use Query; use QueryRef; use SpecificFormattedValue; use StaticPadTemplate; use std::cell::RefCell; use std::mem; use std::mem::transmute; use std::ops; use std::ptr; use glib; use glib::translate::{ from_glib, from_glib_borrow, from_glib_full, from_glib_none, mut_override, FromGlib, ToGlib, ToGlibPtr, }; use glib::Object; use glib::{IsA, IsClassFor, StaticType}; use glib_ffi; use glib_ffi::gpointer; use libc; use ffi; impl Pad { pub fn new_from_static_template<'a, P: Into>>( templ: &StaticPadTemplate, name: P, ) -> Pad { assert_initialized_main_thread!(); let name = name.into(); unsafe { from_glib_none(ffi::gst_pad_new_from_static_template( mut_override(templ.to_glib_none().0), name.to_glib_none().0, )) } } } #[derive(Debug, PartialEq, Eq)] pub struct PadProbeId(libc::c_ulong); impl ToGlib for PadProbeId { type GlibType = libc::c_ulong; fn to_glib(&self) -> libc::c_ulong { self.0 } } impl FromGlib for PadProbeId { fn from_glib(val: libc::c_ulong) -> PadProbeId { skip_assert_initialized!(); assert_ne!(val, 0); PadProbeId(val) } } pub struct PadProbeInfo<'a> { pub mask: PadProbeType, pub id: PadProbeId, pub offset: u64, pub size: u32, pub data: Option>, } pub enum PadProbeData<'a> { Buffer(Buffer), BufferList(BufferList), Query(&'a mut QueryRef), Event(Event), #[doc(hidden)] __Unknown(*mut ffi::GstMiniObject), } pub struct StreamLock(Pad); impl Drop for StreamLock { fn drop(&mut self) { unsafe { let pad: *mut ffi::GstPad = self.0.to_glib_none().0; glib_ffi::g_rec_mutex_unlock(&mut (*pad).stream_rec_lock); } } } pub trait PadExtManual: 'static { fn add_probe(&self, mask: PadProbeType, func: F) -> Option where F: Fn(&Pad, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static; fn remove_probe(&self, id: PadProbeId); fn chain(&self, buffer: Buffer) -> FlowReturn; fn push(&self, buffer: Buffer) -> FlowReturn; fn chain_list(&self, list: BufferList) -> FlowReturn; fn push_list(&self, list: BufferList) -> FlowReturn; fn pull_range(&self, offset: u64, size: u32) -> Result; fn get_range(&self, offset: u64, size: u32) -> Result; fn peer_query(&self, query: &mut QueryRef) -> bool; fn query(&self, query: &mut QueryRef) -> bool; fn query_default<'a, P: IsA + 'a, Q: Into>>( &self, parent: Q, query: &mut QueryRef, ) -> bool; fn proxy_query_caps(&self, query: &mut QueryRef) -> bool; fn proxy_query_accept_caps(&self, query: &mut QueryRef) -> bool; fn event_default<'a, P: IsA<::Object> + 'a, Q: Into>>( &self, parent: Q, event: Event, ) -> bool; fn push_event(&self, event: Event) -> bool; fn send_event(&self, event: Event) -> bool; fn iterate_internal_links(&self) -> ::Iterator; fn iterate_internal_links_default<'a, P: IsA<::Object> + 'a, Q: Into>>( &self, parent: Q, ) -> ::Iterator; fn stream_lock(&self) -> StreamLock; fn set_activate_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>) -> bool + Send + Sync + 'static; fn set_activatemode_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::PadMode, bool) -> bool + Send + Sync + 'static; fn set_chain_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::Buffer) -> ::FlowReturn + Send + Sync + 'static; fn set_chain_list_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::BufferList) -> ::FlowReturn + Send + Sync + 'static; fn set_event_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::Event) -> bool + Send + Sync + 'static; fn set_event_full_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::Event) -> ::FlowReturn + Send + Sync + 'static; fn set_getrange_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, u64, u32) -> Result<::Buffer, ::FlowError> + Send + Sync + 'static; fn set_iterate_internal_links_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>) -> ::Iterator + Send + Sync + 'static; fn set_link_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, &Pad) -> ::PadLinkReturn + Send + Sync + 'static; fn set_query_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, &mut ::QueryRef) -> bool + Send + Sync + 'static; fn set_unlink_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>) + Send + Sync + 'static; fn start_task(&self, func: F) -> Result<(), glib::BoolError>; fn peer_query_convert, U: SpecificFormattedValue>( &self, src_val: V, ) -> Option; fn peer_query_convert_generic>( &self, src_val: V, dest_format: Format, ) -> Option; fn peer_query_duration(&self) -> Option; fn peer_query_duration_generic(&self, format: Format) -> Option; fn peer_query_position(&self) -> Option; fn peer_query_position_generic(&self, format: Format) -> Option; fn query_convert, U: SpecificFormattedValue>( &self, src_val: V, ) -> Option; fn query_convert_generic>( &self, src_val: V, dest_format: Format, ) -> Option; fn query_duration(&self) -> Option; fn query_duration_generic(&self, format: Format) -> Option; fn query_position(&self) -> Option; fn query_position_generic(&self, format: Format) -> Option; fn get_mode(&self) -> ::PadMode; fn sticky_events_foreach Result, Option>>( &self, func: F, ); } impl> PadExtManual for O { fn add_probe(&self, mask: PadProbeType, func: F) -> Option where F: Fn(&Pad, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static, > = Box::new(func); let id = ffi::gst_pad_add_probe( self.to_glib_none().0, mask.to_glib(), Some(trampoline_pad_probe), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); if id == 0 { None } else { Some(from_glib(id)) } } } fn remove_probe(&self, id: PadProbeId) { unsafe { ffi::gst_pad_remove_probe(self.to_glib_none().0, id.to_glib()); } } fn chain(&self, buffer: Buffer) -> FlowReturn { unsafe { from_glib(ffi::gst_pad_chain(self.to_glib_none().0, buffer.into_ptr())) } } fn push(&self, buffer: Buffer) -> FlowReturn { unsafe { from_glib(ffi::gst_pad_push(self.to_glib_none().0, buffer.into_ptr())) } } fn chain_list(&self, list: BufferList) -> FlowReturn { unsafe { from_glib(ffi::gst_pad_chain_list( self.to_glib_none().0, list.into_ptr(), )) } } fn push_list(&self, list: BufferList) -> FlowReturn { unsafe { from_glib(ffi::gst_pad_push_list( self.to_glib_none().0, list.into_ptr(), )) } } fn get_range(&self, offset: u64, size: u32) -> Result { unsafe { let mut buffer = ptr::null_mut(); let ret: FlowReturn = from_glib(ffi::gst_pad_get_range( self.to_glib_none().0, offset, size, &mut buffer, )); ret.into_result_value(|| from_glib_full(buffer)) } } fn pull_range(&self, offset: u64, size: u32) -> Result { unsafe { let mut buffer = ptr::null_mut(); let ret: FlowReturn = from_glib(ffi::gst_pad_pull_range( self.to_glib_none().0, offset, size, &mut buffer, )); ret.into_result_value(|| from_glib_full(buffer)) } } fn query(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_query( self.to_glib_none().0, query.as_mut_ptr(), )) } } fn peer_query(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_peer_query( self.to_glib_none().0, query.as_mut_ptr(), )) } } fn query_default<'a, P: IsA + 'a, Q: Into>>( &self, parent: Q, query: &mut QueryRef, ) -> bool { skip_assert_initialized!(); let parent = parent.into(); let parent = parent.to_glib_none(); unsafe { from_glib(ffi::gst_pad_query_default( self.to_glib_none().0, parent.0 as *mut _, query.as_mut_ptr(), )) } } fn proxy_query_accept_caps(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_proxy_query_accept_caps( self.to_glib_none().0, query.as_mut_ptr(), )) } } fn proxy_query_caps(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_pad_proxy_query_accept_caps( self.to_glib_none().0, query.as_mut_ptr(), )) } } fn event_default<'a, P: IsA<::Object> + 'a, Q: Into>>( &self, parent: Q, event: Event, ) -> bool { skip_assert_initialized!(); let parent = parent.into(); let parent = parent.to_glib_none(); unsafe { from_glib(ffi::gst_pad_event_default( self.to_glib_none().0, parent.0, event.into_ptr(), )) } } fn push_event(&self, event: Event) -> bool { unsafe { from_glib(ffi::gst_pad_push_event( self.to_glib_none().0, event.into_ptr(), )) } } fn send_event(&self, event: Event) -> bool { unsafe { from_glib(ffi::gst_pad_send_event( self.to_glib_none().0, event.into_ptr(), )) } } fn iterate_internal_links(&self) -> ::Iterator { unsafe { from_glib_full(ffi::gst_pad_iterate_internal_links(self.to_glib_none().0)) } } fn iterate_internal_links_default<'a, P: IsA<::Object> + 'a, Q: Into>>( &self, parent: Q, ) -> ::Iterator { let parent = parent.into(); let parent = parent.to_glib_none(); unsafe { from_glib_full(ffi::gst_pad_iterate_internal_links_default( self.to_glib_none().0, parent.0, )) } } fn stream_lock(&self) -> StreamLock { unsafe { let pad = self.to_glib_none().0; glib_ffi::g_rec_mutex_lock(&mut (*pad).stream_rec_lock); StreamLock(from_glib_none(pad)) } } fn set_activate_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>) -> bool + Send + Sync + 'static, { #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))] unsafe { let func_box: Box) -> bool + Send + Sync + 'static> = Box::new(func); ffi::gst_pad_set_activate_function_full( self.to_glib_none().0, Some(trampoline_activate_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_activatemode_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::PadMode, bool) -> bool + Send + Sync + 'static, { #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))] unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>, ::PadMode, bool) -> bool + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_activatemode_function_full( self.to_glib_none().0, Some(trampoline_activatemode_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_chain_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::Buffer) -> ::FlowReturn + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>, ::Buffer) -> ::FlowReturn + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_chain_function_full( self.to_glib_none().0, Some(trampoline_chain_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_chain_list_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::BufferList) -> ::FlowReturn + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>, ::BufferList) -> ::FlowReturn + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_chain_list_function_full( self.to_glib_none().0, Some(trampoline_chain_list_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_event_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::Event) -> bool + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>, ::Event) -> bool + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_event_function_full( self.to_glib_none().0, Some(trampoline_event_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_event_full_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, ::Event) -> ::FlowReturn + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>, ::Event) -> ::FlowReturn + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_event_full_function_full( self.to_glib_none().0, Some(trampoline_event_full_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_getrange_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, u64, u32) -> Result<::Buffer, ::FlowError> + Send + Sync + 'static, { unsafe { #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))] let func_box: Box< Fn(&Pad, &Option<::Object>, u64, u32) -> Result<::Buffer, ::FlowError> + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_getrange_function_full( self.to_glib_none().0, Some(trampoline_getrange_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_iterate_internal_links_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>) -> ::Iterator + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>) -> ::Iterator + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_iterate_internal_links_function_full( self.to_glib_none().0, Some(trampoline_iterate_internal_links_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_link_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, &Pad) -> ::PadLinkReturn + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>, &Pad) -> ::PadLinkReturn + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_link_function_full( self.to_glib_none().0, Some(trampoline_link_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_query_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>, &mut ::QueryRef) -> bool + Send + Sync + 'static, { unsafe { let func_box: Box< Fn(&Pad, &Option<::Object>, &mut ::QueryRef) -> bool + Send + Sync + 'static, > = Box::new(func); ffi::gst_pad_set_query_function_full( self.to_glib_none().0, Some(trampoline_query_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn set_unlink_function(&self, func: F) where F: Fn(&Pad, &Option<::Object>) + Send + Sync + 'static, { unsafe { let func_box: Box) + Send + Sync + 'static> = Box::new(func); ffi::gst_pad_set_unlink_function_full( self.to_glib_none().0, Some(trampoline_unlink_function), Box::into_raw(Box::new(func_box)) as gpointer, Some(destroy_closure), ); } } fn start_task(&self, func: F) -> Result<(), glib::BoolError> { unsafe { glib_result_from_gboolean!( ffi::gst_pad_start_task( self.to_glib_none().0, Some(trampoline_pad_task), into_raw_pad_task(func), Some(destroy_closure_pad_task), ), "Failed to start pad task", ) } } fn peer_query_convert, U: SpecificFormattedValue>( &self, src_val: V, ) -> Option { let src_val = src_val.into(); unsafe { let mut dest_val = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_peer_query_convert( self.to_glib_none().0, src_val.get_format().to_glib(), src_val.to_raw_value(), U::get_default_format().to_glib(), &mut dest_val, )); if ret { Some(U::from_raw(U::get_default_format(), dest_val)) } else { None } } } fn peer_query_convert_generic>( &self, src_val: V, dest_format: Format, ) -> Option { let src_val = src_val.into(); unsafe { let mut dest_val = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_peer_query_convert( self.to_glib_none().0, src_val.get_format().to_glib(), src_val.to_raw_value(), dest_format.to_glib(), &mut dest_val, )); if ret { Some(GenericFormattedValue::new(dest_format, dest_val)) } else { None } } } fn peer_query_duration(&self) -> Option { unsafe { let mut duration = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_peer_query_duration( self.to_glib_none().0, T::get_default_format().to_glib(), &mut duration, )); if ret { Some(T::from_raw(T::get_default_format(), duration)) } else { None } } } fn peer_query_duration_generic(&self, format: Format) -> Option { unsafe { let mut duration = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_peer_query_duration( self.to_glib_none().0, format.to_glib(), &mut duration, )); if ret { Some(GenericFormattedValue::new(format, duration)) } else { None } } } fn peer_query_position(&self) -> Option { unsafe { let mut cur = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_peer_query_position( self.to_glib_none().0, T::get_default_format().to_glib(), &mut cur, )); if ret { Some(T::from_raw(T::get_default_format(), cur)) } else { None } } } fn peer_query_position_generic(&self, format: Format) -> Option { unsafe { let mut cur = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_peer_query_position( self.to_glib_none().0, format.to_glib(), &mut cur, )); if ret { Some(GenericFormattedValue::new(format, cur)) } else { None } } } fn query_convert, U: SpecificFormattedValue>( &self, src_val: V, ) -> Option { let src_val = src_val.into(); unsafe { let mut dest_val = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_query_convert( self.to_glib_none().0, src_val.get_format().to_glib(), src_val.to_raw_value(), U::get_default_format().to_glib(), &mut dest_val, )); if ret { Some(U::from_raw(U::get_default_format(), dest_val)) } else { None } } } fn query_convert_generic>( &self, src_val: V, dest_format: Format, ) -> Option { let src_val = src_val.into(); unsafe { let mut dest_val = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_query_convert( self.to_glib_none().0, src_val.get_format().to_glib(), src_val.get_value(), dest_format.to_glib(), &mut dest_val, )); if ret { Some(GenericFormattedValue::new(dest_format, dest_val)) } else { None } } } fn query_duration(&self) -> Option { unsafe { let mut duration = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_query_duration( self.to_glib_none().0, T::get_default_format().to_glib(), &mut duration, )); if ret { Some(T::from_raw(T::get_default_format(), duration)) } else { None } } } fn query_duration_generic(&self, format: Format) -> Option { unsafe { let mut duration = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_query_duration( self.to_glib_none().0, format.to_glib(), &mut duration, )); if ret { Some(GenericFormattedValue::new(format, duration)) } else { None } } } fn query_position(&self) -> Option { unsafe { let mut cur = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_query_position( self.to_glib_none().0, T::get_default_format().to_glib(), &mut cur, )); if ret { Some(T::from_raw(T::get_default_format(), cur)) } else { None } } } fn query_position_generic(&self, format: Format) -> Option { unsafe { let mut cur = mem::uninitialized(); let ret = from_glib(ffi::gst_pad_query_position( self.to_glib_none().0, format.to_glib(), &mut cur, )); if ret { Some(GenericFormattedValue::new(format, cur)) } else { None } } } fn get_mode(&self) -> ::PadMode { unsafe { let stash = self.to_glib_none(); let ptr: &ffi::GstPad = &*stash.0; from_glib(ptr.mode) } } fn sticky_events_foreach Result, Option>>( &self, func: F, ) { unsafe extern "C" fn trampoline( _pad: *mut ffi::GstPad, event: *mut *mut ffi::GstEvent, user_data: glib_ffi::gpointer, ) -> glib_ffi::gboolean { let func = user_data as *mut &mut (FnMut(Event) -> Result, Option>); let res = (*func)(from_glib_full(*event)); match res { Ok(Some(ev)) => { *event = ev.into_ptr(); glib_ffi::GTRUE } Err(Some(ev)) => { *event = ev.into_ptr(); glib_ffi::GFALSE } Ok(None) => { *event = ptr::null_mut(); glib_ffi::GTRUE } Err(None) => { *event = ptr::null_mut(); glib_ffi::GFALSE } } } unsafe { let mut func = func; let func_obj: &mut (FnMut(Event) -> Result, Option>) = &mut func; let func_ptr = &func_obj as *const &mut (FnMut(Event) -> Result, Option>) as glib_ffi::gpointer; ffi::gst_pad_sticky_events_foreach(self.to_glib_none().0, Some(trampoline), func_ptr); } } } #[repr(C)] pub struct PadClass(ffi::GstPadClass); unsafe impl IsClassFor for PadClass { type Instance = Pad; } unsafe impl Send for PadClass {} unsafe impl Sync for PadClass {} impl ops::Deref for PadClass { type Target = glib::ObjectClass; fn deref(&self) -> &Self::Target { self.upcast_ref() } } impl ops::DerefMut for PadClass { fn deref_mut(&mut self) -> &mut Self::Target { self.upcast_ref_mut() } } unsafe extern "C" fn trampoline_pad_probe( pad: *mut ffi::GstPad, info: *mut ffi::GstPadProbeInfo, func: gpointer, ) -> ffi::GstPadProbeReturn { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &mut PadProbeInfo) -> PadProbeReturn + Send + Sync + 'static) = transmute(func); let mut data_type = None; let mut probe_info = PadProbeInfo { mask: from_glib((*info).type_), id: PadProbeId((*info).id), offset: (*info).offset, size: (*info).size, data: if (*info).data.is_null() { None } else { let data = (*info).data as *mut ffi::GstMiniObject; (*info).data = ptr::null_mut(); if (*data).type_ == Buffer::static_type().to_glib() { data_type = Some(Buffer::static_type()); Some(PadProbeData::Buffer(from_glib_full( data as *const ffi::GstBuffer, ))) } else if (*data).type_ == BufferList::static_type().to_glib() { data_type = Some(BufferList::static_type()); Some(PadProbeData::BufferList(from_glib_full( data as *const ffi::GstBufferList, ))) } else if (*data).type_ == Query::static_type().to_glib() { data_type = Some(Query::static_type()); Some(PadProbeData::Query(QueryRef::from_mut_ptr( data as *mut ffi::GstQuery, ))) } else if (*data).type_ == Event::static_type().to_glib() { data_type = Some(Event::static_type()); Some(PadProbeData::Event(from_glib_full( data as *const ffi::GstEvent, ))) } else { Some(PadProbeData::__Unknown(data)) } }, }; let ret = func(&from_glib_borrow(pad), &mut probe_info).to_glib(); match probe_info.data { Some(PadProbeData::Buffer(buffer)) => { assert_eq!(data_type, Some(Buffer::static_type())); (*info).data = buffer.into_ptr() as *mut libc::c_void; } Some(PadProbeData::BufferList(bufferlist)) => { assert_eq!(data_type, Some(BufferList::static_type())); (*info).data = bufferlist.into_ptr() as *mut libc::c_void; } Some(PadProbeData::Event(event)) => { assert_eq!(data_type, Some(Event::static_type())); (*info).data = event.into_ptr() as *mut libc::c_void; } Some(PadProbeData::Query(query)) => { assert_eq!(data_type, Some(Query::static_type())); (*info).data = query.as_mut_ptr() as *mut libc::c_void; } Some(PadProbeData::__Unknown(ptr)) => { (*info).data = ptr as *mut libc::c_void; } None => { assert_ne!(data_type, Some(Query::static_type())); } } ret } unsafe extern "C" fn trampoline_activate_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, ) -> glib_ffi::gboolean { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>) -> bool + Send + Sync + 'static) = transmute((*pad).activatedata); func(&from_glib_borrow(pad), &from_glib_borrow(parent)).to_glib() } unsafe extern "C" fn trampoline_activatemode_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, mode: ffi::GstPadMode, active: glib_ffi::gboolean, ) -> glib_ffi::gboolean { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, ::PadMode, bool) -> bool + Send + Sync + 'static) = transmute((*pad).activatemodedata); func( &from_glib_borrow(pad), &from_glib_borrow(parent), from_glib(mode), from_glib(active), ) .to_glib() } unsafe extern "C" fn trampoline_chain_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, buffer: *mut ffi::GstBuffer, ) -> ffi::GstFlowReturn { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, ::Buffer) -> ::FlowReturn + Send + Sync + 'static) = transmute((*pad).chaindata); func( &from_glib_borrow(pad), &from_glib_borrow(parent), from_glib_full(buffer), ) .to_glib() } unsafe extern "C" fn trampoline_chain_list_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, list: *mut ffi::GstBufferList, ) -> ffi::GstFlowReturn { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, ::BufferList) -> ::FlowReturn + Send + Sync + 'static) = transmute((*pad).chainlistdata); func( &from_glib_borrow(pad), &from_glib_borrow(parent), from_glib_full(list), ) .to_glib() } unsafe extern "C" fn trampoline_event_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, event: *mut ffi::GstEvent, ) -> glib_ffi::gboolean { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, ::Event) -> bool + Send + Sync + 'static) = transmute((*pad).eventdata); func( &from_glib_borrow(pad), &from_glib_borrow(parent), from_glib_full(event), ) .to_glib() } unsafe extern "C" fn trampoline_event_full_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, event: *mut ffi::GstEvent, ) -> ffi::GstFlowReturn { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, ::Event) -> ::FlowReturn + Send + Sync + 'static) = transmute((*pad).eventdata); func( &from_glib_borrow(pad), &from_glib_borrow(parent), from_glib_full(event), ) .to_glib() } unsafe extern "C" fn trampoline_getrange_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, offset: u64, length: u32, buffer: *mut *mut ffi::GstBuffer, ) -> ffi::GstFlowReturn { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, u64, u32) -> Result<::Buffer, ::FlowError> + Send + Sync + 'static) = transmute((*pad).getrangedata); match func( &from_glib_borrow(pad), &from_glib_borrow(parent), offset, length, ) { Ok(new_buffer) => { *buffer = new_buffer.into_ptr(); ::FlowReturn::Ok.to_glib() } Err(ret) => ::FlowReturn::from_error(ret).to_glib(), } } unsafe extern "C" fn trampoline_iterate_internal_links_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, ) -> *mut ffi::GstIterator { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>) -> ::Iterator + Send + Sync + 'static) = transmute((*pad).iterintlinkdata); // Steal the iterator and return it let ret = func(&from_glib_borrow(pad), &from_glib_borrow(parent)); let ptr = ret.to_glib_none().0; mem::forget(ret); ptr as *mut _ } unsafe extern "C" fn trampoline_link_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, peer: *mut ffi::GstPad, ) -> ffi::GstPadLinkReturn { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, &::Pad) -> ::PadLinkReturn + Send + Sync + 'static) = transmute((*pad).linkdata); func( &from_glib_borrow(pad), &from_glib_borrow(parent), &from_glib_borrow(peer), ) .to_glib() } unsafe extern "C" fn trampoline_query_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, query: *mut ffi::GstQuery, ) -> glib_ffi::gboolean { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>, &mut ::QueryRef) -> bool + Send + Sync + 'static) = transmute((*pad).querydata); func( &from_glib_borrow(pad), &from_glib_borrow(parent), ::QueryRef::from_mut_ptr(query), ) .to_glib() } unsafe extern "C" fn trampoline_unlink_function( pad: *mut ffi::GstPad, parent: *mut ffi::GstObject, ) { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &&(Fn(&Pad, &Option<::Object>) + Send + Sync + 'static) = transmute((*pad).unlinkdata); func(&from_glib_borrow(pad), &from_glib_borrow(parent)) } unsafe extern "C" fn destroy_closure(ptr: gpointer) { Box::>::from_raw(ptr as *mut _); } unsafe extern "C" fn trampoline_pad_task(func: gpointer) { #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let func: &RefCell> = transmute(func); (&mut *func.borrow_mut())() } unsafe extern "C" fn destroy_closure_pad_task(ptr: gpointer) { Box::>>::from_raw(ptr as *mut _); } fn into_raw_pad_task(func: F) -> gpointer { #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))] let func: Box>> = Box::new(RefCell::new(Box::new(func))); Box::into_raw(func) as gpointer } #[cfg(test)] mod tests { use super::*; use prelude::*; use std::sync::mpsc::channel; use std::sync::{Arc, Mutex}; #[test] fn test_event_chain_functions() { ::init().unwrap(); let pad = ::Pad::new("sink", ::PadDirection::Sink); let events = Arc::new(Mutex::new(Vec::new())); let events_clone = events.clone(); pad.set_event_function(move |_, _, event| { let mut events = events_clone.lock().unwrap(); events.push(event); true }); let buffers = Arc::new(Mutex::new(Vec::new())); let buffers_clone = buffers.clone(); pad.set_chain_function(move |_, _, buffer| { let mut buffers = buffers_clone.lock().unwrap(); buffers.push(buffer); ::FlowReturn::Ok }); pad.set_active(true).unwrap(); assert!(pad.send_event(::Event::new_stream_start("test").build())); let segment = ::FormattedSegment::<::ClockTime>::new(); assert!(pad.send_event(::Event::new_segment(segment.as_ref()).build())); assert_eq!(pad.chain(::Buffer::new()), ::FlowReturn::Ok); let events = events.lock().unwrap(); let buffers = buffers.lock().unwrap(); assert_eq!(events.len(), 2); assert_eq!(buffers.len(), 1); match events[0].view() { ::EventView::StreamStart(..) => (), _ => unreachable!(), } match events[1].view() { ::EventView::Segment(..) => (), _ => unreachable!(), } } #[test] fn test_task() { ::init().unwrap(); let pad = ::Pad::new("sink", ::PadDirection::Sink); let (sender, receiver) = channel(); let mut i = 0; let pad_clone = pad.clone(); pad.start_task(move || { i += 1; if i == 3 { sender.send(i).unwrap(); pad_clone.pause_task().unwrap(); } }) .unwrap(); assert_eq!(receiver.recv().unwrap(), 3); } }