diff --git a/Gir_Gst.toml b/Gir_Gst.toml index da8411f59..247f8b9f9 100644 --- a/Gir_Gst.toml +++ b/Gir_Gst.toml @@ -312,6 +312,7 @@ status = "generate" [[object]] name = "Gst.Element" +subclassing = true status = "generate" [[object.function]] name = "make_from_uri" diff --git a/gstreamer/Cargo.toml b/gstreamer/Cargo.toml index 4a3edfbd3..74c754f08 100644 --- a/gstreamer/Cargo.toml +++ b/gstreamer/Cargo.toml @@ -47,6 +47,7 @@ dox = ["gstreamer-sys/dox", "glib/dox", "futures", "ser_de"] futures = ["futures-core-preview"] ser_de = ["num-rational/serde", "serde", "serde_bytes", "serde_derive"] default-features = [] +subclassing = ["glib/subclassing"] [badges] gitlab = { repository = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", branch = "master" } diff --git a/gstreamer/src/auto/element.rs b/gstreamer/src/auto/element.rs index 230f6c272..6d089e99d 100644 --- a/gstreamer/src/auto/element.rs +++ b/gstreamer/src/auto/element.rs @@ -33,8 +33,10 @@ use std::mem; use std::mem::transmute; use std::ptr; +use ElementClass; + glib_wrapper! { - pub struct Element(Object): Object; + pub struct Element(Object): Object; match fn { get_type => || ffi::gst_element_get_type(), diff --git a/gstreamer/src/element.rs b/gstreamer/src/element.rs index ec38a1cf4..f87d25827 100644 --- a/gstreamer/src/element.rs +++ b/gstreamer/src/element.rs @@ -16,7 +16,7 @@ use glib::translate::FromGlibPtrBorrow; use glib::translate::{ from_glib, from_glib_full, from_glib_none, FromGlib, FromGlibPtrContainer, ToGlib, ToGlibPtr, }; -use glib::IsA; +use glib::{IsA, IsClassFor}; use miniobject::MiniObject; use Event; use Format; @@ -29,6 +29,7 @@ use SpecificFormattedValue; use std::ffi::CStr; use std::mem; +use std::ops; use libc; @@ -92,6 +93,8 @@ impl FromGlib for NotifyWatchId { } pub trait ElementExtManual { + fn get_element_class(&self) -> &ElementClass; + fn query(&self, query: &mut QueryRef) -> bool; fn send_event(&self, event: Event) -> bool; @@ -192,6 +195,14 @@ pub trait ElementExtManual { } impl> ElementExtManual for O { + fn get_element_class(&self) -> &ElementClass { + unsafe { + let klass = (*(self.to_glib_none().0 as *mut gobject_ffi::GTypeInstance)).g_class + as *const ElementClass; + &*klass + } + } + fn query(&self, query: &mut QueryRef) -> bool { unsafe { from_glib(ffi::gst_element_query( @@ -211,41 +222,15 @@ impl> ElementExtManual for O { } fn get_metadata<'a>(&self, key: &str) -> Option<&'a str> { - unsafe { - let klass = (*(self.to_glib_none().0 as *mut gobject_ffi::GTypeInstance)).g_class - as *mut ffi::GstElementClass; - - let ptr = ffi::gst_element_class_get_metadata(klass, key.to_glib_none().0); - - if ptr.is_null() { - None - } else { - Some(CStr::from_ptr(ptr).to_str().unwrap()) - } - } + self.get_element_class().get_metadata(key) } fn get_pad_template(&self, name: &str) -> Option { - unsafe { - let klass = (*(self.to_glib_none().0 as *mut gobject_ffi::GTypeInstance)).g_class - as *mut ffi::GstElementClass; - - from_glib_none(ffi::gst_element_class_get_pad_template( - klass, - name.to_glib_none().0, - )) - } + self.get_element_class().get_pad_template(name) } fn get_pad_template_list(&self) -> Vec { - unsafe { - let klass = (*(self.to_glib_none().0 as *mut gobject_ffi::GTypeInstance)).g_class - as *mut ffi::GstElementClass; - - FromGlibPtrContainer::from_glib_none(ffi::gst_element_class_get_pad_template_list( - klass, - )) - } + self.get_element_class().get_pad_template_list() } fn message_full( @@ -614,6 +599,67 @@ impl> ElementExtManual for O { } } +#[repr(C)] +pub struct ElementClass(ffi::GstElementClass); + +unsafe impl IsClassFor for ElementClass { + type Instance = ::Element; +} + +unsafe impl Send for ElementClass {} +unsafe impl Sync for ElementClass {} + +impl ops::Deref for ElementClass { + type Target = glib::ObjectClass; + + fn deref(&self) -> &Self::Target { + self.upcast_ref() + } +} + +impl ops::DerefMut for ElementClass { + fn deref_mut(&mut self) -> &mut Self::Target { + self.upcast_ref_mut() + } +} + +impl ElementClass { + pub fn get_metadata<'a>(&self, key: &str) -> Option<&'a str> { + unsafe { + let klass = self as *const _ as *const ffi::GstElementClass; + + let ptr = ffi::gst_element_class_get_metadata(klass as *mut _, key.to_glib_none().0); + + if ptr.is_null() { + None + } else { + Some(CStr::from_ptr(ptr).to_str().unwrap()) + } + } + } + + pub fn get_pad_template(&self, name: &str) -> Option { + unsafe { + let klass = self as *const _ as *const ffi::GstElementClass; + + from_glib_none(ffi::gst_element_class_get_pad_template( + klass as *mut _, + name.to_glib_none().0, + )) + } + } + + pub fn get_pad_template_list(&self) -> Vec { + unsafe { + let klass = self as *const _ as *const ffi::GstElementClass; + + FromGlibPtrContainer::from_glib_none(ffi::gst_element_class_get_pad_template_list( + klass as *mut _, + )) + } + } +} + lazy_static! { pub static ref ELEMENT_METADATA_AUTHOR: &'static str = unsafe { CStr::from_ptr(ffi::GST_ELEMENT_METADATA_AUTHOR) diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index b98590c2b..c4a13218a 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -16,12 +16,17 @@ extern crate cfg_if; extern crate lazy_static; extern crate libc; -extern crate glib_sys as glib_ffi; -extern crate gobject_sys as gobject_ffi; -extern crate gstreamer_sys as ffi; +// Re-exported for the subclass gst_plugin_define! macro +#[doc(hidden)] +pub extern crate glib_sys as glib_ffi; +#[doc(hidden)] +pub extern crate gobject_sys as gobject_ffi; +#[doc(hidden)] +pub extern crate gstreamer_sys as ffi; #[macro_use] -extern crate glib; +#[doc(hidden)] +pub extern crate glib; extern crate num_rational; @@ -143,6 +148,7 @@ pub use promise::*; mod bin; mod bus; mod element; +pub use element::ElementClass; // OS dependent Bus extensions (also import the other plateform mod for doc) #[cfg(any(feature = "v1_14", feature = "dox"))] @@ -330,3 +336,7 @@ pub mod prelude { } mod utils; + +#[macro_use] +#[cfg(feature = "subclassing")] +pub mod subclass; diff --git a/gstreamer/src/subclass/element.rs b/gstreamer/src/subclass/element.rs new file mode 100644 index 000000000..45ef32d53 --- /dev/null +++ b/gstreamer/src/subclass/element.rs @@ -0,0 +1,365 @@ +// Copyright (C) 2017,2018 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 libc; + +use ffi; +use glib_ffi; + +use super::prelude::*; +use glib; +use glib::prelude::*; +use glib::subclass::prelude::*; +use glib::translate::*; +use prelude::*; + +use Element; +use ElementClass; +use Event; +use PadTemplate; +use QueryRef; +use StateChange; +use StateChangeReturn; + +pub trait ElementImpl: ObjectImpl + Send + Sync + 'static { + fn change_state(&self, element: &::Element, transition: StateChange) -> StateChangeReturn { + self.parent_change_state(element, transition) + } + + fn request_new_pad( + &self, + _element: &::Element, + _templ: &::PadTemplate, + _name: Option, + _caps: Option<&::CapsRef>, + ) -> Option<::Pad> { + None + } + + fn release_pad(&self, _element: &::Element, _pad: &::Pad) {} + + fn send_event(&self, element: &::Element, event: Event) -> bool { + self.parent_send_event(element, event) + } + + fn query(&self, element: &::Element, query: &mut QueryRef) -> bool { + self.parent_query(element, query) + } + + fn set_context(&self, element: &::Element, context: &::Context) { + self.parent_set_context(element, context) + } + + fn parent_change_state( + &self, + element: &::Element, + transition: StateChange, + ) -> StateChangeReturn { + unsafe { + let data = self.get_type_data(); + let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstElementClass; + + (*parent_class) + .change_state + .map(|f| from_glib(f(element.to_glib_none().0, transition.to_glib()))) + .unwrap_or(::StateChangeReturn::Success) + } + } + + fn parent_send_event(&self, element: &::Element, event: Event) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstElementClass; + + (*parent_class) + .send_event + .map(|f| from_glib(f(element.to_glib_none().0, event.into_ptr()))) + .unwrap_or(false) + } + } + + fn parent_query(&self, element: &::Element, query: &mut QueryRef) -> bool { + unsafe { + let data = self.get_type_data(); + let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstElementClass; + + (*parent_class) + .query + .map(|f| from_glib(f(element.to_glib_none().0, query.as_mut_ptr()))) + .unwrap_or(false) + } + } + + fn parent_set_context(&self, element: &::Element, context: &::Context) { + unsafe { + let data = self.get_type_data(); + let parent_class = data.as_ref().get_parent_class() as *mut ffi::GstElementClass; + + (*parent_class) + .set_context + .map(|f| f(element.to_glib_none().0, context.to_glib_none().0)) + .unwrap_or(()) + } + } +} + +pub trait ElementImplExt { + fn catch_panic< + R, + F: FnOnce(&Self) -> R, + G: FnOnce() -> R, + P: IsA<::Element> + IsA + glib::value::SetValue, + >( + &self, + element: &P, + fallback: G, + f: F, + ) -> R; + + fn catch_panic_pad_function R, G: FnOnce() -> R>( + parent: &Option<::Object>, + fallback: G, + f: F, + ) -> R; +} + +impl ElementImplExt for T +where + T::Instance: PanicPoison, +{ + fn catch_panic< + R, + F: FnOnce(&Self) -> R, + G: FnOnce() -> R, + P: IsA<::Element> + IsA + glib::value::SetValue, + >( + &self, + element: &P, + fallback: G, + f: F, + ) -> R { + unsafe { + assert!(element.get_type().is_a(&T::static_type())); + let ptr: *mut ffi::GstElement = element.to_glib_none().0; + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + + gst_panic_to_error!(element, &instance.panicked(), fallback(), { f(&imp) }) + } + } + + fn catch_panic_pad_function R, G: FnOnce() -> R>( + parent: &Option<::Object>, + fallback: G, + f: F, + ) -> R { + unsafe { + let wrap = parent + .as_ref() + .unwrap() + .downcast_ref::<::Element>() + .unwrap(); + assert!(wrap.get_type().is_a(&T::static_type())); + let ptr: *mut ffi::GstElement = wrap.to_glib_none().0; + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + + gst_panic_to_error!(wrap, &instance.panicked(), fallback(), { f(&imp, &wrap) }) + } + } +} + +pub unsafe trait ElementClassSubclassExt: Sized + 'static { + fn add_pad_template(&mut self, pad_template: PadTemplate) { + unsafe { + ffi::gst_element_class_add_pad_template( + self as *const Self as *mut ffi::GstElementClass, + pad_template.to_glib_none().0, + ); + } + } + + fn set_metadata( + &mut self, + long_name: &str, + classification: &str, + description: &str, + author: &str, + ) { + unsafe { + ffi::gst_element_class_set_metadata( + self as *const Self as *mut ffi::GstElementClass, + long_name.to_glib_none().0, + classification.to_glib_none().0, + description.to_glib_none().0, + author.to_glib_none().0, + ); + } + } +} + +unsafe impl ElementClassSubclassExt for ElementClass {} + +unsafe impl IsSubclassable for ElementClass +where + ::Instance: PanicPoison, +{ + fn override_vfuncs(&mut self) { + >::override_vfuncs(self); + + unsafe { + let klass = &mut *(self as *const Self as *mut ffi::GstElementClass); + klass.change_state = Some(element_change_state::); + klass.request_new_pad = Some(element_request_new_pad::); + klass.release_pad = Some(element_release_pad::); + klass.send_event = Some(element_send_event::); + klass.query = Some(element_query::); + klass.set_context = Some(element_set_context::); + } + } +} + +unsafe extern "C" fn element_change_state( + ptr: *mut ffi::GstElement, + transition: ffi::GstStateChange, +) -> ffi::GstStateChangeReturn +where + T: ElementImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Element = from_glib_borrow(ptr); + + // *Never* fail downwards state changes, this causes bugs in GStreamer + // and leads to crashes and deadlocks. + let transition = from_glib(transition); + let fallback = match transition { + StateChange::PlayingToPaused | StateChange::PausedToReady | StateChange::ReadyToNull => { + StateChangeReturn::Success + } + _ => StateChangeReturn::Failure, + }; + + gst_panic_to_error!(&wrap, &instance.panicked(), fallback, { + imp.change_state(&wrap, transition) + }) + .to_glib() +} + +unsafe extern "C" fn element_request_new_pad( + ptr: *mut ffi::GstElement, + templ: *mut ffi::GstPadTemplate, + name: *const libc::c_char, + caps: *const ffi::GstCaps, +) -> *mut ffi::GstPad +where + T: ElementImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Element = from_glib_borrow(ptr); + + let caps = if caps.is_null() { + None + } else { + Some(::CapsRef::from_ptr(caps)) + }; + + // XXX: This is effectively unsafe but the best we can do + // See https://bugzilla.gnome.org/show_bug.cgi?id=791193 + let pad = gst_panic_to_error!(&wrap, &instance.panicked(), None, { + imp.request_new_pad(&wrap, &from_glib_borrow(templ), from_glib_none(name), caps) + }); + + // Ensure that the pad is owned by the element now, if a pad was returned + if let Some(ref pad) = pad { + assert_eq!( + pad.get_parent(), + Some(::Object::from_glib_borrow(ptr as *mut ffi::GstObject)) + ); + } + + pad.to_glib_none().0 +} + +unsafe extern "C" fn element_release_pad( + ptr: *mut ffi::GstElement, + pad: *mut ffi::GstPad, +) where + T: ElementImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Element = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), (), { + imp.release_pad(&wrap, &from_glib_borrow(pad)) + }) +} + +unsafe extern "C" fn element_send_event( + ptr: *mut ffi::GstElement, + event: *mut ffi::GstEvent, +) -> glib_ffi::gboolean +where + T: ElementImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Element = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.send_event(&wrap, from_glib_full(event)) + }) + .to_glib() +} + +unsafe extern "C" fn element_query( + ptr: *mut ffi::GstElement, + query: *mut ffi::GstQuery, +) -> glib_ffi::gboolean +where + T: ElementImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Element = from_glib_borrow(ptr); + let query = QueryRef::from_mut_ptr(query); + + gst_panic_to_error!(&wrap, &instance.panicked(), false, { + imp.query(&wrap, query) + }) + .to_glib() +} + +unsafe extern "C" fn element_set_context( + ptr: *mut ffi::GstElement, + context: *mut ffi::GstContext, +) where + T: ElementImpl, + T::Instance: PanicPoison, +{ + glib_floating_reference_guard!(ptr); + let instance = &*(ptr as *mut T::Instance); + let imp = instance.get_impl(); + let wrap: Element = from_glib_borrow(ptr); + + gst_panic_to_error!(&wrap, &instance.panicked(), (), { + imp.set_context(&wrap, &from_glib_borrow(context)) + }) +} diff --git a/gstreamer/src/subclass/error.rs b/gstreamer/src/subclass/error.rs new file mode 100644 index 000000000..b71366204 --- /dev/null +++ b/gstreamer/src/subclass/error.rs @@ -0,0 +1,93 @@ +// Copyright (C) 2016-2018 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::error::Error; +use std::fmt::Error as FmtError; +use std::fmt::{Display, Formatter}; + +use ErrorMessage; +use FlowReturn; + +#[macro_export] +macro_rules! gst_panic_to_error( + ($element:expr, $panicked:expr, $ret:expr, $code:block) => {{ + use std::panic::{self, AssertUnwindSafe}; + use std::sync::atomic::Ordering; + use $crate::ElementExtManual; + + if $panicked.load(Ordering::Relaxed) { + $element.post_error_message(&gst_error_msg!($crate::LibraryError::Failed, ["Panicked"])); + $ret + } else { + let result = panic::catch_unwind(AssertUnwindSafe(|| $code)); + + match result { + Ok(result) => result, + Err(err) => { + $panicked.store(true, Ordering::Relaxed); + if let Some(cause) = err.downcast_ref::<&str>() { + $element.post_error_message(&gst_error_msg!($crate::LibraryError::Failed, ["Panicked: {}", cause])); + } else if let Some(cause) = err.downcast_ref::() { + $element.post_error_message(&gst_error_msg!($crate::LibraryError::Failed, ["Panicked: {}", cause])); + } else { + $element.post_error_message(&gst_error_msg!($crate::LibraryError::Failed, ["Panicked"])); + } + $ret + } + } + } + }}; +); + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum FlowError { + Flushing, + Eos, + NotNegotiated(ErrorMessage), + Error(ErrorMessage), +} + +impl From for FlowReturn { + fn from(err: FlowError) -> Self { + FlowReturn::from(&err) + } +} + +impl<'a> From<&'a FlowError> for FlowReturn { + fn from(err: &FlowError) -> FlowReturn { + match *err { + FlowError::Flushing => FlowReturn::Flushing, + FlowError::Eos => FlowReturn::Eos, + FlowError::NotNegotiated(..) => FlowReturn::NotNegotiated, + FlowError::Error(..) => FlowReturn::Error, + } + } +} + +impl Display for FlowError { + fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + match *self { + FlowError::Flushing | FlowError::Eos => f.write_str(self.description()), + FlowError::NotNegotiated(ref m) => { + f.write_fmt(format_args!("{}: {}", self.description(), m)) + } + FlowError::Error(ref m) => f.write_fmt(format_args!("{}: {}", self.description(), m)), + } + } +} + +impl Error for FlowError { + fn description(&self) -> &str { + match *self { + FlowError::Flushing => "Flushing", + FlowError::Eos => "Eos", + FlowError::NotNegotiated(..) => "Not Negotiated", + FlowError::Error(..) => "Error", + } + } +} diff --git a/gstreamer/src/subclass/mod.rs b/gstreamer/src/subclass/mod.rs new file mode 100644 index 000000000..5df976f60 --- /dev/null +++ b/gstreamer/src/subclass/mod.rs @@ -0,0 +1,46 @@ +// Copyright (C) 2016-2018 Sebastian Dröge +// 2016 Luis de Bethencourt +// +// 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. +#![cfg_attr(feature = "cargo-clippy", allow(cast_ptr_alignment))] + +#[macro_use] +pub mod error; +#[macro_use] +pub mod plugin; + +pub mod element; + +pub mod prelude { + pub use super::element::{ElementClassSubclassExt, ElementImpl, ElementImplExt}; + pub use super::PanicPoison; + pub use glib::subclass::prelude::*; +} + +use self::prelude::*; +use glib; +use std::sync::atomic::AtomicBool; + +#[repr(C)] +pub struct ElementInstanceStruct { + parent: ::GlibType, + panicked: AtomicBool, +} + +unsafe impl InstanceStruct for ElementInstanceStruct { + type Type = T; +} + +pub trait PanicPoison { + fn panicked(&self) -> &AtomicBool; +} + +impl PanicPoison for ElementInstanceStruct { + fn panicked(&self) -> &AtomicBool { + &self.panicked + } +} diff --git a/gstreamer/src/subclass/plugin.rs b/gstreamer/src/subclass/plugin.rs new file mode 100644 index 000000000..6aec19e98 --- /dev/null +++ b/gstreamer/src/subclass/plugin.rs @@ -0,0 +1,92 @@ +// Copyright (C) 2016-2018 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. + +#[macro_export] +macro_rules! gst_plugin_define( + ($name:expr, $description:expr, $plugin_init:ident, + $version:expr, $license:expr, $source:expr, + $package:expr, $origin:expr, $release_datetime:expr) => { + pub mod plugin_desc { + use $crate::glib::translate::{from_glib_borrow, ToGlib, from_glib}; + + const MAJOR_VERSION: i32 = 1; + const MINOR_VERSION: i32 = 8; + + // Not using c_char here because it requires the libc crate + #[allow(non_camel_case_types)] + type c_char = i8; + + #[repr(C)] + pub struct GstPluginDesc($crate::ffi::GstPluginDesc); + unsafe impl Sync for GstPluginDesc {} + + #[no_mangle] + #[allow(non_upper_case_globals)] + pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc($crate::ffi::GstPluginDesc { + major_version: MAJOR_VERSION, + minor_version: MINOR_VERSION, + name: $name as *const u8 as *const c_char, + description: $description as *const u8 as *const c_char, + plugin_init: Some(plugin_init_trampoline), + version: $version as *const u8 as *const c_char, + license: $license as *const u8 as *const c_char, + source: $source as *const u8 as *const c_char, + package: $package as *const u8 as *const c_char, + origin: $origin as *const u8 as *const c_char, + release_datetime: $release_datetime as *const u8 as *const c_char, + _gst_reserved: [0 as $crate::glib_ffi::gpointer; 4], + }); + + pub fn plugin_register_static() -> bool { + unsafe { + from_glib($crate::ffi::gst_plugin_register_static( + MAJOR_VERSION, + MINOR_VERSION, + $name as *const u8 as *const c_char, + $description as *const u8 as *const c_char, + Some(plugin_init_trampoline), + $version as *const u8 as *const c_char, + $license as *const u8 as *const c_char, + $source as *const u8 as *const c_char, + $package as *const u8 as *const c_char, + $origin as *const u8 as *const c_char, + )) + } + } + + unsafe extern "C" fn plugin_init_trampoline(plugin: *mut $crate::ffi::GstPlugin) -> $crate::glib_ffi::gboolean { + use std::panic::{self, AssertUnwindSafe}; + + let panic_result = panic::catch_unwind(AssertUnwindSafe(|| super::$plugin_init(&from_glib_borrow(plugin)))); + match panic_result { + Ok(register_result) => match register_result { + Ok(_) => $crate::glib_ffi::GTRUE, + Err(err) => { + let cat = $crate::DebugCategory::get("GST_PLUGIN_LOADING").unwrap(); + gst_error!(cat, "Failed to register plugin: {}", err); + $crate::glib_ffi::GFALSE + } + } + Err(err) => { + let cat = $crate::DebugCategory::get("GST_PLUGIN_LOADING").unwrap(); + if let Some(cause) = err.downcast_ref::<&str>() { + gst_error!(cat, "Failed to initialize plugin due to panic: {}", cause); + } else if let Some(cause) = err.downcast_ref::() { + gst_error!(cat, "Failed to initialize plugin due to panic: {}", cause); + } else { + gst_error!(cat, "Failed to initialize plugin due to panic"); + } + + $crate::glib_ffi::GFALSE + } + } + } + } + pub use plugin_desc::plugin_register_static; + }; +);