From 0d338a003e7cec70594f3d3b209ac3422d2a5a95 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Fri, 28 Aug 2020 20:30:46 +0200 Subject: [PATCH] gl/gl_filter: Add GLFilterImpl with configurable filter/filter_texture GLFilter should override either .filter() or .filter_texture(), not both. This allows an implementer to pick at runtime what function is overridden. --- gstreamer-gl/src/subclass/gl_filter.rs | 364 +++++++++++++++++++++++++ gstreamer-gl/src/subclass/mod.rs | 4 + 2 files changed, 368 insertions(+) create mode 100644 gstreamer-gl/src/subclass/gl_filter.rs diff --git a/gstreamer-gl/src/subclass/gl_filter.rs b/gstreamer-gl/src/subclass/gl_filter.rs new file mode 100644 index 000000000..58a6ee98f --- /dev/null +++ b/gstreamer-gl/src/subclass/gl_filter.rs @@ -0,0 +1,364 @@ +use ffi::{GstGLFilter, GstGLFilterClass, GstGLMemory}; +use gst::ffi::GstBuffer; + +use super::prelude::*; +use crate::prelude::*; + +use glib::translate::*; + +use gst::subclass::prelude::*; +use gst::{result_from_gboolean, Buffer, Caps, LoggableError, PadDirection, CAT_RUST}; + +use crate::GLBaseFilter; +use crate::GLFilter; +use crate::GLMemory; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum GLFilterMode { + Buffer, + Texture, +} + +pub trait GLFilterImpl: GLFilterImplExt + GLBaseFilterImpl { + const MODE: GLFilterMode; + + fn set_caps( + &self, + filter: &Self::Type, + incaps: &Caps, + outcaps: &Caps, + ) -> Result<(), LoggableError> { + GLFilterImplExt::parent_set_caps(self, filter, incaps, outcaps) + } + + fn filter( + &self, + filter: &Self::Type, + input: &Buffer, + output: &Buffer, + ) -> Result<(), LoggableError> { + self.parent_filter(filter, input, output) + } + + fn filter_texture( + &self, + filter: &Self::Type, + input: &GLMemory, + output: &GLMemory, + ) -> Result<(), LoggableError> { + self.parent_filter_texture(filter, input, output) + } + + fn init_fbo(&self, filter: &Self::Type) -> Result<(), LoggableError> { + self.parent_init_fbo(filter) + } + + fn transform_internal_caps( + &self, + filter: &Self::Type, + direction: PadDirection, + caps: &Caps, + filter_caps: Option<&Caps>, + ) -> Option { + self.parent_transform_internal_caps(filter, direction, caps, filter_caps) + } +} + +pub trait GLFilterImplExt: ObjectSubclass { + fn parent_set_caps( + &self, + filter: &Self::Type, + incaps: &Caps, + outcaps: &Caps, + ) -> Result<(), LoggableError>; + + fn parent_filter( + &self, + filter: &Self::Type, + input: &Buffer, + output: &Buffer, + ) -> Result<(), LoggableError>; + + fn parent_filter_texture( + &self, + filter: &Self::Type, + input: &GLMemory, + output: &GLMemory, + ) -> Result<(), LoggableError>; + + fn parent_init_fbo(&self, filter: &Self::Type) -> Result<(), LoggableError>; + + fn parent_transform_internal_caps( + &self, + filter: &Self::Type, + direction: PadDirection, + caps: &Caps, + filter_caps: Option<&Caps>, + ) -> Option; +} + +impl GLFilterImplExt for T { + fn parent_set_caps( + &self, + filter: &Self::Type, + incaps: &Caps, + outcaps: &Caps, + ) -> Result<(), LoggableError> { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass; + + (*parent_class) + .set_caps + .map(|f| { + result_from_gboolean!( + f( + filter.unsafe_cast_ref::().to_glib_none().0, + incaps.to_glib_none().0, + outcaps.to_glib_none().0, + ), + CAT_RUST, + "Parent function `set_caps` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + + fn parent_filter( + &self, + filter: &Self::Type, + input: &Buffer, + output: &Buffer, + ) -> Result<(), LoggableError> { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass; + + (*parent_class) + .filter + .map(|f| { + result_from_gboolean!( + f( + filter.unsafe_cast_ref::().to_glib_none().0, + input.to_glib_none().0, + output.to_glib_none().0, + ), + CAT_RUST, + "Parent function `filter` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + + fn parent_filter_texture( + &self, + filter: &Self::Type, + input: &GLMemory, + output: &GLMemory, + ) -> Result<(), LoggableError> { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass; + + (*parent_class) + .filter_texture + .map(|f| { + result_from_gboolean!( + f( + filter.unsafe_cast_ref::().to_glib_none().0, + input.to_glib_none().0, + output.to_glib_none().0, + ), + CAT_RUST, + "Parent function `filter_texture` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + + fn parent_init_fbo(&self, filter: &Self::Type) -> Result<(), LoggableError> { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass; + + (*parent_class) + .init_fbo + .map(|f| { + result_from_gboolean!( + f(filter.unsafe_cast_ref::().to_glib_none().0), + CAT_RUST, + "Parent function `init_fbo` failed" + ) + }) + .unwrap_or(Ok(())) + } + } + fn parent_transform_internal_caps( + &self, + filter: &Self::Type, + direction: PadDirection, + caps: &Caps, + filter_caps: Option<&Caps>, + ) -> Option { + unsafe { + let data = T::type_data(); + let parent_class = data.as_ref().parent_class() as *mut GstGLFilterClass; + + let f = (*parent_class) + .transform_internal_caps + .expect("Missing parent function `transform_internal_caps`"); + + from_glib_full(f( + filter.unsafe_cast_ref::().to_glib_none().0, + direction.to_glib(), + caps.to_glib_none().0, + filter_caps.to_glib_none().0, + )) + } + } +} + +unsafe impl IsSubclassable for GLFilter { + fn class_init(klass: &mut glib::Class) { + >::class_init(klass); + let klass = klass.as_mut(); + klass.set_caps = Some(set_caps::); + klass.init_fbo = Some(init_fbo::); + klass.transform_internal_caps = Some(transform_internal_caps::); + + match ::MODE { + GLFilterMode::Buffer => { + klass.filter = Some(filter::); + klass.filter_texture = None; + } + GLFilterMode::Texture => { + klass.filter = None; + klass.filter_texture = Some(filter_texture::); + } + } + } + + fn instance_init(instance: &mut glib::subclass::InitializingObject) { + >::instance_init(instance) + } +} + +unsafe extern "C" fn filter( + ptr: *mut GstGLFilter, + input: *mut GstBuffer, + output: *mut GstBuffer, +) -> glib::ffi::gboolean { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.impl_(); + let wrap: Borrowed = from_glib_borrow(ptr); + + gst::panic_to_error!(&wrap, &imp.panicked(), false, { + match imp.filter( + wrap.unsafe_cast_ref(), + &from_glib_borrow(input), + &from_glib_borrow(output), + ) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&*wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn filter_texture( + ptr: *mut GstGLFilter, + input: *mut GstGLMemory, + output: *mut GstGLMemory, +) -> glib::ffi::gboolean { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.impl_(); + let wrap: Borrowed = from_glib_borrow(ptr); + + gst::panic_to_error!(&wrap, &imp.panicked(), false, { + match imp.filter_texture( + wrap.unsafe_cast_ref(), + &from_glib_borrow(input), + &from_glib_borrow(output), + ) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&*wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn init_fbo(ptr: *mut GstGLFilter) -> glib::ffi::gboolean { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.impl_(); + let wrap: Borrowed = from_glib_borrow(ptr); + + gst::panic_to_error!(&wrap, &imp.panicked(), false, { + match imp.init_fbo(wrap.unsafe_cast_ref()) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&*wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn set_caps( + ptr: *mut GstGLFilter, + incaps: *mut gst::ffi::GstCaps, + outcaps: *mut gst::ffi::GstCaps, +) -> glib::ffi::gboolean { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.impl_(); + let wrap: Borrowed = from_glib_borrow(ptr); + + gst::panic_to_error!(&wrap, &imp.panicked(), false, { + match GLFilterImpl::set_caps( + imp, + wrap.unsafe_cast_ref(), + &from_glib_borrow(incaps), + &from_glib_borrow(outcaps), + ) { + Ok(()) => true, + Err(err) => { + err.log_with_object(&*wrap); + false + } + } + }) + .to_glib() +} + +unsafe extern "C" fn transform_internal_caps( + ptr: *mut GstGLFilter, + direction: gst::ffi::GstPadDirection, + caps: *mut gst::ffi::GstCaps, + filter_caps: *mut gst::ffi::GstCaps, +) -> *mut gst::ffi::GstCaps { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.impl_(); + let wrap: Borrowed = from_glib_borrow(ptr); + + gst::panic_to_error!(&wrap, &imp.panicked(), None, { + let filter_caps: Borrowed> = from_glib_borrow(filter_caps); + + imp.transform_internal_caps( + wrap.unsafe_cast_ref(), + from_glib(direction), + &from_glib_borrow(caps), + filter_caps.as_ref().as_ref(), + ) + }) + .map(|caps| caps.into_ptr()) + .unwrap_or(std::ptr::null_mut()) +} diff --git a/gstreamer-gl/src/subclass/mod.rs b/gstreamer-gl/src/subclass/mod.rs index 5c165539f..ed0c8b9af 100644 --- a/gstreamer-gl/src/subclass/mod.rs +++ b/gstreamer-gl/src/subclass/mod.rs @@ -1,5 +1,9 @@ mod gl_base_filter; +mod gl_filter; + +pub use self::gl_filter::GLFilterMode; pub mod prelude { pub use super::gl_base_filter::{GLBaseFilterImpl, GLBaseFilterImplExt}; + pub use super::gl_filter::{GLFilterImpl, GLFilterImplExt}; }