diff --git a/gst-plugin/src/bin.rs b/gst-plugin/src/bin.rs new file mode 100644 index 00000000..7e73cccb --- /dev/null +++ b/gst-plugin/src/bin.rs @@ -0,0 +1,208 @@ +// Copyright (C) 2017 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 std::ptr; +use std::mem; + +use glib_ffi; +use gobject_ffi; +use gst_ffi; + +use glib; +use glib::translate::*; +use gst; +use gst::prelude::*; + +use object::*; +use element::*; +use anyimpl::*; + +pub trait BinImpl + : AnyImpl + ObjectImpl + ElementImpl + Send + Sync + 'static { + fn add_element(&self, bin: &T, element: &gst::Element) -> bool { + bin.parent_add_element(element) + } + + fn remove_element(&self, bin: &T, element: &gst::Element) -> bool { + bin.parent_remove_element(element) + } + + fn handle_message(&self, bin: &T, message: gst::Message) { + bin.parent_handle_message(message) + } +} + +any_impl!(BinBase, BinImpl); + +pub unsafe trait BinBase: IsA + IsA + ObjectType { + fn parent_add_element(&self, element: &gst::Element) -> bool { + unsafe { + let klass = self.get_class(); + let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstBinClass; + (*parent_klass) + .add_element + .map(|f| { + from_glib(f(self.to_glib_none().0, element.to_glib_none().0)) + }) + .unwrap_or(false) + } + } + + fn parent_remove_element(&self, element: &gst::Element) -> bool { + unsafe { + let klass = self.get_class(); + let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstBinClass; + (*parent_klass) + .remove_element + .map(|f| { + from_glib(f(self.to_glib_none().0, element.to_glib_none().0)) + }) + .unwrap_or(false) + } + } + + fn parent_handle_message(&self, message: gst::Message) { + unsafe { + let klass = self.get_class(); + let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstBinClass; + (*parent_klass) + .handle_message + .map(move |f| f(self.to_glib_none().0, message.into_ptr())); + } + } +} + +pub unsafe trait BinClassExt +where + T::ImplType: BinImpl, +{ + fn override_vfuncs(&mut self, _: &ClassInitToken) { + unsafe { + let klass = &mut *(self as *const Self as *mut gst_ffi::GstBinClass); + klass.add_element = Some(bin_add_element::); + klass.remove_element = Some(bin_remove_element::); + klass.handle_message = Some(bin_handle_message::); + } + } +} + +glib_wrapper! { + pub struct Bin(Object>): [gst::Bin => gst_ffi::GstBin, + gst::Element => gst_ffi::GstElement, + gst::Object => gst_ffi::GstObject, + gst::ChildProxy => gst_ffi::GstChildProxy]; + + match fn { + get_type => || get_type::(), + } +} + +unsafe impl + IsA + ObjectType> BinBase for T {} +pub type BinClass = ClassStruct; + +// FIXME: Boilerplate +unsafe impl BinClassExt for BinClass {} +unsafe impl ElementClassExt for BinClass {} + +#[macro_export] +macro_rules! box_bin_impl( + ($name:ident) => { + box_element_impl!($name); + + impl BinImpl for Box<$name> { + fn add_element(&self, bin: &T, element: &gst::Element) -> bool { + let imp: &$name = self.as_ref(); + imp.add_element(bin, element) + } + + fn remove_element(&self, bin: &T, element: &gst::Element) -> bool { + let imp: &$name = self.as_ref(); + imp.remove_element(bin, element) + } + + fn handle_message(&self, bin: &T, message: gst::Message) { + let imp: &$name = self.as_ref(); + imp.handle_message(bin, message) + } + } + }; +); +box_bin_impl!(BinImpl); + +impl ObjectType for Bin { + const NAME: &'static str = "RsBin"; + type GlibType = gst_ffi::GstBin; + type GlibClassType = gst_ffi::GstBinClass; + type ImplType = Box>; + + fn glib_type() -> glib::Type { + unsafe { from_glib(gst_ffi::gst_bin_get_type()) } + } + + fn class_init(token: &ClassInitToken, klass: &mut BinClass) { + ElementClassExt::override_vfuncs(klass, token); + BinClassExt::override_vfuncs(klass, token); + } + + object_type_fns!(); +} + +unsafe extern "C" fn bin_add_element( + ptr: *mut gst_ffi::GstBin, + element: *mut gst_ffi::GstElement, +) -> glib_ffi::gboolean +where + T::ImplType: BinImpl, +{ + callback_guard!(); + floating_reference_guard!(ptr); + floating_reference_guard!(element); + let bin = &*(ptr as *mut InstanceStruct); + let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct); + let imp = &*bin.imp; + + panic_to_error!(&wrap, &bin.panicked, false, { + imp.add_element(&wrap, &from_glib_borrow(element)) + }).to_glib() +} + +unsafe extern "C" fn bin_remove_element( + ptr: *mut gst_ffi::GstBin, + element: *mut gst_ffi::GstElement, +) -> glib_ffi::gboolean +where + T::ImplType: BinImpl, +{ + callback_guard!(); + floating_reference_guard!(ptr); + floating_reference_guard!(element); + let bin = &*(ptr as *mut InstanceStruct); + let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct); + let imp = &*bin.imp; + + panic_to_error!(&wrap, &bin.panicked, false, { + imp.remove_element(&wrap, &from_glib_borrow(element)) + }).to_glib() +} + +unsafe extern "C" fn bin_handle_message( + ptr: *mut gst_ffi::GstBin, + message: *mut gst_ffi::GstMessage, +) where + T::ImplType: BinImpl, +{ + callback_guard!(); + floating_reference_guard!(ptr); + let bin = &*(ptr as *mut InstanceStruct); + let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct); + let imp = &*bin.imp; + + panic_to_error!(&wrap, &bin.panicked, (), { + imp.handle_message(&wrap, from_glib_full(message)) + }); +} diff --git a/gst-plugin/src/lib.rs b/gst-plugin/src/lib.rs index fe1b593e..48b416b4 100644 --- a/gst-plugin/src/lib.rs +++ b/gst-plugin/src/lib.rs @@ -73,6 +73,8 @@ pub mod object; #[macro_use] pub mod element; #[macro_use] +pub mod bin; +#[macro_use] pub mod base_src; #[macro_use] pub mod base_sink;