diff --git a/gstreamer/src/subclass/device.rs b/gstreamer/src/subclass/device.rs new file mode 100644 index 000000000..f05c99b82 --- /dev/null +++ b/gstreamer/src/subclass/device.rs @@ -0,0 +1,141 @@ +// Copyright (C) 2019 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use glib_sys; +use gst_sys; + +use glib::translate::*; + +use glib::subclass::prelude::*; + +use Device; +use DeviceClass; +use Element; +use LoggableError; + +use std::ptr; + +pub trait DeviceImpl: DeviceImplExt + ObjectImpl + Send + Sync + 'static { + fn create_element(&self, device: &Device, name: Option<&str>) -> Option { + self.parent_create_element(device, name) + } + + fn reconfigure_element(&self, device: &Device, element: &Element) -> Result<(), LoggableError> { + self.parent_reconfigure_element(device, element) + } +} + +pub trait DeviceImplExt { + fn parent_create_element(&self, device: &Device, name: Option<&str>) -> Option; + + fn parent_reconfigure_element( + &self, + device: &Device, + element: &Element, + ) -> Result<(), LoggableError>; +} + +impl DeviceImplExt for T { + fn parent_create_element(&self, device: &Device, name: Option<&str>) -> Option { + unsafe { + let data = self.get_type_data(); + let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstDeviceClass; + if let Some(f) = (*parent_class).create_element { + from_glib_none(f(device.to_glib_none().0, name.to_glib_none().0)) + } else { + None + } + } + } + + fn parent_reconfigure_element( + &self, + device: &Device, + element: &Element, + ) -> Result<(), LoggableError> { + unsafe { + let data = self.get_type_data(); + let parent_class = data.as_ref().get_parent_class() as *mut gst_sys::GstDeviceClass; + let f = (*parent_class).reconfigure_element.ok_or_else(|| { + gst_loggable_error!( + ::CAT_RUST, + "Parent function `reconfigure_element` is not defined" + ) + })?; + gst_result_from_gboolean!( + f(device.to_glib_none().0, element.to_glib_none().0), + ::CAT_RUST, + "Failed to reconfigure the element using the parent function" + ) + } + } +} + +unsafe impl IsSubclassable for DeviceClass { + fn override_vfuncs(&mut self) { + >::override_vfuncs(self); + unsafe { + let klass = &mut *(self as *mut Self as *mut gst_sys::GstDeviceClass); + klass.create_element = Some(device_create_element::); + klass.reconfigure_element = Some(device_reconfigure_element::); + } + } +} + +unsafe extern "C" fn device_create_element( + ptr: *mut gst_sys::GstDevice, + name: *const libc::c_char, +) -> *mut gst_sys::GstElement +where + T: DeviceImpl, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Device = from_glib_borrow(ptr); + + match imp.create_element( + &wrap, + Option::::from_glib_borrow(name) + .as_ref() + .map(|s| s.as_str()), + ) { + Some(element) => { + // The reference we're going to return, the initial reference is going to + // be dropped here now + let element_ptr = element.to_glib_full(); + drop(element); + // See https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/444 + gobject_sys::g_object_force_floating(element_ptr as *mut gobject_sys::GObject); + element_ptr + } + None => ptr::null_mut(), + } +} + +unsafe extern "C" fn device_reconfigure_element( + ptr: *mut gst_sys::GstDevice, + element: *mut gst_sys::GstElement, +) -> glib_sys::gboolean +where + T: DeviceImpl, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Device = from_glib_borrow(ptr); + + match imp.reconfigure_element(&wrap, &from_glib_borrow(element)) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&wrap); + false + } + } + .to_glib() +} diff --git a/gstreamer/src/subclass/mod.rs b/gstreamer/src/subclass/mod.rs index c6343ae68..4ebdeaea5 100644 --- a/gstreamer/src/subclass/mod.rs +++ b/gstreamer/src/subclass/mod.rs @@ -27,11 +27,15 @@ pub mod element; pub mod ghost_pad; pub mod pad; pub mod pipeline; + +pub mod device; + pub mod uri_handler; pub mod prelude { pub use super::bin::{BinImpl, BinImplExt}; pub use super::child_proxy::ChildProxyImpl; + pub use super::device::{DeviceImpl, DeviceImplExt}; pub use super::element::{ElementClassSubclassExt, ElementImpl, ElementImplExt}; pub use super::ghost_pad::GhostPadImpl; pub use super::pad::{PadImpl, PadImplExt};