// 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 mopa; use glib_ffi; use gobject_ffi; use gst_ffi; use glib; use glib::translate::*; use gst; use gst::prelude::*; use object::*; pub trait ElementImpl : ObjectImpl + mopa::Any + Send + Sync + 'static { fn change_state(&self, element: &T, transition: gst::StateChange) -> gst::StateChangeReturn { element.parent_change_state(transition) } } mopafy_object_impl!(Element, ElementImpl); pub unsafe trait Element: IsA + ObjectType { fn parent_change_state(&self, transition: gst::StateChange) -> gst::StateChangeReturn { unsafe { let klass = self.get_class(); let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass; (*parent_klass) .change_state .map(|f| { from_glib(f(self.to_glib_none().0, transition.to_glib())) }) .unwrap_or(gst::StateChangeReturn::Success) } } } pub unsafe trait ElementClass where T::ImplType: ElementImpl, { fn add_pad_template(&mut self, pad_template: gst::PadTemplate) { unsafe { gst_ffi::gst_element_class_add_pad_template( self as *const Self as *mut gst_ffi::GstElementClass, pad_template.to_glib_full(), ); } } fn set_metadata( &mut self, long_name: &str, classification: &str, description: &str, author: &str, ) { unsafe { gst_ffi::gst_element_class_set_metadata( self as *const Self as *mut gst_ffi::GstElementClass, long_name.to_glib_none().0, classification.to_glib_none().0, description.to_glib_none().0, author.to_glib_none().0, ); } } fn override_vfuncs(&mut self) { unsafe { let klass = &mut *(self as *const Self as *mut gst_ffi::GstElementClass); klass.change_state = Some(element_change_state::); } } } glib_wrapper! { pub struct RsElement(Object>): [gst::Element => gst_ffi::GstElement, gst::Object => gst_ffi::GstObject]; match fn { get_type => || get_type::(), } } unsafe impl + ObjectType> Element for T {} pub type RsElementClass = ClassStruct; // FIXME: Boilerplate unsafe impl ElementClass for RsElementClass {} #[macro_export] macro_rules! box_element_impl( ($name:ident) => { box_object_impl!($name); impl ElementImpl for Box<$name> { fn change_state( &self, element: &T, transition: gst::StateChange, ) -> gst::StateChangeReturn { let imp: &$name = self.as_ref(); imp.change_state(element, transition) } } }; ); box_element_impl!(ElementImpl); impl ObjectType for RsElement { const NAME: &'static str = "RsElement"; type GlibType = gst_ffi::GstElement; type GlibClassType = gst_ffi::GstElementClass; type ImplType = Box>; fn glib_type() -> glib::Type { unsafe { from_glib(gst_ffi::gst_element_get_type()) } } fn class_init(klass: &mut RsElementClass) { klass.override_vfuncs(); } object_type_fns!(); } unsafe extern "C" fn element_change_state( ptr: *mut gst_ffi::GstElement, transition: gst_ffi::GstStateChange, ) -> gst_ffi::GstStateChangeReturn where T::ImplType: ElementImpl, { callback_guard!(); floating_reference_guard!(ptr); let element = &*(ptr as *mut InstanceStruct); let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct); let imp = &*element.imp; panic_to_error!(&wrap, &element.panicked, gst::StateChangeReturn::Failure, { imp.change_state(&wrap, from_glib(transition)) }).to_glib() }