mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-01-23 01:18:11 +00:00
Add support for subclassing GstAggregator and GstAggregatorPad
This commit is contained in:
parent
bf63a823cd
commit
5e55ed6b6c
4 changed files with 1036 additions and 0 deletions
|
@ -27,3 +27,9 @@ gstreamer-base = { git = "https://github.com/sdroege/gstreamer-rs" }
|
|||
[lib]
|
||||
name = "gst_plugin"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[features]
|
||||
v1_10 = ["gstreamer/v1_10", "gstreamer-base/v1_10"]
|
||||
v1_12 = ["gstreamer/v1_12", "gstreamer-base/v1_12", "v1_10"]
|
||||
v1_14 = ["gstreamer/v1_14", "gstreamer-base/v1_14", "v1_12"]
|
||||
|
||||
|
|
857
gst-plugin/src/aggregator.rs
Normal file
857
gst-plugin/src/aggregator.rs
Normal file
|
@ -0,0 +1,857 @@
|
|||
// 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::mem;
|
||||
use std::ptr;
|
||||
|
||||
use libc;
|
||||
|
||||
use glib_ffi;
|
||||
use gobject_ffi;
|
||||
use gst_base_ffi;
|
||||
use gst_ffi;
|
||||
|
||||
use glib;
|
||||
use glib::translate::*;
|
||||
use gst;
|
||||
use gst::prelude::*;
|
||||
use gst_base;
|
||||
|
||||
use gobject_subclass::anyimpl::*;
|
||||
use gobject_subclass::object::*;
|
||||
|
||||
use element::*;
|
||||
use object::*;
|
||||
|
||||
pub trait AggregatorImpl<T: AggregatorBase>:
|
||||
AnyImpl + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static
|
||||
where
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
fn flush(&self, aggregator: &T) -> gst::FlowReturn {
|
||||
aggregator.parent_flush()
|
||||
}
|
||||
|
||||
fn clip(
|
||||
&self,
|
||||
aggregator: &T,
|
||||
aggregator_pad: &gst_base::AggregatorPad,
|
||||
buffer: gst::Buffer,
|
||||
) -> Option<gst::Buffer> {
|
||||
aggregator.parent_clip(aggregator_pad, buffer)
|
||||
}
|
||||
|
||||
fn finish_buffer(&self, aggregator: &T, buffer: gst::Buffer) -> gst::FlowReturn {
|
||||
aggregator.parent_finish_buffer(buffer)
|
||||
}
|
||||
|
||||
fn sink_event(
|
||||
&self,
|
||||
aggregator: &T,
|
||||
aggregator_pad: &gst_base::AggregatorPad,
|
||||
event: gst::Event,
|
||||
) -> bool {
|
||||
aggregator.parent_sink_event(aggregator_pad, event)
|
||||
}
|
||||
|
||||
fn sink_query(
|
||||
&self,
|
||||
aggregator: &T,
|
||||
aggregator_pad: &gst_base::AggregatorPad,
|
||||
query: &mut gst::QueryRef,
|
||||
) -> bool {
|
||||
aggregator.parent_sink_query(aggregator_pad, query)
|
||||
}
|
||||
|
||||
fn src_event(&self, aggregator: &T, event: gst::Event) -> bool {
|
||||
aggregator.parent_src_event(event)
|
||||
}
|
||||
|
||||
fn src_query(&self, aggregator: &T, query: &mut gst::QueryRef) -> bool {
|
||||
aggregator.parent_src_query(query)
|
||||
}
|
||||
|
||||
fn src_activate(&self, aggregator: &T, mode: gst::PadMode, active: bool) -> bool {
|
||||
aggregator.parent_src_activate(mode, active)
|
||||
}
|
||||
|
||||
fn aggregate(&self, aggregator: &T, timeout: bool) -> gst::FlowReturn;
|
||||
|
||||
fn start(&self, aggregator: &T) -> bool {
|
||||
aggregator.parent_start()
|
||||
}
|
||||
|
||||
fn stop(&self, aggregator: &T) -> bool {
|
||||
aggregator.parent_stop()
|
||||
}
|
||||
|
||||
fn get_next_time(&self, aggregator: &T) -> gst::ClockTime {
|
||||
aggregator.parent_get_next_time()
|
||||
}
|
||||
|
||||
fn create_new_pad(
|
||||
&self,
|
||||
aggregator: &T,
|
||||
templ: &gst::PadTemplate,
|
||||
req_name: Option<&str>,
|
||||
caps: Option<&gst::CapsRef>,
|
||||
) -> Option<gst_base::AggregatorPad> {
|
||||
aggregator.parent_create_new_pad(templ, req_name, caps)
|
||||
}
|
||||
|
||||
fn update_src_caps(
|
||||
&self,
|
||||
aggregator: &T,
|
||||
caps: &gst::CapsRef,
|
||||
) -> Result<gst::Caps, gst::FlowReturn> {
|
||||
aggregator.parent_update_src_caps(caps)
|
||||
}
|
||||
|
||||
fn fixate_src_caps(&self, aggregator: &T, caps: gst::Caps) -> gst::Caps {
|
||||
aggregator.parent_fixate_src_caps(caps)
|
||||
}
|
||||
|
||||
fn negotiated_src_caps(&self, aggregator: &T, caps: &gst::CapsRef) -> bool {
|
||||
aggregator.parent_negotiated_src_caps(caps)
|
||||
}
|
||||
}
|
||||
|
||||
any_impl!(AggregatorBase, AggregatorImpl, PanicPoison);
|
||||
|
||||
pub unsafe trait AggregatorBase:
|
||||
IsA<gst::Element> + IsA<gst_base::Aggregator> + ObjectType
|
||||
{
|
||||
fn parent_flush(&self) -> gst::FlowReturn {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.flush
|
||||
.map(|f| from_glib(f(self.to_glib_none().0)))
|
||||
.unwrap_or(gst::FlowReturn::Ok)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_clip(
|
||||
&self,
|
||||
aggregator_pad: &gst_base::AggregatorPad,
|
||||
buffer: gst::Buffer,
|
||||
) -> Option<gst::Buffer> {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
match (*parent_klass).clip {
|
||||
None => Some(buffer),
|
||||
Some(ref func) => from_glib_full(func(
|
||||
self.to_glib_none().0,
|
||||
aggregator_pad.to_glib_none().0,
|
||||
buffer.into_ptr(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_finish_buffer(&self, buffer: gst::Buffer) -> gst::FlowReturn {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.finish_buffer
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, buffer.into_ptr())))
|
||||
.unwrap_or(gst::FlowReturn::Ok)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_sink_event(
|
||||
&self,
|
||||
aggregator_pad: &gst_base::AggregatorPad,
|
||||
event: gst::Event,
|
||||
) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.sink_event
|
||||
.map(|f| {
|
||||
from_glib(f(
|
||||
self.to_glib_none().0,
|
||||
aggregator_pad.to_glib_none().0,
|
||||
event.into_ptr(),
|
||||
))
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_sink_query(
|
||||
&self,
|
||||
aggregator_pad: &gst_base::AggregatorPad,
|
||||
query: &mut gst::QueryRef,
|
||||
) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.sink_query
|
||||
.map(|f| {
|
||||
from_glib(f(
|
||||
self.to_glib_none().0,
|
||||
aggregator_pad.to_glib_none().0,
|
||||
query.as_mut_ptr(),
|
||||
))
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_src_event(&self, event: gst::Event) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.src_event
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, event.into_ptr())))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_src_query(&self, query: &mut gst::QueryRef) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.src_query
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_src_activate(&self, mode: gst::PadMode, active: bool) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.src_activate
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, mode.to_glib(), active.to_glib())))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_aggregate(&self, timeout: bool) -> gst::FlowReturn {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.aggregate
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, timeout.to_glib())))
|
||||
.unwrap_or(gst::FlowReturn::Error)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_start(&self) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.start
|
||||
.map(|f| from_glib(f(self.to_glib_none().0)))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_stop(&self) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.stop
|
||||
.map(|f| from_glib(f(self.to_glib_none().0)))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_get_next_time(&self) -> gst::ClockTime {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.get_next_time
|
||||
.map(|f| from_glib(f(self.to_glib_none().0)))
|
||||
.unwrap_or(gst::CLOCK_TIME_NONE)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_create_new_pad(
|
||||
&self,
|
||||
templ: &gst::PadTemplate,
|
||||
req_name: Option<&str>,
|
||||
caps: Option<&gst::CapsRef>,
|
||||
) -> Option<gst_base::AggregatorPad> {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.create_new_pad
|
||||
.map(|f| {
|
||||
from_glib_full(f(
|
||||
self.to_glib_none().0,
|
||||
templ.to_glib_none().0,
|
||||
req_name.to_glib_none().0,
|
||||
caps.map(|c| c.as_ptr()).unwrap_or(ptr::null()),
|
||||
))
|
||||
})
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_update_src_caps(&self, caps: &gst::CapsRef) -> Result<gst::Caps, gst::FlowReturn> {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.update_src_caps
|
||||
.map(|f| {
|
||||
let mut out_caps = ptr::null_mut();
|
||||
let flow_ret =
|
||||
from_glib(f(self.to_glib_none().0, caps.as_mut_ptr(), &mut out_caps));
|
||||
if flow_ret == gst::FlowReturn::Ok {
|
||||
Ok(from_glib_full(out_caps))
|
||||
} else {
|
||||
Err(flow_ret)
|
||||
}
|
||||
})
|
||||
.unwrap_or(Err(gst::FlowReturn::Error))
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_fixate_src_caps(&self, caps: gst::Caps) -> gst::Caps {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
|
||||
match (*parent_klass).fixate_src_caps {
|
||||
Some(ref f) => from_glib_full(f(self.to_glib_none().0, caps.into_ptr())),
|
||||
None => caps,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_negotiated_src_caps(&self, caps: &gst::CapsRef) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorClass;
|
||||
(*parent_klass)
|
||||
.negotiated_src_caps
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, caps.as_mut_ptr())))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe trait AggregatorClassExt<T: AggregatorBase>
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
||||
unsafe {
|
||||
let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstAggregatorClass);
|
||||
klass.flush = Some(aggregator_flush::<T>);
|
||||
klass.clip = Some(aggregator_clip::<T>);
|
||||
klass.finish_buffer = Some(aggregator_finish_buffer::<T>);
|
||||
klass.sink_event = Some(aggregator_sink_event::<T>);
|
||||
klass.sink_query = Some(aggregator_sink_query::<T>);
|
||||
klass.src_event = Some(aggregator_src_event::<T>);
|
||||
klass.src_query = Some(aggregator_src_query::<T>);
|
||||
klass.src_activate = Some(aggregator_src_activate::<T>);
|
||||
klass.aggregate = Some(aggregator_aggregate::<T>);
|
||||
klass.start = Some(aggregator_start::<T>);
|
||||
klass.stop = Some(aggregator_stop::<T>);
|
||||
klass.get_next_time = Some(aggregator_get_next_time::<T>);
|
||||
klass.create_new_pad = Some(aggregator_create_new_pad::<T>);
|
||||
klass.update_src_caps = Some(aggregator_update_src_caps::<T>);
|
||||
klass.fixate_src_caps = Some(aggregator_fixate_src_caps::<T>);
|
||||
klass.negotiated_src_caps = Some(aggregator_negotiated_src_caps::<T>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib_wrapper! {
|
||||
pub struct Aggregator(Object<ElementInstanceStruct<Aggregator>>):
|
||||
[gst_base::Aggregator => gst_base_ffi::GstAggregator,
|
||||
gst::Element => gst_ffi::GstElement,
|
||||
gst::Object => gst_ffi::GstObject];
|
||||
|
||||
match fn {
|
||||
get_type => || get_type::<Aggregator>(),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: IsA<gst::Element> + IsA<gst_base::Aggregator> + ObjectType> AggregatorBase for T {}
|
||||
pub type AggregatorClass = ClassStruct<Aggregator>;
|
||||
|
||||
// FIXME: Boilerplate
|
||||
unsafe impl AggregatorClassExt<Aggregator> for AggregatorClass {}
|
||||
unsafe impl ElementClassExt<Aggregator> for AggregatorClass {}
|
||||
unsafe impl ObjectClassExt<Aggregator> for AggregatorClass {}
|
||||
|
||||
unsafe impl Send for Aggregator {}
|
||||
unsafe impl Sync for Aggregator {}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! box_aggregator_impl(
|
||||
($name:ident) => {
|
||||
box_element_impl!($name);
|
||||
|
||||
impl<T: AggregatorBase> AggregatorImpl<T> for Box<$name<T>>
|
||||
where
|
||||
T::InstanceStructType: PanicPoison
|
||||
{
|
||||
fn flush(&self, aggregator: &T) -> gst::FlowReturn {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.flush(aggregator)
|
||||
}
|
||||
|
||||
fn clip(&self, aggregator: &T, aggregator_pad: &gst_base::AggregatorPad, buffer: gst::Buffer) -> Option<gst::Buffer> {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.clip(aggregator, aggregator_pad, buffer)
|
||||
}
|
||||
|
||||
fn finish_buffer(&self, aggregator: &T, buffer: gst::Buffer) -> gst::FlowReturn {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.finish_buffer(aggregator, buffer)
|
||||
}
|
||||
|
||||
fn sink_event(&self, aggregator: &T, aggregator_pad: &gst_base::AggregatorPad, event: gst::Event) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.sink_event(aggregator, aggregator_pad, event)
|
||||
}
|
||||
|
||||
fn sink_query(&self, aggregator: &T, aggregator_pad: &gst_base::AggregatorPad, query: &mut gst::QueryRef) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.sink_query(aggregator, aggregator_pad, query)
|
||||
}
|
||||
|
||||
fn src_event(&self, aggregator: &T, event: gst::Event) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.src_event(aggregator, event)
|
||||
}
|
||||
|
||||
fn src_query(&self, aggregator: &T, query: &mut gst::QueryRef) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.src_query(aggregator, query)
|
||||
}
|
||||
|
||||
fn src_activate(&self, aggregator: &T, mode: gst::PadMode, active: bool) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.src_activate(aggregator, mode, active)
|
||||
}
|
||||
|
||||
fn aggregate(&self, aggregator: &T, timeout: bool) -> gst::FlowReturn {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.aggregate(aggregator, timeout)
|
||||
}
|
||||
|
||||
fn start(&self, aggregator: &T) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.start(aggregator)
|
||||
}
|
||||
|
||||
fn stop(&self, aggregator: &T) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.stop(aggregator)
|
||||
}
|
||||
|
||||
fn get_next_time(&self, aggregator: &T) -> gst::ClockTime {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.get_next_time(aggregator)
|
||||
}
|
||||
|
||||
fn create_new_pad(&self, aggregator: &T, templ: &gst::PadTemplate, req_name: Option<&str>, caps: Option<&gst::CapsRef>) -> Option<gst_base::AggregatorPad> {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.create_new_pad(aggregator, templ, req_name, caps)
|
||||
}
|
||||
|
||||
fn update_src_caps(&self, aggregator: &T, caps: &gst::CapsRef) -> Result<gst::Caps, gst::FlowReturn> {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.update_src_caps(aggregator, caps)
|
||||
}
|
||||
|
||||
fn fixate_src_caps(&self, aggregator: &T, caps: gst::Caps) -> gst::Caps {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.fixate_src_caps(aggregator, caps)
|
||||
}
|
||||
|
||||
fn negotiated_src_caps(&self, aggregator: &T, caps: &gst::CapsRef) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.negotiated_src_caps(aggregator, caps)
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
box_aggregator_impl!(AggregatorImpl);
|
||||
|
||||
impl ObjectType for Aggregator {
|
||||
const NAME: &'static str = "RsAggregator";
|
||||
type ParentType = gst_base::Aggregator;
|
||||
type ImplType = Box<AggregatorImpl<Self>>;
|
||||
type InstanceStructType = ElementInstanceStruct<Self>;
|
||||
|
||||
fn class_init(token: &ClassInitToken, klass: &mut AggregatorClass) {
|
||||
ElementClassExt::override_vfuncs(klass, token);
|
||||
AggregatorClassExt::override_vfuncs(klass, token);
|
||||
}
|
||||
|
||||
object_type_fns!();
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_flush<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
) -> gst_ffi::GstFlowReturn
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), gst::FlowReturn::Error, {
|
||||
imp.flush(&wrap)
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_clip<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
aggregator_pad: *mut gst_base_ffi::GstAggregatorPad,
|
||||
buffer: *mut gst_ffi::GstBuffer,
|
||||
) -> *mut gst_ffi::GstBuffer
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
let ret = panic_to_error!(&wrap, &aggregator.panicked(), None, {
|
||||
imp.clip(
|
||||
&wrap,
|
||||
&from_glib_borrow(aggregator_pad),
|
||||
from_glib_full(buffer),
|
||||
)
|
||||
});
|
||||
|
||||
ret.map(|r| r.into_ptr()).unwrap_or(ptr::null_mut())
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_finish_buffer<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
buffer: *mut gst_ffi::GstBuffer,
|
||||
) -> gst_ffi::GstFlowReturn
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), gst::FlowReturn::Error, {
|
||||
imp.finish_buffer(&wrap, from_glib_full(buffer))
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_sink_event<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
aggregator_pad: *mut gst_base_ffi::GstAggregatorPad,
|
||||
event: *mut gst_ffi::GstEvent,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, {
|
||||
imp.sink_event(
|
||||
&wrap,
|
||||
&from_glib_borrow(aggregator_pad),
|
||||
from_glib_full(event),
|
||||
)
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_sink_query<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
aggregator_pad: *mut gst_base_ffi::GstAggregatorPad,
|
||||
query: *mut gst_ffi::GstQuery,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, {
|
||||
imp.sink_query(
|
||||
&wrap,
|
||||
&from_glib_borrow(aggregator_pad),
|
||||
gst::QueryRef::from_mut_ptr(query),
|
||||
)
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_src_event<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
event: *mut gst_ffi::GstEvent,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, {
|
||||
imp.src_event(&wrap, from_glib_full(event))
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_src_query<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
query: *mut gst_ffi::GstQuery,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, {
|
||||
imp.src_query(&wrap, gst::QueryRef::from_mut_ptr(query))
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_src_activate<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
mode: gst_ffi::GstPadMode,
|
||||
active: glib_ffi::gboolean,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, {
|
||||
imp.src_activate(&wrap, from_glib(mode), from_glib(active))
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_aggregate<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
timeout: glib_ffi::gboolean,
|
||||
) -> gst_ffi::GstFlowReturn
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), gst::FlowReturn::Error, {
|
||||
imp.aggregate(&wrap, from_glib(timeout))
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_start<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, { imp.start(&wrap) }).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_stop<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, { imp.stop(&wrap) }).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_get_next_time<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
) -> gst_ffi::GstClockTime
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), gst::CLOCK_TIME_NONE, {
|
||||
imp.get_next_time(&wrap)
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_create_new_pad<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
templ: *mut gst_ffi::GstPadTemplate,
|
||||
req_name: *const libc::c_char,
|
||||
caps: *const gst_ffi::GstCaps,
|
||||
) -> *mut gst_base_ffi::GstAggregatorPad
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), None, {
|
||||
let req_name: Option<String> = from_glib_none(req_name);
|
||||
|
||||
// FIXME: Easier way to convert Option<String> to Option<&str>?
|
||||
let mut _tmp = String::new();
|
||||
let req_name = match req_name {
|
||||
Some(n) => {
|
||||
_tmp = n;
|
||||
Some(_tmp.as_str())
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
imp.create_new_pad(
|
||||
&wrap,
|
||||
&from_glib_borrow(templ),
|
||||
req_name,
|
||||
if caps.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(gst::CapsRef::from_ptr(caps))
|
||||
},
|
||||
)
|
||||
}).to_glib_full()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_update_src_caps<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
caps: *mut gst_ffi::GstCaps,
|
||||
res: *mut *mut gst_ffi::GstCaps,
|
||||
) -> gst_ffi::GstFlowReturn
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
*res = ptr::null_mut();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), gst::FlowReturn::Error, {
|
||||
match imp.update_src_caps(&wrap, gst::CapsRef::from_ptr(caps)) {
|
||||
Ok(res_caps) => {
|
||||
*res = res_caps.into_ptr();
|
||||
gst::FlowReturn::Ok
|
||||
}
|
||||
Err(err) => err,
|
||||
}
|
||||
}).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_fixate_src_caps<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
caps: *mut gst_ffi::GstCaps,
|
||||
) -> *mut gst_ffi::GstCaps
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), gst::Caps::new_empty(), {
|
||||
imp.fixate_src_caps(&wrap, from_glib_full(caps))
|
||||
}).into_ptr()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_negotiated_src_caps<T: AggregatorBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregator,
|
||||
caps: *mut gst_ffi::GstCaps,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorImpl<T>,
|
||||
T::InstanceStructType: PanicPoison,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator.get_impl();
|
||||
|
||||
panic_to_error!(&wrap, &aggregator.panicked(), false, {
|
||||
imp.negotiated_src_caps(&wrap, gst::CapsRef::from_ptr(caps))
|
||||
}).to_glib()
|
||||
}
|
167
gst-plugin/src/aggregator_pad.rs
Normal file
167
gst-plugin/src/aggregator_pad.rs
Normal file
|
@ -0,0 +1,167 @@
|
|||
// Copyright (C) 2018 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::mem;
|
||||
use std::ptr;
|
||||
|
||||
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 gobject_subclass::anyimpl::*;
|
||||
use gobject_subclass::object::*;
|
||||
|
||||
use pad::*;
|
||||
|
||||
pub trait AggregatorPadImpl<T: AggregatorPadBase>:
|
||||
AnyImpl + ObjectImpl<T> + PadImpl<T> + Send + Sync + 'static
|
||||
{
|
||||
fn flush(&self, aggregator_pad: &T, aggregator: &gst_base::Aggregator) -> gst::FlowReturn {
|
||||
aggregator_pad.parent_flush(aggregator)
|
||||
}
|
||||
|
||||
fn skip_buffer(&self, aggregator_pad: &T, aggregator: &gst_base::Aggregator, buffer: &gst::BufferRef) -> bool {
|
||||
aggregator_pad.parent_skip_buffer(aggregator, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
any_impl!(AggregatorPadBase, AggregatorPadImpl);
|
||||
|
||||
pub unsafe trait AggregatorPadBase: IsA<gst_base::AggregatorPad> + IsA<gst::Pad> + ObjectType {
|
||||
fn parent_flush(&self, aggregator: &gst_base::Aggregator) -> gst::FlowReturn {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorPadClass;
|
||||
(*parent_klass)
|
||||
.flush
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, aggregator.to_glib_none().0)))
|
||||
.unwrap_or(gst::FlowReturn::Ok)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_skip_buffer(&self, aggregator: &gst_base::Aggregator, buffer: &gst::BufferRef) -> bool {
|
||||
unsafe {
|
||||
let klass = self.get_class();
|
||||
let parent_klass =
|
||||
(*klass).get_parent_class() as *const gst_base_ffi::GstAggregatorPadClass;
|
||||
(*parent_klass)
|
||||
.skip_buffer
|
||||
.map(|f| from_glib(f(self.to_glib_none().0, aggregator.to_glib_none().0, buffer.as_mut_ptr())))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe trait AggregatorPadClassExt<T: AggregatorPadBase>
|
||||
where
|
||||
T::ImplType: AggregatorPadImpl<T>,
|
||||
{
|
||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
||||
unsafe {
|
||||
let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstAggregatorPadClass);
|
||||
klass.flush = Some(aggregator_pad_flush::<T>);
|
||||
klass.skip_buffer = Some(aggregator_pad_skip_buffer::<T>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib_wrapper! {
|
||||
pub struct AggregatorPad(Object<InstanceStruct<AggregatorPad>>):
|
||||
[gst_base::AggregatorPad => gst_base_ffi::GstAggregatorPad,
|
||||
gst::Pad => gst_ffi::GstPad,
|
||||
gst::Object => gst_ffi::GstObject];
|
||||
|
||||
match fn {
|
||||
get_type => || get_type::<AggregatorPad>(),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: IsA<gst_base::AggregatorPad> + IsA<gst::Pad> + ObjectType> AggregatorPadBase for T {}
|
||||
pub type AggregatorPadClass = ClassStruct<AggregatorPad>;
|
||||
|
||||
// FIXME: Boilerplate
|
||||
unsafe impl AggregatorPadClassExt<AggregatorPad> for AggregatorPadClass {}
|
||||
unsafe impl PadClassExt<AggregatorPad> for AggregatorPadClass {}
|
||||
unsafe impl ObjectClassExt<AggregatorPad> for AggregatorPadClass {}
|
||||
|
||||
unsafe impl Send for AggregatorPad {}
|
||||
unsafe impl Sync for AggregatorPad {}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! box_aggregator_pad_impl(
|
||||
($name:ident) => {
|
||||
box_pad_impl!($name);
|
||||
|
||||
impl<T: AggregatorPadBase> AggregatorPadImpl<T> for Box<$name<T>>
|
||||
{
|
||||
fn flush(&self, aggregator_pad: &T, aggregator: &gst_base::Aggregator) -> gst::FlowReturn {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.flush(aggregator_pad, aggregator)
|
||||
}
|
||||
|
||||
fn skip_buffer(&self, aggregator_pad: &T, aggregator: &gst_base::Aggregator, buffer: &gst::BufferRef) -> bool {
|
||||
let imp: &$name<T> = self.as_ref();
|
||||
imp.skip_buffer(aggregator_pad, aggregator, buffer)
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
box_aggregator_pad_impl!(AggregatorPadImpl);
|
||||
|
||||
impl ObjectType for AggregatorPad {
|
||||
const NAME: &'static str = "RsAggregatorPad";
|
||||
type ParentType = gst_base::AggregatorPad;
|
||||
type ImplType = Box<AggregatorPadImpl<Self>>;
|
||||
type InstanceStructType = InstanceStruct<Self>;
|
||||
|
||||
fn class_init(token: &ClassInitToken, klass: &mut AggregatorPadClass) {
|
||||
PadClassExt::override_vfuncs(klass, token);
|
||||
AggregatorPadClassExt::override_vfuncs(klass, token);
|
||||
}
|
||||
|
||||
object_type_fns!();
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_pad_flush<T: AggregatorPadBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregatorPad,
|
||||
aggregator: *mut gst_base_ffi::GstAggregator,
|
||||
) -> gst_ffi::GstFlowReturn
|
||||
where
|
||||
T::ImplType: AggregatorPadImpl<T>,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator_pad = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator_pad.get_impl();
|
||||
|
||||
imp.flush(&wrap, &from_glib_borrow(aggregator)).to_glib()
|
||||
}
|
||||
|
||||
unsafe extern "C" fn aggregator_pad_skip_buffer<T: AggregatorPadBase>(
|
||||
ptr: *mut gst_base_ffi::GstAggregatorPad,
|
||||
aggregator: *mut gst_base_ffi::GstAggregator,
|
||||
buffer: *mut gst_ffi::GstBuffer,
|
||||
) -> glib_ffi::gboolean
|
||||
where
|
||||
T::ImplType: AggregatorPadImpl<T>,
|
||||
{
|
||||
floating_reference_guard!(ptr);
|
||||
let aggregator_pad = &*(ptr as *mut T::InstanceStructType);
|
||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
||||
let imp = aggregator_pad.get_impl();
|
||||
|
||||
imp.skip_buffer(&wrap, &from_glib_borrow(aggregator), gst::BufferRef::from_ptr(buffer)).to_glib()
|
||||
}
|
|
@ -47,11 +47,17 @@ pub mod base_src;
|
|||
pub mod base_sink;
|
||||
#[macro_use]
|
||||
pub mod base_transform;
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
#[macro_use]
|
||||
pub mod aggregator;
|
||||
|
||||
#[macro_use]
|
||||
pub mod pad;
|
||||
#[macro_use]
|
||||
pub mod ghost_pad;
|
||||
#[cfg(any(feature = "v1_14", feature = "dox"))]
|
||||
#[macro_use]
|
||||
pub mod aggregator_pad;
|
||||
|
||||
pub mod child_proxy;
|
||||
pub mod uri_handler;
|
||||
|
|
Loading…
Reference in a new issue