// Take a look at the license at the top of the repository in the LICENSE file. use glib::prelude::*; use glib::subclass::prelude::*; use glib::translate::*; use crate::RTSPMediaFactory; use std::mem::transmute; pub trait RTSPMediaFactoryImpl: RTSPMediaFactoryImplExt + ObjectImpl + Send + Sync { fn gen_key(&self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl) -> Option { self.parent_gen_key(factory, url) } fn create_element( &self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl, ) -> Option { self.parent_create_element(factory, url) } fn construct(&self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl) -> Option { self.parent_construct(factory, url) } fn create_pipeline( &self, factory: &Self::Type, media: &crate::RTSPMedia, ) -> Option { self.parent_create_pipeline(factory, media) } fn configure(&self, factory: &Self::Type, media: &crate::RTSPMedia) { self.parent_configure(factory, media) } fn media_constructed(&self, factory: &Self::Type, media: &crate::RTSPMedia) { self.parent_media_constructed(factory, media) } fn media_configure(&self, factory: &Self::Type, media: &crate::RTSPMedia) { self.parent_media_configure(factory, media) } } pub trait RTSPMediaFactoryImplExt: ObjectSubclass { fn parent_gen_key( &self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl, ) -> Option; fn parent_create_element( &self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl, ) -> Option; fn parent_construct( &self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl, ) -> Option; fn parent_create_pipeline( &self, factory: &Self::Type, media: &crate::RTSPMedia, ) -> Option; fn parent_configure(&self, factory: &Self::Type, media: &crate::RTSPMedia); fn parent_media_constructed(&self, factory: &Self::Type, media: &crate::RTSPMedia); fn parent_media_configure(&self, factory: &Self::Type, media: &crate::RTSPMedia); } impl RTSPMediaFactoryImplExt for T { fn parent_gen_key( &self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl, ) -> Option { unsafe { let data = T::type_data(); let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstRTSPMediaFactoryClass; (*parent_class) .gen_key .map(|f| { from_glib_full(f( factory .unsafe_cast_ref::() .to_glib_none() .0, url.to_glib_none().0, )) }) .unwrap_or(None) } } fn parent_create_element( &self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl, ) -> Option { unsafe { let data = T::type_data(); let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstRTSPMediaFactoryClass; (*parent_class) .create_element .map(|f| { from_glib_none(f( factory .unsafe_cast_ref::() .to_glib_none() .0, url.to_glib_none().0, )) }) .unwrap_or(None) } } fn parent_construct( &self, factory: &Self::Type, url: &gst_rtsp::RTSPUrl, ) -> Option { unsafe { let data = T::type_data(); let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstRTSPMediaFactoryClass; (*parent_class) .construct .map(|f| { from_glib_full(f( factory .unsafe_cast_ref::() .to_glib_none() .0, url.to_glib_none().0, )) }) .unwrap_or(None) } } fn parent_create_pipeline( &self, factory: &Self::Type, media: &crate::RTSPMedia, ) -> Option { unsafe { let data = T::type_data(); let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstRTSPMediaFactoryClass; (*parent_class) .create_pipeline .map(|f| { let ptr = f( factory .unsafe_cast_ref::() .to_glib_none() .0, media.to_glib_none().0, ) as *mut gst::ffi::GstPipeline; // See https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/merge_requests/109 if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE { glib::gobject_ffi::g_object_ref_sink(ptr as *mut _); } from_glib_none(ptr) }) .unwrap_or(None) } } fn parent_configure(&self, factory: &Self::Type, media: &crate::RTSPMedia) { unsafe { let data = T::type_data(); let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstRTSPMediaFactoryClass; if let Some(f) = (*parent_class).configure { f( factory .unsafe_cast_ref::() .to_glib_none() .0, media.to_glib_none().0, ); } } } fn parent_media_constructed(&self, factory: &Self::Type, media: &crate::RTSPMedia) { unsafe { let data = T::type_data(); let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstRTSPMediaFactoryClass; if let Some(f) = (*parent_class).media_constructed { f( factory .unsafe_cast_ref::() .to_glib_none() .0, media.to_glib_none().0, ); } } } fn parent_media_configure(&self, factory: &Self::Type, media: &crate::RTSPMedia) { unsafe { let data = T::type_data(); let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstRTSPMediaFactoryClass; if let Some(f) = (*parent_class).media_configure { f( factory .unsafe_cast_ref::() .to_glib_none() .0, media.to_glib_none().0, ); } } } } unsafe impl IsSubclassable for RTSPMediaFactory { fn override_vfuncs(klass: &mut glib::Class) { >::override_vfuncs(klass); let klass = klass.as_mut(); klass.gen_key = Some(factory_gen_key::); klass.create_element = Some(factory_create_element::); klass.construct = Some(factory_construct::); klass.create_pipeline = Some(factory_create_pipeline::); klass.configure = Some(factory_configure::); klass.media_constructed = Some(factory_media_constructed::); klass.media_configure = Some(factory_media_configure::); } } unsafe extern "C" fn factory_gen_key( ptr: *mut ffi::GstRTSPMediaFactory, url: *const gst_rtsp::ffi::GstRTSPUrl, ) -> *mut std::os::raw::c_char { let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: Borrowed = from_glib_borrow(ptr); imp.gen_key(wrap.unsafe_cast_ref(), &from_glib_borrow(url)) .to_glib_full() } unsafe extern "C" fn factory_create_element( ptr: *mut ffi::GstRTSPMediaFactory, url: *const gst_rtsp::ffi::GstRTSPUrl, ) -> *mut gst::ffi::GstElement { let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: Borrowed = from_glib_borrow(ptr); let element = imp .create_element(wrap.unsafe_cast_ref(), &from_glib_borrow(url)) .to_glib_full(); glib::gobject_ffi::g_object_force_floating(element as *mut _); element } unsafe extern "C" fn factory_construct( ptr: *mut ffi::GstRTSPMediaFactory, url: *const gst_rtsp::ffi::GstRTSPUrl, ) -> *mut ffi::GstRTSPMedia { let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: Borrowed = from_glib_borrow(ptr); imp.construct(wrap.unsafe_cast_ref(), &from_glib_borrow(url)) .to_glib_full() } unsafe extern "C" fn factory_create_pipeline( ptr: *mut ffi::GstRTSPMediaFactory, media: *mut ffi::GstRTSPMedia, ) -> *mut gst::ffi::GstElement { use once_cell::sync::Lazy; static PIPELINE_QUARK: Lazy = Lazy::new(|| glib::Quark::from_string("gstreamer-rs-rtsp-media-pipeline")); let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: Borrowed = from_glib_borrow(ptr); let pipeline: *mut gst::ffi::GstPipeline = imp .create_pipeline(wrap.unsafe_cast_ref(), &from_glib_borrow(media)) .to_glib_full(); // FIXME We somehow need to ensure the pipeline actually stays alive... glib::gobject_ffi::g_object_set_qdata_full( media as *mut _, PIPELINE_QUARK.to_glib(), pipeline as *mut _, Some(transmute::<_, unsafe extern "C" fn(glib::ffi::gpointer)>( glib::gobject_ffi::g_object_unref as *const (), )), ); pipeline as *mut _ } unsafe extern "C" fn factory_configure( ptr: *mut ffi::GstRTSPMediaFactory, media: *mut ffi::GstRTSPMedia, ) { let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: Borrowed = from_glib_borrow(ptr); imp.configure(wrap.unsafe_cast_ref(), &from_glib_borrow(media)); } unsafe extern "C" fn factory_media_constructed( ptr: *mut ffi::GstRTSPMediaFactory, media: *mut ffi::GstRTSPMedia, ) { let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: Borrowed = from_glib_borrow(ptr); imp.media_constructed(wrap.unsafe_cast_ref(), &from_glib_borrow(media)); } unsafe extern "C" fn factory_media_configure( ptr: *mut ffi::GstRTSPMediaFactory, media: *mut ffi::GstRTSPMedia, ) { let instance = &*(ptr as *mut T::Instance); let imp = instance.get_impl(); let wrap: Borrowed = from_glib_borrow(ptr); imp.media_configure(wrap.unsafe_cast_ref(), &from_glib_borrow(media)); }