mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-25 21:11:00 +00:00
Implement generic object subclass creation in a more... generic... way
That actually works for subclasses of subclasses too without too much boilerplate, and also keeps the GObject boilerplate in a single file instead of having it for every single subclass.
This commit is contained in:
parent
8d253fd46a
commit
cda23d5c41
5 changed files with 381 additions and 242 deletions
89
gst-plugin/src/base_src.rs
Normal file
89
gst-plugin/src/base_src.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 gst_base_ffi;
|
||||||
|
|
||||||
|
use glib;
|
||||||
|
use glib::translate::*;
|
||||||
|
use gst;
|
||||||
|
use gst::prelude::*;
|
||||||
|
use gst_base;
|
||||||
|
use gst_base::prelude::*;
|
||||||
|
|
||||||
|
use object::*;
|
||||||
|
use element::*;
|
||||||
|
|
||||||
|
pub trait BaseSrcImpl: mopa::Any + ElementImpl + Send + Sync + 'static {}
|
||||||
|
|
||||||
|
mopafy!(BaseSrcImpl);
|
||||||
|
|
||||||
|
pub unsafe trait BaseSrc: IsA<gst_base::BaseSrc> {}
|
||||||
|
|
||||||
|
pub unsafe trait BaseSrcClass<T: ObjectType>
|
||||||
|
where
|
||||||
|
T::RsType: IsA<gst_base::BaseSrc>,
|
||||||
|
T::ImplType: BaseSrcImpl,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
glib_wrapper! {
|
||||||
|
pub struct RsBaseSrc(Object<InstanceStruct<RsBaseSrc>>): [gst_base::BaseSrc => gst_base_ffi::GstBaseSrc,
|
||||||
|
gst::Element => gst_ffi::GstElement,
|
||||||
|
gst::Object => gst_ffi::GstObject];
|
||||||
|
|
||||||
|
match fn {
|
||||||
|
get_type => || get_type::<RsBaseSrc>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: IsA<gst_base::BaseSrc>> BaseSrc for T {}
|
||||||
|
pub type RsBaseSrcClass = ClassStruct<RsBaseSrc>;
|
||||||
|
|
||||||
|
// FIXME: Boilerplate
|
||||||
|
unsafe impl BaseSrcClass<RsBaseSrc> for gst_base_ffi::GstBaseSrcClass {}
|
||||||
|
unsafe impl BaseSrcClass<RsBaseSrc> for RsBaseSrcClass {}
|
||||||
|
unsafe impl ElementClass<RsBaseSrc> for gst_base_ffi::GstBaseSrcClass {}
|
||||||
|
unsafe impl ElementClass<RsBaseSrc> for RsBaseSrcClass {}
|
||||||
|
|
||||||
|
// FIXME: Boilerplate
|
||||||
|
impl BaseSrcImpl for Box<BaseSrcImpl> {}
|
||||||
|
|
||||||
|
// FIXME: Boilerplate
|
||||||
|
impl ElementImpl for Box<BaseSrcImpl> {
|
||||||
|
fn change_state(
|
||||||
|
&self,
|
||||||
|
element: &gst::Element,
|
||||||
|
transition: gst::StateChange,
|
||||||
|
) -> gst::StateChangeReturn {
|
||||||
|
let imp: &BaseSrcImpl = self.as_ref();
|
||||||
|
imp.change_state(element, transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectType for RsBaseSrc {
|
||||||
|
const NAME: &'static str = "RsBaseSrc";
|
||||||
|
type GlibType = gst_base_ffi::GstBaseSrc;
|
||||||
|
type GlibClassType = gst_base_ffi::GstBaseSrcClass;
|
||||||
|
type RsType = RsBaseSrc;
|
||||||
|
type ImplType = Box<BaseSrcImpl>;
|
||||||
|
|
||||||
|
fn glib_type() -> glib::Type {
|
||||||
|
unsafe { from_glib(gst_base_ffi::gst_base_src_get_type()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::GlibClassType) {
|
||||||
|
ElementClass::override_vfuncs(klass);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ use std::u64;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use error::*;
|
use error::*;
|
||||||
|
use object::{register_type, ImplTypeStatic};
|
||||||
use element::*;
|
use element::*;
|
||||||
|
|
||||||
use glib;
|
use glib;
|
||||||
|
@ -92,6 +93,7 @@ impl Stream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Get rid of this wrapper
|
||||||
pub struct DemuxerWrapper {
|
pub struct DemuxerWrapper {
|
||||||
cat: gst::DebugCategory,
|
cat: gst::DebugCategory,
|
||||||
demuxer: Mutex<Box<DemuxerImpl>>,
|
demuxer: Mutex<Box<DemuxerImpl>>,
|
||||||
|
@ -384,22 +386,19 @@ impl Demuxer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn class_init(
|
fn class_init(klass: &mut RsElementClass, demuxer_info: &DemuxerInfo) {
|
||||||
klass: &mut RsElementClass,
|
klass.set_metadata(
|
||||||
long_name: &str,
|
&demuxer_info.long_name,
|
||||||
classification: &str,
|
&demuxer_info.classification,
|
||||||
description: &str,
|
&demuxer_info.description,
|
||||||
author: &str,
|
&demuxer_info.author,
|
||||||
input_caps: &gst::Caps,
|
);
|
||||||
output_caps: &gst::Caps,
|
|
||||||
) {
|
|
||||||
klass.set_metadata(long_name, classification, description, author);
|
|
||||||
|
|
||||||
let pad_template = gst::PadTemplate::new(
|
let pad_template = gst::PadTemplate::new(
|
||||||
"sink",
|
"sink",
|
||||||
gst::PadDirection::Sink,
|
gst::PadDirection::Sink,
|
||||||
gst::PadPresence::Always,
|
gst::PadPresence::Always,
|
||||||
input_caps,
|
&demuxer_info.input_caps,
|
||||||
);
|
);
|
||||||
klass.add_pad_template(pad_template);
|
klass.add_pad_template(pad_template);
|
||||||
|
|
||||||
|
@ -407,7 +406,7 @@ impl Demuxer {
|
||||||
"src_%u",
|
"src_%u",
|
||||||
gst::PadDirection::Src,
|
gst::PadDirection::Src,
|
||||||
gst::PadPresence::Sometimes,
|
gst::PadPresence::Sometimes,
|
||||||
output_caps,
|
&demuxer_info.output_caps,
|
||||||
);
|
);
|
||||||
klass.add_pad_template(pad_template);
|
klass.add_pad_template(pad_template);
|
||||||
}
|
}
|
||||||
|
@ -688,7 +687,7 @@ impl Demuxer {
|
||||||
impl ElementImpl for Demuxer {
|
impl ElementImpl for Demuxer {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &RsElement,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
let mut ret = gst::StateChangeReturn::Success;
|
let mut ret = gst::StateChangeReturn::Success;
|
||||||
|
@ -725,32 +724,34 @@ impl ElementImpl for Demuxer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DemuxerStatic {
|
||||||
|
name: String,
|
||||||
|
demuxer_info: DemuxerInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImplTypeStatic<RsElement> for DemuxerStatic {
|
||||||
|
fn get_name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(&self, element: &RsElement) -> Box<ElementImpl> {
|
||||||
|
Demuxer::init(element, &self.demuxer_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_init(&self, klass: &mut RsElementClass) {
|
||||||
|
Demuxer::class_init(klass, &self.demuxer_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn demuxer_register(plugin: &gst::Plugin, demuxer_info: DemuxerInfo) {
|
pub fn demuxer_register(plugin: &gst::Plugin, demuxer_info: DemuxerInfo) {
|
||||||
let name = demuxer_info.name.clone();
|
let name = demuxer_info.name.clone();
|
||||||
let rank = demuxer_info.rank;
|
let rank = demuxer_info.rank;
|
||||||
|
|
||||||
let long_name = demuxer_info.long_name.clone();
|
let demuxer_static = DemuxerStatic {
|
||||||
let classification = demuxer_info.classification.clone();
|
name: format!("Demuxer-{}", name),
|
||||||
let description = demuxer_info.description.clone();
|
demuxer_info: demuxer_info,
|
||||||
let author = demuxer_info.author.clone();
|
};
|
||||||
let input_caps = demuxer_info.input_caps.clone();
|
|
||||||
let output_caps = demuxer_info.output_caps.clone();
|
|
||||||
|
|
||||||
element_register(
|
let type_ = register_type(demuxer_static);
|
||||||
plugin,
|
gst::Element::register(plugin, &name, rank, type_);
|
||||||
&name,
|
|
||||||
rank,
|
|
||||||
move |klass| {
|
|
||||||
Demuxer::class_init(
|
|
||||||
klass,
|
|
||||||
&long_name,
|
|
||||||
&classification,
|
|
||||||
&description,
|
|
||||||
&author,
|
|
||||||
&input_caps,
|
|
||||||
&output_caps,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
move |element| Demuxer::init(element, &demuxer_info),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
use mopa;
|
use mopa;
|
||||||
|
|
||||||
use glib_ffi;
|
use glib_ffi;
|
||||||
|
@ -21,10 +19,12 @@ use glib::translate::*;
|
||||||
use gst;
|
use gst;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
|
||||||
|
use object::*;
|
||||||
|
|
||||||
pub trait ElementImpl: mopa::Any + Send + Sync + 'static {
|
pub trait ElementImpl: mopa::Any + Send + Sync + 'static {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &RsElement,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
element.parent_change_state(transition)
|
element.parent_change_state(transition)
|
||||||
|
@ -53,7 +53,11 @@ pub unsafe trait Element: IsA<gst::Element> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe trait ElementClass {
|
pub unsafe trait ElementClass<T: ObjectType>
|
||||||
|
where
|
||||||
|
T::RsType: IsA<gst::Element>,
|
||||||
|
T::ImplType: ElementImpl,
|
||||||
|
{
|
||||||
fn add_pad_template(&mut self, pad_template: gst::PadTemplate) {
|
fn add_pad_template(&mut self, pad_template: gst::PadTemplate) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gst_ffi::gst_element_class_add_pad_template(
|
gst_ffi::gst_element_class_add_pad_template(
|
||||||
|
@ -80,14 +84,21 @@ pub unsafe trait ElementClass {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::<T>);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glib_wrapper! {
|
glib_wrapper! {
|
||||||
pub struct RsElement(Object<ffi::RsElement>): [gst::Element => gst_ffi::GstElement,
|
pub struct RsElement(Object<InstanceStruct<RsElement>>): [gst::Element => gst_ffi::GstElement,
|
||||||
gst::Object => gst_ffi::GstObject];
|
gst::Object => gst_ffi::GstObject];
|
||||||
|
|
||||||
match fn {
|
match fn {
|
||||||
get_type => || ffi::rs_element_get_type(),
|
get_type => || get_type::<RsElement>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,211 +106,59 @@ impl RsElement {
|
||||||
pub fn get_impl(&self) -> &ElementImpl {
|
pub fn get_impl(&self) -> &ElementImpl {
|
||||||
unsafe {
|
unsafe {
|
||||||
let stash = self.to_glib_none();
|
let stash = self.to_glib_none();
|
||||||
let ptr: *const ffi::RsElement = stash.0;
|
let ptr: *mut InstanceStruct<RsElement> = stash.0;
|
||||||
(*ptr).get_impl()
|
(*ptr).get_impl().as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Element>> Element for T {}
|
unsafe impl<T: IsA<gst::Element>> Element for T {}
|
||||||
unsafe impl ElementClass for RsElementClass {}
|
pub type RsElementClass = ClassStruct<RsElement>;
|
||||||
|
unsafe impl ElementClass<RsElement> for RsElementClass {}
|
||||||
|
unsafe impl ElementClass<RsElement> for gst_ffi::GstElementClass {}
|
||||||
|
|
||||||
struct ElementData {
|
// FIXME: Boilerplate
|
||||||
class_init: Box<Fn(&mut RsElementClass) + Send + 'static>,
|
impl ElementImpl for Box<ElementImpl> {
|
||||||
init: Box<Fn(&RsElement) -> Box<ElementImpl> + Send + Sync + 'static>,
|
fn change_state(
|
||||||
}
|
&self,
|
||||||
|
element: &gst::Element,
|
||||||
pub mod ffi {
|
transition: gst::StateChange,
|
||||||
use super::*;
|
) -> gst::StateChangeReturn {
|
||||||
use super::RsElement as RsElementWrapper;
|
let imp: &ElementImpl = self.as_ref();
|
||||||
|
imp.change_state(element, transition)
|
||||||
#[repr(C)]
|
|
||||||
pub struct RsElement {
|
|
||||||
parent: gst_ffi::GstElement,
|
|
||||||
imp: *const Box<ElementImpl>,
|
|
||||||
panicked: AtomicBool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RsElement {
|
|
||||||
pub fn get_impl(&self) -> &ElementImpl {
|
|
||||||
unsafe {
|
|
||||||
assert!(!self.imp.is_null());
|
|
||||||
&*(*self.imp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct RsElementClass {
|
|
||||||
parent_class: gst_ffi::GstElementClass,
|
|
||||||
element_data: *const ElementData,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn rs_element_get_type() -> glib_ffi::GType {
|
|
||||||
use std::sync::{Once, ONCE_INIT};
|
|
||||||
|
|
||||||
static mut TYPE: glib_ffi::GType = gobject_ffi::G_TYPE_INVALID;
|
|
||||||
static ONCE: Once = ONCE_INIT;
|
|
||||||
|
|
||||||
ONCE.call_once(|| {
|
|
||||||
let type_info = gobject_ffi::GTypeInfo {
|
|
||||||
class_size: mem::size_of::<RsElementClass>() as u16,
|
|
||||||
base_init: None,
|
|
||||||
base_finalize: None,
|
|
||||||
class_init: Some(element_class_init),
|
|
||||||
class_finalize: None,
|
|
||||||
class_data: ptr::null_mut(),
|
|
||||||
instance_size: mem::size_of::<RsElement>() as u16,
|
|
||||||
n_preallocs: 0,
|
|
||||||
instance_init: None,
|
|
||||||
value_table: ptr::null(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let type_name = {
|
|
||||||
let mut idx = 0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let type_name = CString::new(format!("RsElement-{}", idx)).unwrap();
|
|
||||||
if gobject_ffi::g_type_from_name(type_name.as_ptr()) ==
|
|
||||||
gobject_ffi::G_TYPE_INVALID
|
|
||||||
{
|
|
||||||
break type_name;
|
|
||||||
}
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TYPE = gobject_ffi::g_type_register_static(
|
|
||||||
gst_ffi::gst_element_get_type(),
|
|
||||||
type_name.as_ptr(),
|
|
||||||
&type_info,
|
|
||||||
gobject_ffi::GTypeFlags::empty(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
TYPE
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_finalize(obj: *mut gobject_ffi::GObject) {
|
|
||||||
callback_guard!();
|
|
||||||
let element = &mut *(obj as *mut RsElement);
|
|
||||||
|
|
||||||
drop(Box::from_raw(element.imp as *mut Box<ElementImpl>));
|
|
||||||
element.imp = ptr::null_mut();
|
|
||||||
|
|
||||||
let klass = *(obj as *const glib_ffi::gpointer);
|
|
||||||
let parent_klass = gobject_ffi::g_type_class_peek_parent(klass);
|
|
||||||
let parent_klass = &*(gobject_ffi::g_type_class_peek_parent(parent_klass) as
|
|
||||||
*const gobject_ffi::GObjectClass);
|
|
||||||
parent_klass.finalize.map(|f| f(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_sub_class_init(
|
|
||||||
klass: glib_ffi::gpointer,
|
|
||||||
klass_data: glib_ffi::gpointer,
|
|
||||||
) {
|
|
||||||
callback_guard!();
|
|
||||||
let element_data = &*(klass_data as *const ElementData);
|
|
||||||
|
|
||||||
{
|
|
||||||
let klass = &mut *(klass as *mut RsElementClass);
|
|
||||||
|
|
||||||
klass.element_data = element_data;
|
|
||||||
|
|
||||||
(element_data.class_init)(klass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_class_init(
|
|
||||||
klass: glib_ffi::gpointer,
|
|
||||||
_klass_data: glib_ffi::gpointer,
|
|
||||||
) {
|
|
||||||
callback_guard!();
|
|
||||||
{
|
|
||||||
let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass);
|
|
||||||
|
|
||||||
gobject_klass.finalize = Some(element_finalize);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let element_klass = &mut *(klass as *mut gst_ffi::GstElementClass);
|
|
||||||
|
|
||||||
element_klass.change_state = Some(element_change_state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_change_state(
|
|
||||||
ptr: *mut gst_ffi::GstElement,
|
|
||||||
transition: gst_ffi::GstStateChange,
|
|
||||||
) -> gst_ffi::GstStateChangeReturn {
|
|
||||||
callback_guard!();
|
|
||||||
let element = &*(ptr as *mut RsElement);
|
|
||||||
let wrap: RsElementWrapper = from_glib_borrow(ptr as *mut RsElement);
|
|
||||||
let imp = &*element.imp;
|
|
||||||
|
|
||||||
panic_to_error2!(&wrap, &element.panicked, gst::StateChangeReturn::Failure, {
|
|
||||||
imp.change_state(&wrap, from_glib(transition))
|
|
||||||
}).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_sub_init(
|
|
||||||
instance: *mut gobject_ffi::GTypeInstance,
|
|
||||||
klass: glib_ffi::gpointer,
|
|
||||||
) {
|
|
||||||
callback_guard!();
|
|
||||||
let element = &mut *(instance as *mut RsElement);
|
|
||||||
let wrap: RsElementWrapper = from_glib_borrow(instance as *mut RsElement);
|
|
||||||
let klass = &*(klass as *const RsElementClass);
|
|
||||||
let element_data = &*klass.element_data;
|
|
||||||
|
|
||||||
let imp = (element_data.init)(&wrap);
|
|
||||||
element.imp = Box::into_raw(Box::new(imp));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn element_register<F, G>(
|
|
||||||
plugin: &gst::Plugin,
|
|
||||||
name: &str,
|
|
||||||
rank: u32,
|
|
||||||
class_init: F,
|
|
||||||
init: G,
|
|
||||||
) where
|
|
||||||
F: Fn(&mut RsElementClass) + Send + 'static,
|
|
||||||
G: Fn(&RsElementWrapper) -> Box<ElementImpl> + Send + Sync + 'static,
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
let parent_type = rs_element_get_type();
|
|
||||||
let type_name = format!("RsElement-{}", name);
|
|
||||||
|
|
||||||
let element_data = ElementData {
|
|
||||||
class_init: Box::new(class_init),
|
|
||||||
init: Box::new(init),
|
|
||||||
};
|
|
||||||
let element_data = Box::into_raw(Box::new(element_data)) as glib_ffi::gpointer;
|
|
||||||
|
|
||||||
let type_info = gobject_ffi::GTypeInfo {
|
|
||||||
class_size: mem::size_of::<RsElementClass>() as u16,
|
|
||||||
base_init: None,
|
|
||||||
base_finalize: None,
|
|
||||||
class_init: Some(element_sub_class_init),
|
|
||||||
class_finalize: None,
|
|
||||||
class_data: element_data,
|
|
||||||
instance_size: mem::size_of::<RsElement>() as u16,
|
|
||||||
n_preallocs: 0,
|
|
||||||
instance_init: Some(element_sub_init),
|
|
||||||
value_table: ptr::null(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let type_ = gobject_ffi::g_type_register_static(
|
|
||||||
parent_type,
|
|
||||||
type_name.to_glib_none().0,
|
|
||||||
&type_info,
|
|
||||||
gobject_ffi::GTypeFlags::empty(),
|
|
||||||
);
|
|
||||||
|
|
||||||
gst::Element::register(plugin, &name, rank, from_glib(type_));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::ffi::RsElementClass;
|
impl ObjectType for RsElement {
|
||||||
pub use self::ffi::element_register;
|
const NAME: &'static str = "RsElement";
|
||||||
|
type GlibType = gst_ffi::GstElement;
|
||||||
|
type GlibClassType = gst_ffi::GstElementClass;
|
||||||
|
type RsType = RsElement;
|
||||||
|
type ImplType = Box<ElementImpl>;
|
||||||
|
|
||||||
|
fn glib_type() -> glib::Type {
|
||||||
|
unsafe { from_glib(gst_ffi::gst_element_get_type()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::GlibClassType) {
|
||||||
|
klass.override_vfuncs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn element_change_state<T: ObjectType>(
|
||||||
|
ptr: *mut gst_ffi::GstElement,
|
||||||
|
transition: gst_ffi::GstStateChange,
|
||||||
|
) -> gst_ffi::GstStateChangeReturn
|
||||||
|
where
|
||||||
|
T::RsType: IsA<gst::Element>,
|
||||||
|
T::ImplType: ElementImpl,
|
||||||
|
{
|
||||||
|
callback_guard!();
|
||||||
|
let element = &*(ptr as *mut InstanceStruct<T>);
|
||||||
|
let wrap: gst::Element = from_glib_borrow(ptr as *mut gst_ffi::GstElement);
|
||||||
|
let imp = &*element.imp;
|
||||||
|
|
||||||
|
panic_to_error2!(&wrap, &element.panicked, gst::StateChangeReturn::Failure, {
|
||||||
|
imp.change_state(&wrap, from_glib(transition))
|
||||||
|
}).to_glib()
|
||||||
|
}
|
||||||
|
|
|
@ -43,4 +43,6 @@ pub mod sink;
|
||||||
pub mod demuxer;
|
pub mod demuxer;
|
||||||
pub mod bytes;
|
pub mod bytes;
|
||||||
|
|
||||||
|
pub mod object;
|
||||||
pub mod element;
|
pub mod element;
|
||||||
|
pub mod base_src;
|
||||||
|
|
188
gst-plugin/src/object.rs
Normal file
188
gst-plugin/src/object.rs
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::ptr;
|
||||||
|
use std::mem;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
|
use glib_ffi;
|
||||||
|
use gobject_ffi;
|
||||||
|
|
||||||
|
use glib;
|
||||||
|
use glib::translate::*;
|
||||||
|
|
||||||
|
pub trait ImplTypeStatic<T: ObjectType>: Send + Sync + 'static {
|
||||||
|
fn get_name(&self) -> &str;
|
||||||
|
fn new(&self, &T::RsType) -> T::ImplType;
|
||||||
|
fn class_init(&self, &mut ClassStruct<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ObjectType: 'static
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
const NAME: &'static str;
|
||||||
|
type GlibType;
|
||||||
|
type GlibClassType;
|
||||||
|
type RsType: FromGlibPtrBorrow<*mut InstanceStruct<Self>>;
|
||||||
|
type ImplType: 'static;
|
||||||
|
|
||||||
|
fn glib_type() -> glib::Type;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::GlibClassType);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct InstanceStruct<T: ObjectType> {
|
||||||
|
pub parent: T::GlibType,
|
||||||
|
pub imp: *const T::ImplType,
|
||||||
|
pub panicked: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ObjectType> InstanceStruct<T> {
|
||||||
|
pub fn get_impl(&self) -> &T::ImplType {
|
||||||
|
unsafe { &*self.imp }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ClassStruct<T: ObjectType> {
|
||||||
|
pub parent: T::GlibClassType,
|
||||||
|
pub imp_static: *const Box<ImplTypeStatic<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn class_init<T: ObjectType>(
|
||||||
|
klass: glib_ffi::gpointer,
|
||||||
|
_klass_data: glib_ffi::gpointer,
|
||||||
|
) {
|
||||||
|
callback_guard!();
|
||||||
|
{
|
||||||
|
let gobject_klass = &mut *(klass as *mut gobject_ffi::GObjectClass);
|
||||||
|
|
||||||
|
gobject_klass.finalize = Some(finalize::<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
T::class_init(&mut *(klass as *mut T::GlibClassType));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn finalize<T: ObjectType>(obj: *mut gobject_ffi::GObject) {
|
||||||
|
callback_guard!();
|
||||||
|
let instance = &mut *(obj as *mut InstanceStruct<T>);
|
||||||
|
|
||||||
|
drop(Box::from_raw(instance.imp as *mut T::ImplType));
|
||||||
|
instance.imp = ptr::null_mut();
|
||||||
|
|
||||||
|
let klass = *(obj as *const glib_ffi::gpointer);
|
||||||
|
let parent_klass = gobject_ffi::g_type_class_peek_parent(klass);
|
||||||
|
let parent_klass =
|
||||||
|
&*(gobject_ffi::g_type_class_peek_parent(parent_klass) as *const gobject_ffi::GObjectClass);
|
||||||
|
parent_klass.finalize.map(|f| f(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_type<T: ObjectType>() -> glib_ffi::GType {
|
||||||
|
use std::sync::{Once, ONCE_INIT};
|
||||||
|
|
||||||
|
static mut TYPE: glib_ffi::GType = gobject_ffi::G_TYPE_INVALID;
|
||||||
|
static ONCE: Once = ONCE_INIT;
|
||||||
|
|
||||||
|
ONCE.call_once(|| {
|
||||||
|
let type_info = gobject_ffi::GTypeInfo {
|
||||||
|
class_size: mem::size_of::<ClassStruct<T>>() as u16,
|
||||||
|
base_init: None,
|
||||||
|
base_finalize: None,
|
||||||
|
class_init: Some(class_init::<T>),
|
||||||
|
class_finalize: None,
|
||||||
|
class_data: ptr::null_mut(),
|
||||||
|
instance_size: mem::size_of::<InstanceStruct<T>>() as u16,
|
||||||
|
n_preallocs: 0,
|
||||||
|
instance_init: None,
|
||||||
|
value_table: ptr::null(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_name = {
|
||||||
|
let mut idx = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let type_name = CString::new(format!("{}-{}", T::NAME, idx)).unwrap();
|
||||||
|
if gobject_ffi::g_type_from_name(type_name.as_ptr()) == gobject_ffi::G_TYPE_INVALID
|
||||||
|
{
|
||||||
|
break type_name;
|
||||||
|
}
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TYPE = gobject_ffi::g_type_register_static(
|
||||||
|
T::glib_type().to_glib(),
|
||||||
|
type_name.as_ptr(),
|
||||||
|
&type_info,
|
||||||
|
gobject_ffi::GTypeFlags::empty(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
TYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn sub_class_init<T: ObjectType>(
|
||||||
|
klass: glib_ffi::gpointer,
|
||||||
|
klass_data: glib_ffi::gpointer,
|
||||||
|
) {
|
||||||
|
callback_guard!();
|
||||||
|
{
|
||||||
|
let klass = &mut *(klass as *mut ClassStruct<T>);
|
||||||
|
let imp_static = klass_data as *const Box<ImplTypeStatic<T>>;
|
||||||
|
klass.imp_static = imp_static;
|
||||||
|
|
||||||
|
(*imp_static).class_init(klass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn sub_init<T: ObjectType>(
|
||||||
|
obj: *mut gobject_ffi::GTypeInstance,
|
||||||
|
_klass: glib_ffi::gpointer,
|
||||||
|
) {
|
||||||
|
callback_guard!();
|
||||||
|
let instance = &mut *(obj as *mut InstanceStruct<T>);
|
||||||
|
let klass = &**(obj as *const *const ClassStruct<T>);
|
||||||
|
let rs_instance: T::RsType = from_glib_borrow(obj as *mut InstanceStruct<T>);
|
||||||
|
|
||||||
|
let imp = (*klass.imp_static).new(&rs_instance);
|
||||||
|
instance.imp = Box::into_raw(Box::new(imp));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_type<T: ObjectType, I: ImplTypeStatic<T>>(imp: I) -> glib::Type {
|
||||||
|
unsafe {
|
||||||
|
let parent_type = get_type::<T>();
|
||||||
|
let type_name = format!("{}-{}", T::NAME, imp.get_name());
|
||||||
|
|
||||||
|
let imp: Box<ImplTypeStatic<T>> = Box::new(imp);
|
||||||
|
|
||||||
|
let type_info = gobject_ffi::GTypeInfo {
|
||||||
|
class_size: mem::size_of::<ClassStruct<T>>() as u16,
|
||||||
|
base_init: None,
|
||||||
|
base_finalize: None,
|
||||||
|
class_init: Some(sub_class_init::<T>),
|
||||||
|
class_finalize: None,
|
||||||
|
class_data: Box::into_raw(Box::new(imp)) as glib_ffi::gpointer,
|
||||||
|
instance_size: mem::size_of::<InstanceStruct<T>>() as u16,
|
||||||
|
n_preallocs: 0,
|
||||||
|
instance_init: Some(sub_init::<T>),
|
||||||
|
value_table: ptr::null(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let type_ = gobject_ffi::g_type_register_static(
|
||||||
|
parent_type,
|
||||||
|
type_name.to_glib_none().0,
|
||||||
|
&type_info,
|
||||||
|
gobject_ffi::GTypeFlags::empty(),
|
||||||
|
);
|
||||||
|
|
||||||
|
from_glib(type_)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue