Skip to main content

gstreamer_rtp/subclass/
rtp_header_extension.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{prelude::*, subclass::prelude::*, translate::*};
4
5use super::prelude::*;
6use crate::RTPHeaderExtension;
7use crate::ffi;
8
9pub trait RTPHeaderExtensionImpl:
10    ElementImpl + ObjectSubclass<Type: IsA<RTPHeaderExtension>>
11{
12    const URI: &'static str;
13
14    /// retrieve the supported flags
15    ///
16    /// # Returns
17    ///
18    /// the flags supported by this instance of `self`
19    fn supported_flags(&self) -> crate::RTPHeaderExtensionFlags {
20        self.parent_supported_flags()
21    }
22
23    /// This is used to know how much data a certain header extension will need for
24    /// both allocating the resulting data, and deciding how much payload data can
25    /// be generated.
26    ///
27    /// Implementations should return as accurate a value as is possible using the
28    /// information given in the input `buffer`.
29    /// ## `input_meta`
30    /// a [`gst::Buffer`][crate::gst::Buffer]
31    ///
32    /// # Returns
33    ///
34    /// the maximum size of the data written by this extension
35    fn max_size(&self, input: &gst::BufferRef) -> usize {
36        self.parent_max_size(input)
37    }
38
39    /// Writes the RTP header extension to `data` using information available from
40    /// the `input_meta`. `data` will be sized to be at least the value returned
41    /// from [`RTPHeaderExtensionExt::max_size()`][crate::prelude::RTPHeaderExtensionExt::max_size()].
42    /// ## `input_meta`
43    /// the input [`gst::Buffer`][crate::gst::Buffer] to read information from if necessary
44    /// ## `write_flags`
45    /// [`RTPHeaderExtensionFlags`][crate::RTPHeaderExtensionFlags] for how the extension should
46    ///  be written
47    /// ## `output`
48    /// output RTP [`gst::Buffer`][crate::gst::Buffer]
49    /// ## `data`
50    /// location to write the rtp header extension into
51    ///
52    /// # Returns
53    ///
54    /// the size of the data written, < 0 on failure
55    fn write(
56        &self,
57        input: &gst::BufferRef,
58        write_flags: crate::RTPHeaderExtensionFlags,
59        output: &gst::BufferRef,
60        output_data: &mut [u8],
61    ) -> Result<usize, gst::LoggableError> {
62        self.parent_write(input, write_flags, output, output_data)
63    }
64
65    /// Read the RTP header extension from `data`.
66    /// ## `read_flags`
67    /// [`RTPHeaderExtensionFlags`][crate::RTPHeaderExtensionFlags] for how the extension should
68    ///  be written
69    /// ## `data`
70    /// location to read the rtp header extension from
71    /// ## `buffer`
72    /// a [`gst::Buffer`][crate::gst::Buffer] to modify if necessary
73    ///
74    /// # Returns
75    ///
76    /// whether the extension could be read from `data`
77    fn read(
78        &self,
79        read_flags: crate::RTPHeaderExtensionFlags,
80        input_data: &[u8],
81        output: &mut gst::BufferRef,
82    ) -> Result<(), gst::LoggableError> {
83        self.parent_read(read_flags, input_data, output)
84    }
85
86    /// Passes RTP payloader's sink (i.e. not payloaded) `caps` to the header
87    /// extension.
88    /// ## `caps`
89    /// sink [`gst::Caps`][crate::gst::Caps]
90    ///
91    /// # Returns
92    ///
93    /// Whether `caps` could be read successfully
94    fn set_non_rtp_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
95        self.parent_set_non_rtp_sink_caps(caps)
96    }
97
98    /// Updates depayloader src caps based on the information received in RTP header.
99    /// `caps` must be writable as this function may modify them.
100    /// ## `caps`
101    /// src [`gst::Caps`][crate::gst::Caps] to modify
102    ///
103    /// # Returns
104    ///
105    /// whether `caps` were modified successfully
106    fn update_non_rtp_src_caps(&self, caps: &mut gst::CapsRef) -> Result<(), gst::LoggableError> {
107        self.parent_update_non_rtp_src_caps(caps)
108    }
109
110    /// set the necessary attributes that may be signaled e.g. with
111    ///  an SDP.
112    fn set_attributes(
113        &self,
114        direction: crate::RTPHeaderExtensionDirection,
115        attributes: &str,
116    ) -> Result<(), gst::LoggableError> {
117        self.parent_set_attributes(direction, attributes)
118    }
119
120    /// [`RTPHeaderExtensionExt::set_id()`][crate::prelude::RTPHeaderExtensionExt::set_id()] must have been called with a valid
121    /// extension id that is contained in these caps.
122    ///
123    /// The only current known caps format is based on the SDP standard as produced
124    /// by `gst_sdp_media_attributes_to_caps()`.
125    /// ## `caps`
126    /// writable [`gst::Caps`][crate::gst::Caps] to modify
127    ///
128    /// # Returns
129    ///
130    /// whether the configured attributes on `self` can successfully be set on
131    ///     `caps`
132    fn set_caps_from_attributes(&self, caps: &mut gst::CapsRef) -> Result<(), gst::LoggableError> {
133        self.parent_set_caps_from_attributes(caps)
134    }
135}
136
137pub trait RTPHeaderExtensionImplExt: RTPHeaderExtensionImpl {
138    fn parent_supported_flags(&self) -> crate::RTPHeaderExtensionFlags {
139        unsafe {
140            let data = Self::type_data();
141            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
142            let f = (*parent_class)
143                .get_supported_flags
144                .expect("no parent \"get_supported_flags\" implementation");
145            from_glib(f(self
146                .obj()
147                .unsafe_cast_ref::<RTPHeaderExtension>()
148                .to_glib_none()
149                .0))
150        }
151    }
152
153    fn parent_max_size(&self, input: &gst::BufferRef) -> usize {
154        unsafe {
155            let data = Self::type_data();
156            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
157            let f = (*parent_class)
158                .get_max_size
159                .expect("no parent \"get_max_size\" implementation");
160            f(
161                self.obj()
162                    .unsafe_cast_ref::<RTPHeaderExtension>()
163                    .to_glib_none()
164                    .0,
165                input.as_ptr(),
166            )
167        }
168    }
169
170    fn parent_write(
171        &self,
172        input: &gst::BufferRef,
173        write_flags: crate::RTPHeaderExtensionFlags,
174        output: &gst::BufferRef,
175        output_data: &mut [u8],
176    ) -> Result<usize, gst::LoggableError> {
177        unsafe {
178            let data = Self::type_data();
179            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
180            let f = (*parent_class)
181                .write
182                .expect("no parent \"write\" implementation");
183
184            let res = f(
185                self.obj()
186                    .unsafe_cast_ref::<RTPHeaderExtension>()
187                    .to_glib_none()
188                    .0,
189                input.as_ptr(),
190                write_flags.into_glib(),
191                mut_override(output.as_ptr()),
192                output_data.as_mut_ptr(),
193                output_data.len(),
194            );
195
196            if res < 0 {
197                Err(gst::loggable_error!(
198                    gst::CAT_RUST,
199                    "Failed to write extension data"
200                ))
201            } else {
202                Ok(res as usize)
203            }
204        }
205    }
206
207    fn parent_read(
208        &self,
209        read_flags: crate::RTPHeaderExtensionFlags,
210        input_data: &[u8],
211        output: &mut gst::BufferRef,
212    ) -> Result<(), gst::LoggableError> {
213        unsafe {
214            let data = Self::type_data();
215            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
216            let f = (*parent_class)
217                .read
218                .expect("no parent \"read\" implementation");
219
220            gst::result_from_gboolean!(
221                f(
222                    self.obj()
223                        .unsafe_cast_ref::<RTPHeaderExtension>()
224                        .to_glib_none()
225                        .0,
226                    read_flags.into_glib(),
227                    input_data.as_ptr(),
228                    input_data.len(),
229                    output.as_mut_ptr(),
230                ),
231                gst::CAT_RUST,
232                "Failed to read extension data",
233            )
234        }
235    }
236
237    fn parent_set_non_rtp_sink_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> {
238        unsafe {
239            let data = Self::type_data();
240            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
241            if let Some(f) = (*parent_class).set_non_rtp_sink_caps {
242                gst::result_from_gboolean!(
243                    f(
244                        self.obj()
245                            .unsafe_cast_ref::<RTPHeaderExtension>()
246                            .to_glib_none()
247                            .0,
248                        caps.as_mut_ptr(),
249                    ),
250                    gst::CAT_RUST,
251                    "Failed to set non-RTP sink caps",
252                )
253            } else {
254                Ok(())
255            }
256        }
257    }
258
259    fn parent_update_non_rtp_src_caps(
260        &self,
261        caps: &mut gst::CapsRef,
262    ) -> Result<(), gst::LoggableError> {
263        unsafe {
264            let data = Self::type_data();
265            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
266            if let Some(f) = (*parent_class).update_non_rtp_src_caps {
267                gst::result_from_gboolean!(
268                    f(
269                        self.obj()
270                            .unsafe_cast_ref::<RTPHeaderExtension>()
271                            .to_glib_none()
272                            .0,
273                        caps.as_mut_ptr(),
274                    ),
275                    gst::CAT_RUST,
276                    "Failed to update non-RTP source caps",
277                )
278            } else {
279                Ok(())
280            }
281        }
282    }
283
284    fn parent_set_attributes(
285        &self,
286        direction: crate::RTPHeaderExtensionDirection,
287        attributes: &str,
288    ) -> Result<(), gst::LoggableError> {
289        unsafe {
290            let data = Self::type_data();
291            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
292            if let Some(f) = (*parent_class).set_attributes {
293                gst::result_from_gboolean!(
294                    f(
295                        self.obj()
296                            .unsafe_cast_ref::<RTPHeaderExtension>()
297                            .to_glib_none()
298                            .0,
299                        direction.into_glib(),
300                        attributes.to_glib_none().0,
301                    ),
302                    gst::CAT_RUST,
303                    "Failed to set attributes",
304                )
305            } else {
306                Ok(())
307            }
308        }
309    }
310
311    fn parent_set_caps_from_attributes(
312        &self,
313        caps: &mut gst::CapsRef,
314    ) -> Result<(), gst::LoggableError> {
315        unsafe {
316            let data = Self::type_data();
317            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTPHeaderExtensionClass;
318            let f = (*parent_class)
319                .set_caps_from_attributes
320                .expect("no parent \"set_caps_from_attributes\" implementation");
321
322            gst::result_from_gboolean!(
323                f(
324                    self.obj()
325                        .unsafe_cast_ref::<RTPHeaderExtension>()
326                        .to_glib_none()
327                        .0,
328                    caps.as_mut_ptr(),
329                ),
330                gst::CAT_RUST,
331                "Failed to set caps from attributes",
332            )
333        }
334    }
335}
336
337impl<T: RTPHeaderExtensionImpl> RTPHeaderExtensionImplExt for T {}
338
339unsafe impl<T: RTPHeaderExtensionImpl> IsSubclassable<T> for RTPHeaderExtension {
340    fn class_init(klass: &mut glib::Class<Self>) {
341        Self::parent_class_init::<T>(klass);
342        let klass = klass.as_mut();
343        klass.get_supported_flags = Some(get_supported_flags::<T>);
344        klass.get_max_size = Some(get_max_size::<T>);
345        klass.write = Some(write::<T>);
346        klass.read = Some(read::<T>);
347        klass.set_non_rtp_sink_caps = Some(set_non_rtp_sink_caps::<T>);
348        klass.update_non_rtp_src_caps = Some(update_non_rtp_src_caps::<T>);
349        klass.set_attributes = Some(set_attributes::<T>);
350        klass.set_caps_from_attributes = Some(set_caps_from_attributes::<T>);
351
352        unsafe {
353            ffi::gst_rtp_header_extension_class_set_uri(&mut *klass, T::URI.to_glib_none().0);
354        }
355    }
356}
357
358unsafe extern "C" fn get_supported_flags<T: RTPHeaderExtensionImpl>(
359    ptr: *mut ffi::GstRTPHeaderExtension,
360) -> ffi::GstRTPHeaderExtensionFlags {
361    unsafe {
362        let instance = &*(ptr as *mut T::Instance);
363        let imp = instance.imp();
364
365        gst::panic_to_error!(imp, crate::RTPHeaderExtensionFlags::empty(), {
366            imp.supported_flags()
367        })
368        .into_glib()
369    }
370}
371
372unsafe extern "C" fn get_max_size<T: RTPHeaderExtensionImpl>(
373    ptr: *mut ffi::GstRTPHeaderExtension,
374    input: *const gst::ffi::GstBuffer,
375) -> usize {
376    unsafe {
377        let instance = &*(ptr as *mut T::Instance);
378        let imp = instance.imp();
379
380        gst::panic_to_error!(imp, 0, { imp.max_size(gst::BufferRef::from_ptr(input)) })
381    }
382}
383
384unsafe extern "C" fn write<T: RTPHeaderExtensionImpl>(
385    ptr: *mut ffi::GstRTPHeaderExtension,
386    input: *const gst::ffi::GstBuffer,
387    write_flags: ffi::GstRTPHeaderExtensionFlags,
388    output: *mut gst::ffi::GstBuffer,
389    output_data: *mut u8,
390    output_data_len: usize,
391) -> isize {
392    unsafe {
393        let instance = &*(ptr as *mut T::Instance);
394        let imp = instance.imp();
395
396        gst::panic_to_error!(imp, -1, {
397            match imp.write(
398                gst::BufferRef::from_ptr(input),
399                from_glib(write_flags),
400                gst::BufferRef::from_ptr(output),
401                if output_data_len == 0 {
402                    &mut []
403                } else {
404                    std::slice::from_raw_parts_mut(output_data, output_data_len)
405                },
406            ) {
407                Ok(len) => len as isize,
408                Err(err) => {
409                    err.log_with_imp(imp);
410                    -1
411                }
412            }
413        })
414    }
415}
416
417unsafe extern "C" fn read<T: RTPHeaderExtensionImpl>(
418    ptr: *mut ffi::GstRTPHeaderExtension,
419    read_flags: ffi::GstRTPHeaderExtensionFlags,
420    input_data: *const u8,
421    input_data_len: usize,
422    output: *mut gst::ffi::GstBuffer,
423) -> glib::ffi::gboolean {
424    unsafe {
425        let instance = &*(ptr as *mut T::Instance);
426        let imp = instance.imp();
427
428        gst::panic_to_error!(imp, false, {
429            match imp.read(
430                from_glib(read_flags),
431                if input_data_len == 0 {
432                    &[]
433                } else {
434                    std::slice::from_raw_parts(input_data, input_data_len)
435                },
436                gst::BufferRef::from_mut_ptr(output),
437            ) {
438                Ok(_) => true,
439                Err(err) => {
440                    err.log_with_imp(imp);
441                    false
442                }
443            }
444        })
445        .into_glib()
446    }
447}
448
449unsafe extern "C" fn set_non_rtp_sink_caps<T: RTPHeaderExtensionImpl>(
450    ptr: *mut ffi::GstRTPHeaderExtension,
451    caps: *mut gst::ffi::GstCaps,
452) -> glib::ffi::gboolean {
453    unsafe {
454        let instance = &*(ptr as *mut T::Instance);
455        let imp = instance.imp();
456
457        gst::panic_to_error!(imp, false, {
458            match imp.set_non_rtp_sink_caps(&from_glib_borrow(caps)) {
459                Ok(_) => true,
460                Err(err) => {
461                    err.log_with_imp(imp);
462                    false
463                }
464            }
465        })
466        .into_glib()
467    }
468}
469
470unsafe extern "C" fn update_non_rtp_src_caps<T: RTPHeaderExtensionImpl>(
471    ptr: *mut ffi::GstRTPHeaderExtension,
472    caps: *mut gst::ffi::GstCaps,
473) -> glib::ffi::gboolean {
474    unsafe {
475        let instance = &*(ptr as *mut T::Instance);
476        let imp = instance.imp();
477
478        gst::panic_to_error!(imp, false, {
479            match imp.update_non_rtp_src_caps(gst::CapsRef::from_mut_ptr(caps)) {
480                Ok(_) => true,
481                Err(err) => {
482                    err.log_with_imp(imp);
483                    false
484                }
485            }
486        })
487        .into_glib()
488    }
489}
490
491unsafe extern "C" fn set_attributes<T: RTPHeaderExtensionImpl>(
492    ptr: *mut ffi::GstRTPHeaderExtension,
493    direction: ffi::GstRTPHeaderExtensionDirection,
494    attributes: *const libc::c_char,
495) -> glib::ffi::gboolean {
496    unsafe {
497        let instance = &*(ptr as *mut T::Instance);
498        let imp = instance.imp();
499
500        gst::panic_to_error!(imp, false, {
501            match imp.set_attributes(
502                from_glib(direction),
503                &glib::GString::from_glib_borrow(attributes),
504            ) {
505                Ok(_) => true,
506                Err(err) => {
507                    err.log_with_imp(imp);
508                    false
509                }
510            }
511        })
512        .into_glib()
513    }
514}
515
516unsafe extern "C" fn set_caps_from_attributes<T: RTPHeaderExtensionImpl>(
517    ptr: *mut ffi::GstRTPHeaderExtension,
518    caps: *mut gst::ffi::GstCaps,
519) -> glib::ffi::gboolean {
520    unsafe {
521        let instance = &*(ptr as *mut T::Instance);
522        let imp = instance.imp();
523
524        gst::panic_to_error!(imp, false, {
525            match imp.set_caps_from_attributes(gst::CapsRef::from_mut_ptr(caps)) {
526                Ok(_) => true,
527                Err(err) => {
528                    err.log_with_imp(imp);
529                    false
530                }
531            }
532        })
533        .into_glib()
534    }
535}