From a0bac4a722a82cf9cc2f901766239a63f4e429fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 23 Sep 2017 19:20:23 +0300 Subject: [PATCH] Add interface infrastructure and GstURIHandler support --- gst-plugin/src/lib.rs | 1 + gst-plugin/src/object.rs | 34 +++++++- gst-plugin/src/uri_handler.rs | 147 ++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 gst-plugin/src/uri_handler.rs diff --git a/gst-plugin/src/lib.rs b/gst-plugin/src/lib.rs index 5153c97a..cfbbfbf6 100644 --- a/gst-plugin/src/lib.rs +++ b/gst-plugin/src/lib.rs @@ -46,3 +46,4 @@ pub mod bytes; pub mod object; pub mod element; pub mod base_src; +pub mod uri_handler; diff --git a/gst-plugin/src/object.rs b/gst-plugin/src/object.rs index 50acce4c..86a89d94 100644 --- a/gst-plugin/src/object.rs +++ b/gst-plugin/src/object.rs @@ -45,8 +45,11 @@ pub trait ImplTypeStatic: Send + Sync + 'static { fn get_name(&self) -> &str; fn new(&self, &T::RsType) -> T::ImplType; fn class_init(&self, &mut ClassStruct); + fn type_init(&self, _: &TypeInitToken, _type_: glib::Type) {} } +pub struct TypeInitToken(()); + pub trait ObjectType: 'static where Self: Sized, @@ -87,6 +90,25 @@ impl InstanceStruct { pub struct ClassStruct { pub parent: T::GlibClassType, pub imp_static: *const Box>, + pub interfaces_static: *const Vec<(glib_ffi::GType, glib_ffi::gpointer)>, +} + +impl ClassStruct { + pub fn get_interface_static(&self, type_: glib_ffi::GType) -> glib_ffi::gpointer { + unsafe { + if self.interfaces_static.is_null() { + return ptr::null_mut(); + } + + for &(t, p) in (*self.interfaces_static).iter() { + if t == type_ { + return p; + } + } + + ptr::null_mut() + } + } } pub unsafe trait ObjectClassStruct { @@ -415,6 +437,7 @@ unsafe extern "C" fn sub_class_init( let klass = &mut *(klass as *mut ClassStruct); let imp_static = klass_data as *const Box>; klass.imp_static = imp_static; + klass.interfaces_static = Box::into_raw(Box::new(Vec::new())); (*imp_static).class_init(klass); } @@ -467,6 +490,7 @@ pub fn register_type>(imp: I) -> glib::Type let type_name = format!("{}-{}", T::NAME, imp.get_name()); let imp: Box> = Box::new(imp); + let imp_ptr = Box::into_raw(Box::new(imp)); let type_info = gobject_ffi::GTypeInfo { class_size: mem::size_of::>() as u16, @@ -474,20 +498,22 @@ pub fn register_type>(imp: I) -> glib::Type base_finalize: None, class_init: Some(sub_class_init::), class_finalize: None, - class_data: Box::into_raw(Box::new(imp)) as glib_ffi::gpointer, + class_data: imp_ptr as glib_ffi::gpointer, instance_size: mem::size_of::>() as u16, n_preallocs: 0, instance_init: Some(sub_init::), value_table: ptr::null(), }; - let type_ = gobject_ffi::g_type_register_static( + let type_ = from_glib(gobject_ffi::g_type_register_static( parent_type, type_name.to_glib_none().0, &type_info, gobject_ffi::GTypeFlags::empty(), - ); + )); - from_glib(type_) + (*imp_ptr).type_init(&TypeInitToken(()), type_); + + type_ } } diff --git a/gst-plugin/src/uri_handler.rs b/gst-plugin/src/uri_handler.rs new file mode 100644 index 00000000..0917ea16 --- /dev/null +++ b/gst-plugin/src/uri_handler.rs @@ -0,0 +1,147 @@ +// 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 mopa; + +use glib_ffi; +use gobject_ffi; +use gst_ffi; + +use libc; +use glib; +use glib::translate::*; +use gst; +use gst::prelude::*; + +use object::*; + +pub trait URIHandlerImpl: mopa::Any + Send + Sync + 'static { + fn get_uri(&self, element: &gst::URIHandler) -> Option; + fn set_uri(&self, element: &gst::URIHandler, uri: Option) -> Result<(), glib::Error>; +} + +pub trait URIHandlerImplStatic: Send + Sync + 'static { + fn get_impl(&self, imp: &T::ImplType) -> &URIHandlerImpl; + fn get_type(&self) -> gst::URIType; + fn get_protocols(&self) -> Vec; +} + +struct URIHandlerStatic { + imp_static: *const URIHandlerImplStatic, + protocols: *const Vec<*const libc::c_char>, +} + +unsafe extern "C" fn uri_handler_get_type( + type_: glib_ffi::GType, +) -> gst_ffi::GstURIType { + callback_guard!(); + let klass = gobject_ffi::g_type_class_peek(type_); + let klass = &*(klass as *const ClassStruct); + let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type()) as + *const URIHandlerStatic; + (*(*interface_static).imp_static).get_type().to_glib() +} + +unsafe extern "C" fn uri_handler_get_protocols( + type_: glib_ffi::GType, +) -> *const *const libc::c_char { + callback_guard!(); + let klass = gobject_ffi::g_type_class_peek(type_); + let klass = &*(klass as *const ClassStruct); + let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type()) as + *const URIHandlerStatic; + (*(*interface_static).protocols).as_ptr() +} + +unsafe extern "C" fn uri_handler_get_uri( + uri_handler: *mut gst_ffi::GstURIHandler, +) -> *mut libc::c_char { + callback_guard!(); + let klass = &**(uri_handler as *const *const ClassStruct); + let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type()) as + *const URIHandlerStatic; + + let instance = &*(uri_handler as *const InstanceStruct); + let imp = instance.get_impl(); + let imp = (*(*interface_static).imp_static).get_impl(imp); + + imp.get_uri(&from_glib_borrow(uri_handler)).to_glib_full() +} + +unsafe extern "C" fn uri_handler_set_uri( + uri_handler: *mut gst_ffi::GstURIHandler, + uri: *const libc::c_char, + err: *mut *mut glib_ffi::GError, +) -> glib_ffi::gboolean { + callback_guard!(); + + let klass = &**(uri_handler as *const *const ClassStruct); + let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type()) as + *const URIHandlerStatic; + + let instance = &*(uri_handler as *const InstanceStruct); + let imp = instance.get_impl(); + let imp = (*(*interface_static).imp_static).get_impl(imp); + + match imp.set_uri(&from_glib_borrow(uri_handler), from_glib_none(uri)) { + Ok(()) => true.to_glib(), + Err(error) => { + *err = error.to_glib_full() as *mut _; + false.to_glib() + } + } +} + +unsafe extern "C" fn uri_handler_init( + iface: glib_ffi::gpointer, + iface_data: glib_ffi::gpointer, +) { + callback_guard!(); + let uri_handler_iface = &mut *(iface as *mut gst_ffi::GstURIHandlerInterface); + + let iface_type = (*(iface as *const gobject_ffi::GTypeInterface)).g_type; + let type_ = (*(iface as *const gobject_ffi::GTypeInterface)).g_instance_type; + let klass = &mut *(gobject_ffi::g_type_class_ref(type_) as *mut ClassStruct); + let interfaces_static = &mut *(klass.interfaces_static as *mut Vec<_>); + interfaces_static.push((iface_type, iface_data)); + + uri_handler_iface.get_type = Some(uri_handler_get_type::); + uri_handler_iface.get_protocols = Some(uri_handler_get_protocols::); + uri_handler_iface.get_uri = Some(uri_handler_get_uri::); + uri_handler_iface.set_uri = Some(uri_handler_set_uri::); +} + +pub fn register_uri_handler>( + _: &TypeInitToken, + type_: glib::Type, + imp: &I, +) { + unsafe { + let protocols: Vec<_> = imp.get_protocols() + .iter() + .map(|s| s.to_glib_full()) + .collect(); + + let imp = imp as &URIHandlerImplStatic as *const URIHandlerImplStatic; + let interface_static = Box::new(URIHandlerStatic { + imp_static: imp, + protocols: Box::into_raw(Box::new(protocols)), + }); + + let iface_info = gobject_ffi::GInterfaceInfo { + interface_init: Some(uri_handler_init::), + interface_finalize: None, + interface_data: Box::into_raw(interface_static) as glib_ffi::gpointer, + }; + gobject_ffi::g_type_add_interface_static( + type_.to_glib(), + gst_ffi::gst_uri_handler_get_type(), + &iface_info, + ); + } +}