gstreamer/subclass/
device.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*};
6
7use super::prelude::*;
8use crate::{ffi, Device, Element, LoggableError};
9
10pub trait DeviceImpl: DeviceImplExt + GstObjectImpl + Send + Sync {
11    fn create_element(&self, name: Option<&str>) -> Result<Element, LoggableError> {
12        self.parent_create_element(name)
13    }
14
15    fn reconfigure_element(&self, element: &Element) -> Result<(), LoggableError> {
16        self.parent_reconfigure_element(element)
17    }
18}
19
20mod sealed {
21    pub trait Sealed {}
22    impl<T: super::DeviceImplExt> Sealed for T {}
23}
24
25pub trait DeviceImplExt: sealed::Sealed + ObjectSubclass {
26    fn parent_create_element(&self, name: Option<&str>) -> Result<Element, LoggableError> {
27        unsafe {
28            let data = Self::type_data();
29            let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceClass;
30            if let Some(f) = (*parent_class).create_element {
31                let ptr = f(
32                    self.obj().unsafe_cast_ref::<Device>().to_glib_none().0,
33                    name.to_glib_none().0,
34                );
35
36                // Don't steal floating reference here but pass it further to the caller
37                Option::<_>::from_glib_full(ptr).ok_or_else(|| {
38                    loggable_error!(
39                        crate::CAT_RUST,
40                        "Failed to create element using the parent function"
41                    )
42                })
43            } else {
44                Err(loggable_error!(
45                    crate::CAT_RUST,
46                    "Parent function `create_element` is not defined"
47                ))
48            }
49        }
50    }
51
52    fn parent_reconfigure_element(&self, element: &Element) -> Result<(), LoggableError> {
53        unsafe {
54            let data = Self::type_data();
55            let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceClass;
56            let f = (*parent_class).reconfigure_element.ok_or_else(|| {
57                loggable_error!(
58                    crate::CAT_RUST,
59                    "Parent function `reconfigure_element` is not defined"
60                )
61            })?;
62            result_from_gboolean!(
63                f(
64                    self.obj().unsafe_cast_ref::<Device>().to_glib_none().0,
65                    element.to_glib_none().0
66                ),
67                crate::CAT_RUST,
68                "Failed to reconfigure the element using the parent function"
69            )
70        }
71    }
72}
73
74impl<T: DeviceImpl> DeviceImplExt for T {}
75
76unsafe impl<T: DeviceImpl> IsSubclassable<T> for Device {
77    fn class_init(klass: &mut glib::Class<Self>) {
78        Self::parent_class_init::<T>(klass);
79        let klass = klass.as_mut();
80        klass.create_element = Some(device_create_element::<T>);
81        klass.reconfigure_element = Some(device_reconfigure_element::<T>);
82    }
83}
84
85unsafe extern "C" fn device_create_element<T: DeviceImpl>(
86    ptr: *mut ffi::GstDevice,
87    name: *const libc::c_char,
88) -> *mut ffi::GstElement {
89    let instance = &*(ptr as *mut T::Instance);
90    let imp = instance.imp();
91
92    match imp.create_element(
93        Option::<glib::GString>::from_glib_borrow(name)
94            .as_ref()
95            .as_ref()
96            .map(|s| s.as_str()),
97    ) {
98        Ok(element) => {
99            // The reference we're going to return, the initial reference is going to
100            // be dropped here now
101            let element = element.into_glib_ptr();
102            // See https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/444
103            glib::gobject_ffi::g_object_force_floating(element as *mut glib::gobject_ffi::GObject);
104            element
105        }
106        Err(err) => {
107            err.log_with_imp(imp);
108            ptr::null_mut()
109        }
110    }
111}
112
113unsafe extern "C" fn device_reconfigure_element<T: DeviceImpl>(
114    ptr: *mut ffi::GstDevice,
115    element: *mut ffi::GstElement,
116) -> glib::ffi::gboolean {
117    let instance = &*(ptr as *mut T::Instance);
118    let imp = instance.imp();
119
120    match imp.reconfigure_element(&from_glib_borrow(element)) {
121        Ok(()) => true,
122        Err(err) => {
123            err.log_with_imp(imp);
124            false
125        }
126    }
127    .into_glib()
128}