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