Skip to main content

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::{RTSPMediaFactory, ffi};
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    unsafe {
231        let instance = &*(ptr as *mut T::Instance);
232        let imp = instance.imp();
233
234        imp.gen_key(&from_glib_borrow(url)).into_glib_ptr()
235    }
236}
237
238unsafe extern "C" fn factory_create_element<T: RTSPMediaFactoryImpl>(
239    ptr: *mut ffi::GstRTSPMediaFactory,
240    url: *const gst_rtsp::ffi::GstRTSPUrl,
241) -> *mut gst::ffi::GstElement {
242    unsafe {
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}
251
252unsafe extern "C" fn factory_construct<T: RTSPMediaFactoryImpl>(
253    ptr: *mut ffi::GstRTSPMediaFactory,
254    url: *const gst_rtsp::ffi::GstRTSPUrl,
255) -> *mut ffi::GstRTSPMedia {
256    unsafe {
257        let instance = &*(ptr as *mut T::Instance);
258        let imp = instance.imp();
259
260        imp.construct(&from_glib_borrow(url)).into_glib_ptr()
261    }
262}
263
264unsafe extern "C" fn factory_create_pipeline<T: RTSPMediaFactoryImpl>(
265    ptr: *mut ffi::GstRTSPMediaFactory,
266    media: *mut ffi::GstRTSPMedia,
267) -> *mut gst::ffi::GstElement {
268    unsafe {
269        static PIPELINE_QUARK: std::sync::OnceLock<glib::Quark> = std::sync::OnceLock::new();
270
271        let pipeline_quark = PIPELINE_QUARK
272            .get_or_init(|| glib::Quark::from_str("gstreamer-rs-rtsp-media-pipeline"));
273
274        let instance = &*(ptr as *mut T::Instance);
275        let imp = instance.imp();
276
277        let pipeline: *mut gst::ffi::GstPipeline = imp
278            .create_pipeline(&from_glib_borrow(media))
279            .into_glib_ptr();
280
281        // FIXME We somehow need to ensure the pipeline actually stays alive...
282        glib::gobject_ffi::g_object_set_qdata_full(
283            media as *mut _,
284            pipeline_quark.into_glib(),
285            pipeline as *mut _,
286            Some(transmute::<
287                *const (),
288                unsafe extern "C" fn(glib::ffi::gpointer),
289            >(glib::gobject_ffi::g_object_unref as *const ())),
290        );
291
292        pipeline as *mut _
293    }
294}
295
296unsafe extern "C" fn factory_configure<T: RTSPMediaFactoryImpl>(
297    ptr: *mut ffi::GstRTSPMediaFactory,
298    media: *mut ffi::GstRTSPMedia,
299) {
300    unsafe {
301        let instance = &*(ptr as *mut T::Instance);
302        let imp = instance.imp();
303
304        imp.configure(&from_glib_borrow(media));
305    }
306}
307
308unsafe extern "C" fn factory_media_constructed<T: RTSPMediaFactoryImpl>(
309    ptr: *mut ffi::GstRTSPMediaFactory,
310    media: *mut ffi::GstRTSPMedia,
311) {
312    unsafe {
313        let instance = &*(ptr as *mut T::Instance);
314        let imp = instance.imp();
315
316        imp.media_constructed(&from_glib_borrow(media));
317    }
318}
319
320unsafe extern "C" fn factory_media_configure<T: RTSPMediaFactoryImpl>(
321    ptr: *mut ffi::GstRTSPMediaFactory,
322    media: *mut ffi::GstRTSPMedia,
323) {
324    unsafe {
325        let instance = &*(ptr as *mut T::Instance);
326        let imp = instance.imp();
327
328        imp.media_configure(&from_glib_borrow(media));
329    }
330}