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 and assign it to media.
57    /// ## `media`
58    /// a [`RTSPMedia`][crate::RTSPMedia]
59    ///
60    /// # Returns
61    ///
62    /// the [`gst::Element`][crate::gst::Element] pipeline.
63    fn create_pipeline(&self, media: &crate::RTSPMedia) -> Option<gst::Pipeline> {
64        self.parent_create_pipeline(media)
65    }
66
67    /// configure the media created with `construct`. The default
68    ///  implementation will configure the 'shared' property of the media.
69    fn configure(&self, media: &crate::RTSPMedia) {
70        self.parent_configure(media)
71    }
72
73    /// signal emitted when a media was constructed
74    fn media_constructed(&self, media: &crate::RTSPMedia) {
75        self.parent_media_constructed(media)
76    }
77
78    /// signal emitted when a media should be configured
79    fn media_configure(&self, media: &crate::RTSPMedia) {
80        self.parent_media_configure(media)
81    }
82}
83
84pub trait RTSPMediaFactoryImplExt: RTSPMediaFactoryImpl {
85    fn parent_gen_key(&self, url: &gst_rtsp::RTSPUrl) -> Option<glib::GString> {
86        unsafe {
87            let data = Self::type_data();
88            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
89            (*parent_class)
90                .gen_key
91                .map(|f| {
92                    from_glib_full(f(
93                        self.obj()
94                            .unsafe_cast_ref::<RTSPMediaFactory>()
95                            .to_glib_none()
96                            .0,
97                        url.to_glib_none().0,
98                    ))
99                })
100                .unwrap_or(None)
101        }
102    }
103
104    fn parent_create_element(&self, url: &gst_rtsp::RTSPUrl) -> Option<gst::Element> {
105        unsafe {
106            let data = Self::type_data();
107            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
108            (*parent_class)
109                .create_element
110                .map(|f| {
111                    from_glib_none(f(
112                        self.obj()
113                            .unsafe_cast_ref::<RTSPMediaFactory>()
114                            .to_glib_none()
115                            .0,
116                        url.to_glib_none().0,
117                    ))
118                })
119                .unwrap_or(None)
120        }
121    }
122
123    fn parent_construct(&self, url: &gst_rtsp::RTSPUrl) -> Option<crate::RTSPMedia> {
124        unsafe {
125            let data = Self::type_data();
126            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
127            (*parent_class)
128                .construct
129                .map(|f| {
130                    from_glib_full(f(
131                        self.obj()
132                            .unsafe_cast_ref::<RTSPMediaFactory>()
133                            .to_glib_none()
134                            .0,
135                        url.to_glib_none().0,
136                    ))
137                })
138                .unwrap_or(None)
139        }
140    }
141
142    fn parent_create_pipeline(&self, media: &crate::RTSPMedia) -> Option<gst::Pipeline> {
143        unsafe {
144            let data = Self::type_data();
145            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
146            (*parent_class)
147                .create_pipeline
148                .map(|f| {
149                    let ptr = f(
150                        self.obj()
151                            .unsafe_cast_ref::<RTSPMediaFactory>()
152                            .to_glib_none()
153                            .0,
154                        media.to_glib_none().0,
155                    ) as *mut gst::ffi::GstPipeline;
156
157                    // See https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/merge_requests/109
158                    if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
159                        glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
160                    }
161                    from_glib_none(ptr)
162                })
163                .unwrap_or(None)
164        }
165    }
166
167    fn parent_configure(&self, media: &crate::RTSPMedia) {
168        unsafe {
169            let data = Self::type_data();
170            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
171            if let Some(f) = (*parent_class).configure {
172                f(
173                    self.obj()
174                        .unsafe_cast_ref::<RTSPMediaFactory>()
175                        .to_glib_none()
176                        .0,
177                    media.to_glib_none().0,
178                );
179            }
180        }
181    }
182
183    fn parent_media_constructed(&self, media: &crate::RTSPMedia) {
184        unsafe {
185            let data = Self::type_data();
186            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
187            if let Some(f) = (*parent_class).media_constructed {
188                f(
189                    self.obj()
190                        .unsafe_cast_ref::<RTSPMediaFactory>()
191                        .to_glib_none()
192                        .0,
193                    media.to_glib_none().0,
194                );
195            }
196        }
197    }
198
199    fn parent_media_configure(&self, media: &crate::RTSPMedia) {
200        unsafe {
201            let data = Self::type_data();
202            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaFactoryClass;
203            if let Some(f) = (*parent_class).media_configure {
204                f(
205                    self.obj()
206                        .unsafe_cast_ref::<RTSPMediaFactory>()
207                        .to_glib_none()
208                        .0,
209                    media.to_glib_none().0,
210                );
211            }
212        }
213    }
214}
215
216impl<T: RTSPMediaFactoryImpl> RTSPMediaFactoryImplExt for T {}
217unsafe impl<T: RTSPMediaFactoryImpl> IsSubclassable<T> for RTSPMediaFactory {
218    fn class_init(klass: &mut glib::Class<Self>) {
219        Self::parent_class_init::<T>(klass);
220        let klass = klass.as_mut();
221        klass.gen_key = Some(factory_gen_key::<T>);
222        klass.create_element = Some(factory_create_element::<T>);
223        klass.construct = Some(factory_construct::<T>);
224        klass.create_pipeline = Some(factory_create_pipeline::<T>);
225        klass.configure = Some(factory_configure::<T>);
226        klass.media_constructed = Some(factory_media_constructed::<T>);
227        klass.media_configure = Some(factory_media_configure::<T>);
228    }
229}
230
231unsafe extern "C" fn factory_gen_key<T: RTSPMediaFactoryImpl>(
232    ptr: *mut ffi::GstRTSPMediaFactory,
233    url: *const gst_rtsp::ffi::GstRTSPUrl,
234) -> *mut std::ffi::c_char {
235    unsafe {
236        let instance = &*(ptr as *mut T::Instance);
237        let imp = instance.imp();
238
239        imp.gen_key(&from_glib_borrow(url)).into_glib_ptr()
240    }
241}
242
243unsafe extern "C" fn factory_create_element<T: RTSPMediaFactoryImpl>(
244    ptr: *mut ffi::GstRTSPMediaFactory,
245    url: *const gst_rtsp::ffi::GstRTSPUrl,
246) -> *mut gst::ffi::GstElement {
247    unsafe {
248        let instance = &*(ptr as *mut T::Instance);
249        let imp = instance.imp();
250
251        let element = imp.create_element(&from_glib_borrow(url)).into_glib_ptr();
252        glib::gobject_ffi::g_object_force_floating(element as *mut _);
253        element
254    }
255}
256
257unsafe extern "C" fn factory_construct<T: RTSPMediaFactoryImpl>(
258    ptr: *mut ffi::GstRTSPMediaFactory,
259    url: *const gst_rtsp::ffi::GstRTSPUrl,
260) -> *mut ffi::GstRTSPMedia {
261    unsafe {
262        let instance = &*(ptr as *mut T::Instance);
263        let imp = instance.imp();
264
265        imp.construct(&from_glib_borrow(url)).into_glib_ptr()
266    }
267}
268
269unsafe extern "C" fn factory_create_pipeline<T: RTSPMediaFactoryImpl>(
270    ptr: *mut ffi::GstRTSPMediaFactory,
271    media: *mut ffi::GstRTSPMedia,
272) -> *mut gst::ffi::GstElement {
273    unsafe {
274        static PIPELINE_QUARK: std::sync::OnceLock<glib::Quark> = std::sync::OnceLock::new();
275
276        let pipeline_quark = PIPELINE_QUARK
277            .get_or_init(|| glib::Quark::from_str("gstreamer-rs-rtsp-media-pipeline"));
278
279        let instance = &*(ptr as *mut T::Instance);
280        let imp = instance.imp();
281
282        let pipeline: *mut gst::ffi::GstPipeline = imp
283            .create_pipeline(&from_glib_borrow(media))
284            .into_glib_ptr();
285
286        // FIXME We somehow need to ensure the pipeline actually stays alive...
287        glib::gobject_ffi::g_object_set_qdata_full(
288            media as *mut _,
289            pipeline_quark.into_glib(),
290            pipeline as *mut _,
291            Some(transmute::<
292                *const (),
293                unsafe extern "C" fn(glib::ffi::gpointer),
294            >(glib::gobject_ffi::g_object_unref as *const ())),
295        );
296
297        pipeline as *mut _
298    }
299}
300
301unsafe extern "C" fn factory_configure<T: RTSPMediaFactoryImpl>(
302    ptr: *mut ffi::GstRTSPMediaFactory,
303    media: *mut ffi::GstRTSPMedia,
304) {
305    unsafe {
306        let instance = &*(ptr as *mut T::Instance);
307        let imp = instance.imp();
308
309        imp.configure(&from_glib_borrow(media));
310    }
311}
312
313unsafe extern "C" fn factory_media_constructed<T: RTSPMediaFactoryImpl>(
314    ptr: *mut ffi::GstRTSPMediaFactory,
315    media: *mut ffi::GstRTSPMedia,
316) {
317    unsafe {
318        let instance = &*(ptr as *mut T::Instance);
319        let imp = instance.imp();
320
321        imp.media_constructed(&from_glib_borrow(media));
322    }
323}
324
325unsafe extern "C" fn factory_media_configure<T: RTSPMediaFactoryImpl>(
326    ptr: *mut ffi::GstRTSPMediaFactory,
327    media: *mut ffi::GstRTSPMedia,
328) {
329    unsafe {
330        let instance = &*(ptr as *mut T::Instance);
331        let imp = instance.imp();
332
333        imp.media_configure(&from_glib_borrow(media));
334    }
335}