gstreamer_rtsp_server/subclass/
rtsp_media_factory.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::mem::transmute;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{ffi, RTSPMediaFactory};
8
9pub trait RTSPMediaFactoryImpl: RTSPMediaFactoryImplExt + ObjectImpl + Send + Sync {
10    /// convert `url` to a key for caching shared [`RTSPMedia`][crate::RTSPMedia] objects.
11    ///  The default implementation of this function will use the complete URL
12    ///  including the query parameters to return a key.
13    fn gen_key(&self, url: &gst_rtsp::RTSPUrl) -> Option<glib::GString> {
14        self.parent_gen_key(url)
15    }
16
17    /// Construct and return a [`gst::Element`][crate::gst::Element] that is a [`gst::Bin`][crate::gst::Bin] containing
18    /// the elements to use for streaming the media.
19    ///
20    /// The bin should contain payloaders pay\`d` for each stream. The default
21    /// implementation of this function returns the bin created from the
22    /// launch parameter.
23    /// ## `url`
24    /// the url used
25    ///
26    /// # Returns
27    ///
28    /// a new [`gst::Element`][crate::gst::Element].
29    fn create_element(&self, url: &gst_rtsp::RTSPUrl) -> Option<gst::Element> {
30        self.parent_create_element(url)
31    }
32
33    /// Construct the media object and create its streams. Implementations
34    /// should create the needed gstreamer elements and add them to the result
35    /// object. No state changes should be performed on them yet.
36    ///
37    /// One or more GstRTSPStream objects should be created from the result
38    /// with gst_rtsp_media_create_stream ().
39    ///
40    /// After the media is constructed, it can be configured and then prepared
41    /// with gst_rtsp_media_prepare ().
42    ///
43    /// The returned media will be locked and must be unlocked afterwards.
44    /// ## `url`
45    /// the url used
46    ///
47    /// # Returns
48    ///
49    /// a new [`RTSPMedia`][crate::RTSPMedia] if the media could be prepared.
50    fn construct(&self, url: &gst_rtsp::RTSPUrl) -> Option<crate::RTSPMedia> {
51        self.parent_construct(url)
52    }
53
54    /// create a new pipeline or re-use an existing one and
55    ///  add the [`RTSPMedia`][crate::RTSPMedia]'s element created by `construct` to the pipeline.
56    fn create_pipeline(&self, media: &crate::RTSPMedia) -> Option<gst::Pipeline> {
57        self.parent_create_pipeline(media)
58    }
59
60    /// configure the media created with `construct`. The default
61    ///  implementation will configure the 'shared' property of the media.
62    fn configure(&self, media: &crate::RTSPMedia) {
63        self.parent_configure(media)
64    }
65
66    /// signal emitted when a media was constructed
67    fn media_constructed(&self, media: &crate::RTSPMedia) {
68        self.parent_media_constructed(media)
69    }
70
71    /// signal emitted when a media should be configured
72    fn media_configure(&self, media: &crate::RTSPMedia) {
73        self.parent_media_configure(media)
74    }
75}
76
77mod sealed {
78    pub trait Sealed {}
79    impl<T: super::RTSPMediaFactoryImplExt> Sealed for T {}
80}
81
82pub trait RTSPMediaFactoryImplExt: sealed::Sealed + ObjectSubclass {
83    fn parent_gen_key(&self, url: &gst_rtsp::RTSPUrl) -> Option<glib::GString> {
84        unsafe {
85            let data = Self::type_data();
86            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
87            (*parent_class)
88                .gen_key
89                .map(|f| {
90                    from_glib_full(f(
91                        self.obj()
92                            .unsafe_cast_ref::<RTSPMediaFactory>()
93                            .to_glib_none()
94                            .0,
95                        url.to_glib_none().0,
96                    ))
97                })
98                .unwrap_or(None)
99        }
100    }
101
102    fn parent_create_element(&self, url: &gst_rtsp::RTSPUrl) -> Option<gst::Element> {
103        unsafe {
104            let data = Self::type_data();
105            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
106            (*parent_class)
107                .create_element
108                .map(|f| {
109                    from_glib_none(f(
110                        self.obj()
111                            .unsafe_cast_ref::<RTSPMediaFactory>()
112                            .to_glib_none()
113                            .0,
114                        url.to_glib_none().0,
115                    ))
116                })
117                .unwrap_or(None)
118        }
119    }
120
121    fn parent_construct(&self, url: &gst_rtsp::RTSPUrl) -> Option<crate::RTSPMedia> {
122        unsafe {
123            let data = Self::type_data();
124            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
125            (*parent_class)
126                .construct
127                .map(|f| {
128                    from_glib_full(f(
129                        self.obj()
130                            .unsafe_cast_ref::<RTSPMediaFactory>()
131                            .to_glib_none()
132                            .0,
133                        url.to_glib_none().0,
134                    ))
135                })
136                .unwrap_or(None)
137        }
138    }
139
140    fn parent_create_pipeline(&self, media: &crate::RTSPMedia) -> Option<gst::Pipeline> {
141        unsafe {
142            let data = Self::type_data();
143            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
144            (*parent_class)
145                .create_pipeline
146                .map(|f| {
147                    let ptr = f(
148                        self.obj()
149                            .unsafe_cast_ref::<RTSPMediaFactory>()
150                            .to_glib_none()
151                            .0,
152                        media.to_glib_none().0,
153                    ) as *mut gst::ffi::GstPipeline;
154
155                    // See https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/merge_requests/109
156                    if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
157                        glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
158                    }
159                    from_glib_none(ptr)
160                })
161                .unwrap_or(None)
162        }
163    }
164
165    fn parent_configure(&self, media: &crate::RTSPMedia) {
166        unsafe {
167            let data = Self::type_data();
168            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
169            if let Some(f) = (*parent_class).configure {
170                f(
171                    self.obj()
172                        .unsafe_cast_ref::<RTSPMediaFactory>()
173                        .to_glib_none()
174                        .0,
175                    media.to_glib_none().0,
176                );
177            }
178        }
179    }
180
181    fn parent_media_constructed(&self, media: &crate::RTSPMedia) {
182        unsafe {
183            let data = Self::type_data();
184            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
185            if let Some(f) = (*parent_class).media_constructed {
186                f(
187                    self.obj()
188                        .unsafe_cast_ref::<RTSPMediaFactory>()
189                        .to_glib_none()
190                        .0,
191                    media.to_glib_none().0,
192                );
193            }
194        }
195    }
196
197    fn parent_media_configure(&self, media: &crate::RTSPMedia) {
198        unsafe {
199            let data = Self::type_data();
200            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
201            if let Some(f) = (*parent_class).media_configure {
202                f(
203                    self.obj()
204                        .unsafe_cast_ref::<RTSPMediaFactory>()
205                        .to_glib_none()
206                        .0,
207                    media.to_glib_none().0,
208                );
209            }
210        }
211    }
212}
213
214impl<T: RTSPMediaFactoryImpl> RTSPMediaFactoryImplExt for T {}
215unsafe impl<T: RTSPMediaFactoryImpl> IsSubclassable<T> for RTSPMediaFactory {
216    fn class_init(klass: &mut glib::Class<Self>) {
217        Self::parent_class_init::<T>(klass);
218        let klass = klass.as_mut();
219        klass.gen_key = Some(factory_gen_key::<T>);
220        klass.create_element = Some(factory_create_element::<T>);
221        klass.construct = Some(factory_construct::<T>);
222        klass.create_pipeline = Some(factory_create_pipeline::<T>);
223        klass.configure = Some(factory_configure::<T>);
224        klass.media_constructed = Some(factory_media_constructed::<T>);
225        klass.media_configure = Some(factory_media_configure::<T>);
226    }
227}
228
229unsafe extern "C" fn factory_gen_key<T: RTSPMediaFactoryImpl>(
230    ptr: *mut ffi::GstRTSPMediaFactory,
231    url: *const gst_rtsp::ffi::GstRTSPUrl,
232) -> *mut std::os::raw::c_char {
233    let instance = &*(ptr as *mut T::Instance);
234    let imp = instance.imp();
235
236    imp.gen_key(&from_glib_borrow(url)).into_glib_ptr()
237}
238
239unsafe extern "C" fn factory_create_element<T: RTSPMediaFactoryImpl>(
240    ptr: *mut ffi::GstRTSPMediaFactory,
241    url: *const gst_rtsp::ffi::GstRTSPUrl,
242) -> *mut gst::ffi::GstElement {
243    let instance = &*(ptr as *mut T::Instance);
244    let imp = instance.imp();
245
246    let element = imp.create_element(&from_glib_borrow(url)).into_glib_ptr();
247    glib::gobject_ffi::g_object_force_floating(element as *mut _);
248    element
249}
250
251unsafe extern "C" fn factory_construct<T: RTSPMediaFactoryImpl>(
252    ptr: *mut ffi::GstRTSPMediaFactory,
253    url: *const gst_rtsp::ffi::GstRTSPUrl,
254) -> *mut ffi::GstRTSPMedia {
255    let instance = &*(ptr as *mut T::Instance);
256    let imp = instance.imp();
257
258    imp.construct(&from_glib_borrow(url)).into_glib_ptr()
259}
260
261unsafe extern "C" fn factory_create_pipeline<T: RTSPMediaFactoryImpl>(
262    ptr: *mut ffi::GstRTSPMediaFactory,
263    media: *mut ffi::GstRTSPMedia,
264) -> *mut gst::ffi::GstElement {
265    static PIPELINE_QUARK: std::sync::OnceLock<glib::Quark> = std::sync::OnceLock::new();
266
267    let pipeline_quark =
268        PIPELINE_QUARK.get_or_init(|| glib::Quark::from_str("gstreamer-rs-rtsp-media-pipeline"));
269
270    let instance = &*(ptr as *mut T::Instance);
271    let imp = instance.imp();
272
273    let pipeline: *mut gst::ffi::GstPipeline = imp
274        .create_pipeline(&from_glib_borrow(media))
275        .into_glib_ptr();
276
277    // FIXME We somehow need to ensure the pipeline actually stays alive...
278    glib::gobject_ffi::g_object_set_qdata_full(
279        media as *mut _,
280        pipeline_quark.into_glib(),
281        pipeline as *mut _,
282        Some(transmute::<
283            *const (),
284            unsafe extern "C" fn(glib::ffi::gpointer),
285        >(glib::gobject_ffi::g_object_unref as *const ())),
286    );
287
288    pipeline as *mut _
289}
290
291unsafe extern "C" fn factory_configure<T: RTSPMediaFactoryImpl>(
292    ptr: *mut ffi::GstRTSPMediaFactory,
293    media: *mut ffi::GstRTSPMedia,
294) {
295    let instance = &*(ptr as *mut T::Instance);
296    let imp = instance.imp();
297
298    imp.configure(&from_glib_borrow(media));
299}
300
301unsafe extern "C" fn factory_media_constructed<T: RTSPMediaFactoryImpl>(
302    ptr: *mut ffi::GstRTSPMediaFactory,
303    media: *mut ffi::GstRTSPMedia,
304) {
305    let instance = &*(ptr as *mut T::Instance);
306    let imp = instance.imp();
307
308    imp.media_constructed(&from_glib_borrow(media));
309}
310
311unsafe extern "C" fn factory_media_configure<T: RTSPMediaFactoryImpl>(
312    ptr: *mut ffi::GstRTSPMediaFactory,
313    media: *mut ffi::GstRTSPMedia,
314) {
315    let instance = &*(ptr as *mut T::Instance);
316    let imp = instance.imp();
317
318    imp.media_configure(&from_glib_borrow(media));
319}