mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-01-11 11:45:30 +00:00
Remove gst-plugin and gst-plugin-simple crates
They're not used anymore.
This commit is contained in:
parent
4b4ae6d52c
commit
abe87fae12
28 changed files with 0 additions and 6760 deletions
|
@ -1,8 +1,6 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
"gst-plugin",
|
|
||||||
"gst-plugin-simple",
|
|
||||||
"gst-plugin-file",
|
"gst-plugin-file",
|
||||||
"gst-plugin-http",
|
"gst-plugin-http",
|
||||||
"gst-plugin-flv",
|
"gst-plugin-flv",
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "gst-plugin-simple"
|
|
||||||
version = "0.4.0"
|
|
||||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
|
||||||
repository = "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs"
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
url = "1.1"
|
|
||||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
|
||||||
gobject-subclass = { git = "https://github.com/gtk-rs/gobject-subclass" }
|
|
||||||
gst-plugin = { path="../gst-plugin" }
|
|
||||||
gstreamer = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
|
||||||
gstreamer-base = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "gst_plugin_simple"
|
|
||||||
path = "src/lib.rs"
|
|
|
@ -1,689 +0,0 @@
|
||||||
// Copyright (C) 2016-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::sync::Mutex;
|
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::u32;
|
|
||||||
use std::u64;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
use gst_plugin::error::*;
|
|
||||||
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
use gst_base;
|
|
||||||
|
|
||||||
pub type StreamIndex = u32;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum SeekResult {
|
|
||||||
TooEarly,
|
|
||||||
Ok(u64),
|
|
||||||
Eos,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum HandleBufferResult {
|
|
||||||
NeedMoreData,
|
|
||||||
Again,
|
|
||||||
// NeedDataFromOffset(u64),
|
|
||||||
StreamAdded(Stream),
|
|
||||||
HaveAllStreams,
|
|
||||||
StreamChanged(Stream),
|
|
||||||
// StreamsAdded(Vec<Stream>), // Implies HaveAllStreams
|
|
||||||
StreamsChanged(Vec<Stream>),
|
|
||||||
// TODO need something to replace/add new streams
|
|
||||||
// TODO should probably directly implement the GstStreams new world order
|
|
||||||
BufferForStream(StreamIndex, gst::Buffer),
|
|
||||||
Eos(Option<StreamIndex>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DemuxerImpl: Send + 'static {
|
|
||||||
fn start(
|
|
||||||
&mut self,
|
|
||||||
demuxer: &Element,
|
|
||||||
upstream_size: Option<u64>,
|
|
||||||
random_access: bool,
|
|
||||||
) -> Result<(), gst::ErrorMessage>;
|
|
||||||
fn stop(&mut self, demuxer: &Element) -> Result<(), gst::ErrorMessage>;
|
|
||||||
|
|
||||||
fn seek(
|
|
||||||
&mut self,
|
|
||||||
demuxer: &Element,
|
|
||||||
start: gst::ClockTime,
|
|
||||||
stop: gst::ClockTime,
|
|
||||||
) -> Result<SeekResult, gst::ErrorMessage>;
|
|
||||||
fn handle_buffer(
|
|
||||||
&mut self,
|
|
||||||
demuxer: &Element,
|
|
||||||
buffer: Option<gst::Buffer>,
|
|
||||||
) -> Result<HandleBufferResult, FlowError>;
|
|
||||||
fn end_of_stream(&mut self, demuxer: &Element) -> Result<(), gst::ErrorMessage>;
|
|
||||||
|
|
||||||
fn is_seekable(&self, demuxer: &Element) -> bool;
|
|
||||||
fn get_position(&self, demuxer: &Element) -> gst::ClockTime;
|
|
||||||
fn get_duration(&self, demuxer: &Element) -> gst::ClockTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Stream {
|
|
||||||
pub index: StreamIndex,
|
|
||||||
pub caps: gst::Caps,
|
|
||||||
pub stream_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stream {
|
|
||||||
pub fn new(index: StreamIndex, caps: gst::Caps, stream_id: String) -> Stream {
|
|
||||||
Stream {
|
|
||||||
index,
|
|
||||||
caps,
|
|
||||||
stream_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DemuxerInfo {
|
|
||||||
pub name: String,
|
|
||||||
pub long_name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub classification: String,
|
|
||||||
pub author: String,
|
|
||||||
pub rank: u32,
|
|
||||||
pub create_instance: fn(&Element) -> Box<DemuxerImpl>,
|
|
||||||
pub input_caps: gst::Caps,
|
|
||||||
pub output_caps: gst::Caps,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Demuxer {
|
|
||||||
cat: gst::DebugCategory,
|
|
||||||
sinkpad: gst::Pad,
|
|
||||||
flow_combiner: Mutex<UniqueFlowCombiner>,
|
|
||||||
group_id: Mutex<gst::GroupId>,
|
|
||||||
srcpads: Mutex<BTreeMap<u32, gst::Pad>>,
|
|
||||||
imp: Mutex<Box<DemuxerImpl>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct UniqueFlowCombiner(gst_base::FlowCombiner);
|
|
||||||
|
|
||||||
impl UniqueFlowCombiner {
|
|
||||||
fn add_pad(&mut self, pad: &gst::Pad) {
|
|
||||||
self.0.add_pad(pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&mut self) {
|
|
||||||
self.0.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_flow(&mut self, flow_ret: gst::FlowReturn) -> gst::FlowReturn {
|
|
||||||
self.0.update_flow(flow_ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for UniqueFlowCombiner {}
|
|
||||||
unsafe impl Sync for UniqueFlowCombiner {}
|
|
||||||
|
|
||||||
impl Demuxer {
|
|
||||||
fn new(element: &Element, sinkpad: gst::Pad, demuxer_info: &DemuxerInfo) -> Self {
|
|
||||||
Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"rsdemux",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Rust demuxer base class",
|
|
||||||
),
|
|
||||||
sinkpad,
|
|
||||||
flow_combiner: Mutex::new(Default::default()),
|
|
||||||
group_id: Mutex::new(gst::util_group_id_next()),
|
|
||||||
srcpads: Mutex::new(BTreeMap::new()),
|
|
||||||
imp: Mutex::new((demuxer_info.create_instance)(element)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(klass: &mut ElementClass, demuxer_info: &DemuxerInfo) {
|
|
||||||
klass.set_metadata(
|
|
||||||
&demuxer_info.long_name,
|
|
||||||
&demuxer_info.classification,
|
|
||||||
&demuxer_info.description,
|
|
||||||
&demuxer_info.author,
|
|
||||||
);
|
|
||||||
|
|
||||||
let pad_template = gst::PadTemplate::new(
|
|
||||||
"sink",
|
|
||||||
gst::PadDirection::Sink,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&demuxer_info.input_caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(pad_template);
|
|
||||||
|
|
||||||
let pad_template = gst::PadTemplate::new(
|
|
||||||
"src_%u",
|
|
||||||
gst::PadDirection::Src,
|
|
||||||
gst::PadPresence::Sometimes,
|
|
||||||
&demuxer_info.output_caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(pad_template);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &Element, demuxer_info: &DemuxerInfo) -> Box<ElementImpl<Element>> {
|
|
||||||
let templ = element.get_pad_template("sink").unwrap();
|
|
||||||
let sinkpad = gst::Pad::new_from_template(&templ, "sink");
|
|
||||||
sinkpad.set_activate_function(Demuxer::sink_activate);
|
|
||||||
sinkpad.set_activatemode_function(Demuxer::sink_activatemode);
|
|
||||||
sinkpad.set_chain_function(Demuxer::sink_chain);
|
|
||||||
sinkpad.set_event_function(Demuxer::sink_event);
|
|
||||||
element.add_pad(&sinkpad).unwrap();
|
|
||||||
|
|
||||||
let imp = Self::new(element, sinkpad, demuxer_info);
|
|
||||||
Box::new(imp)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_stream(&self, element: &Element, index: u32, caps: gst::Caps, stream_id: &str) {
|
|
||||||
let mut srcpads = self.srcpads.lock().unwrap();
|
|
||||||
assert!(!srcpads.contains_key(&index));
|
|
||||||
|
|
||||||
let templ = element.get_pad_template("src_%u").unwrap();
|
|
||||||
let name = format!("src_{}", index);
|
|
||||||
let pad = gst::Pad::new_from_template(&templ, Some(name.as_str()));
|
|
||||||
pad.set_query_function(Demuxer::src_query);
|
|
||||||
pad.set_event_function(Demuxer::src_event);
|
|
||||||
|
|
||||||
pad.set_active(true).unwrap();
|
|
||||||
|
|
||||||
let full_stream_id = pad.create_stream_id(element, stream_id).unwrap();
|
|
||||||
pad.push_event(
|
|
||||||
gst::Event::new_stream_start(&full_stream_id)
|
|
||||||
.group_id(*self.group_id.lock().unwrap())
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
pad.push_event(gst::Event::new_caps(&caps).build());
|
|
||||||
|
|
||||||
let segment = gst::FormattedSegment::<gst::ClockTime>::default();
|
|
||||||
pad.push_event(gst::Event::new_segment(&segment).build());
|
|
||||||
|
|
||||||
self.flow_combiner.lock().unwrap().add_pad(&pad);
|
|
||||||
element.add_pad(&pad).unwrap();
|
|
||||||
|
|
||||||
srcpads.insert(index, pad);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn added_all_streams(&self, element: &Element) {
|
|
||||||
element.no_more_pads();
|
|
||||||
*self.group_id.lock().unwrap() = gst::util_group_id_next();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stream_format_changed(&self, _element: &Element, index: u32, caps: gst::Caps) {
|
|
||||||
let srcpads = self.srcpads.lock().unwrap();
|
|
||||||
|
|
||||||
if let Some(pad) = srcpads.get(&index) {
|
|
||||||
pad.push_event(gst::Event::new_caps(&caps).build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stream_eos(&self, _element: &Element, index: Option<u32>) {
|
|
||||||
let srcpads = self.srcpads.lock().unwrap();
|
|
||||||
|
|
||||||
let event = gst::Event::new_eos().build();
|
|
||||||
match index {
|
|
||||||
Some(index) => {
|
|
||||||
if let Some(pad) = srcpads.get(&index) {
|
|
||||||
pad.push_event(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
for (_, pad) in srcpads.iter().by_ref() {
|
|
||||||
pad.push_event(event.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stream_push_buffer(
|
|
||||||
&self,
|
|
||||||
_element: &Element,
|
|
||||||
index: u32,
|
|
||||||
buffer: gst::Buffer,
|
|
||||||
) -> gst::FlowReturn {
|
|
||||||
let srcpads = self.srcpads.lock().unwrap();
|
|
||||||
|
|
||||||
if let Some(pad) = srcpads.get(&index) {
|
|
||||||
self.flow_combiner
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.update_flow(pad.push(buffer))
|
|
||||||
} else {
|
|
||||||
gst::FlowReturn::Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_all_streams(&self, element: &Element) {
|
|
||||||
self.flow_combiner.lock().unwrap().clear();
|
|
||||||
let mut srcpads = self.srcpads.lock().unwrap();
|
|
||||||
for (_, pad) in srcpads.iter().by_ref() {
|
|
||||||
element.remove_pad(pad).unwrap();
|
|
||||||
}
|
|
||||||
srcpads.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sink_activate(pad: &gst::Pad, _parent: &Option<gst::Object>) -> bool {
|
|
||||||
let mode = {
|
|
||||||
let mut query = gst::Query::new_scheduling();
|
|
||||||
if !pad.peer_query(&mut query) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
//if (gst_query_has_scheduling_mode_with_flags (query, GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE)) {
|
|
||||||
// GST_DEBUG_OBJECT (demuxer, "Activating in PULL mode");
|
|
||||||
// mode = GST_PAD_MODE_PULL;
|
|
||||||
//} else {
|
|
||||||
//GST_DEBUG_OBJECT (demuxer, "Activating in PUSH mode");
|
|
||||||
//}
|
|
||||||
gst::PadMode::Push
|
|
||||||
};
|
|
||||||
|
|
||||||
match pad.activate_mode(mode, true) {
|
|
||||||
Ok(_) => true,
|
|
||||||
Err(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start(&self, element: &Element, upstream_size: Option<u64>, random_access: bool) -> bool {
|
|
||||||
let demuxer_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_debug!(
|
|
||||||
self.cat,
|
|
||||||
obj: element,
|
|
||||||
"Starting with upstream size {:?} and random access {}",
|
|
||||||
upstream_size,
|
|
||||||
random_access
|
|
||||||
);
|
|
||||||
|
|
||||||
match demuxer_impl.start(element, upstream_size, random_access) {
|
|
||||||
Ok(..) => {
|
|
||||||
gst_trace!(self.cat, obj: element, "Successfully started",);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: element, "Failed to start: {:?}", msg);
|
|
||||||
element.post_error_message(msg);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, element: &Element) -> bool {
|
|
||||||
let demuxer_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: element, "Stopping");
|
|
||||||
|
|
||||||
match demuxer_impl.stop(element) {
|
|
||||||
Ok(..) => {
|
|
||||||
gst_trace!(self.cat, obj: element, "Successfully stop");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: element, "Failed to stop: {:?}", msg);
|
|
||||||
element.post_error_message(msg);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sink_activatemode(
|
|
||||||
_pad: &gst::Pad,
|
|
||||||
parent: &Option<gst::Object>,
|
|
||||||
mode: gst::PadMode,
|
|
||||||
active: bool,
|
|
||||||
) -> bool {
|
|
||||||
let element = parent.as_ref().unwrap().downcast_ref::<Element>().unwrap();
|
|
||||||
let demuxer = element.get_impl().downcast_ref::<Demuxer>().unwrap();
|
|
||||||
|
|
||||||
if active {
|
|
||||||
let upstream_size = demuxer
|
|
||||||
.sinkpad
|
|
||||||
.peer_query_duration::<gst::format::Bytes>()
|
|
||||||
.and_then(|v| v.0);
|
|
||||||
|
|
||||||
if !demuxer.start(element, upstream_size, mode == gst::PadMode::Pull) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if mode == gst::PadMode::Pull {
|
|
||||||
// TODO
|
|
||||||
// demuxer.sinkpad.start_task(...)
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
if mode == gst::PadMode::Pull {
|
|
||||||
let _ = demuxer.sinkpad.stop_task();
|
|
||||||
}
|
|
||||||
|
|
||||||
demuxer.stop(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sink_chain(
|
|
||||||
_pad: &gst::Pad,
|
|
||||||
parent: &Option<gst::Object>,
|
|
||||||
buffer: gst::Buffer,
|
|
||||||
) -> gst::FlowReturn {
|
|
||||||
let element = parent.as_ref().unwrap().downcast_ref::<Element>().unwrap();
|
|
||||||
let demuxer = element.get_impl().downcast_ref::<Demuxer>().unwrap();
|
|
||||||
|
|
||||||
let mut res = {
|
|
||||||
let demuxer_impl = &mut demuxer.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_trace!(demuxer.cat, obj: element, "Handling buffer {:?}", buffer);
|
|
||||||
|
|
||||||
match demuxer_impl.handle_buffer(element, Some(buffer)) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(flow_error) => {
|
|
||||||
gst_error!(
|
|
||||||
demuxer.cat,
|
|
||||||
obj: element,
|
|
||||||
"Failed handling buffer: {:?}",
|
|
||||||
flow_error
|
|
||||||
);
|
|
||||||
match flow_error {
|
|
||||||
FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
|
|
||||||
element.post_error_message(msg);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
return flow_error.into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Loop until AllEos, NeedMoreData or error when pushing downstream
|
|
||||||
loop {
|
|
||||||
gst_trace!(demuxer.cat, obj: element, "Handled {:?}", res);
|
|
||||||
|
|
||||||
match res {
|
|
||||||
HandleBufferResult::NeedMoreData => {
|
|
||||||
return gst::FlowReturn::Ok;
|
|
||||||
}
|
|
||||||
HandleBufferResult::StreamAdded(stream) => {
|
|
||||||
demuxer.add_stream(element, stream.index, stream.caps, &stream.stream_id);
|
|
||||||
}
|
|
||||||
HandleBufferResult::HaveAllStreams => {
|
|
||||||
demuxer.added_all_streams(element);
|
|
||||||
}
|
|
||||||
HandleBufferResult::StreamChanged(stream) => {
|
|
||||||
demuxer.stream_format_changed(element, stream.index, stream.caps);
|
|
||||||
}
|
|
||||||
HandleBufferResult::StreamsChanged(streams) => {
|
|
||||||
for stream in streams {
|
|
||||||
demuxer.stream_format_changed(element, stream.index, stream.caps);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HandleBufferResult::BufferForStream(index, buffer) => {
|
|
||||||
let flow_ret = demuxer.stream_push_buffer(element, index, buffer);
|
|
||||||
|
|
||||||
if flow_ret != gst::FlowReturn::Ok {
|
|
||||||
return flow_ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HandleBufferResult::Eos(index) => {
|
|
||||||
demuxer.stream_eos(element, index);
|
|
||||||
return gst::FlowReturn::Eos;
|
|
||||||
}
|
|
||||||
HandleBufferResult::Again => {
|
|
||||||
// nothing, just call again
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
gst_trace!(demuxer.cat, obj: element, "Calling again");
|
|
||||||
|
|
||||||
res = {
|
|
||||||
let demuxer_impl = &mut demuxer.imp.lock().unwrap();
|
|
||||||
match demuxer_impl.handle_buffer(element, None) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(flow_error) => {
|
|
||||||
gst_error!(
|
|
||||||
demuxer.cat,
|
|
||||||
obj: element,
|
|
||||||
"Failed calling again: {:?}",
|
|
||||||
flow_error
|
|
||||||
);
|
|
||||||
match flow_error {
|
|
||||||
FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
|
|
||||||
element.post_error_message(msg);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
return flow_error.into();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sink_event(pad: &gst::Pad, parent: &Option<gst::Object>, event: gst::Event) -> bool {
|
|
||||||
use gst::EventView;
|
|
||||||
|
|
||||||
let element = parent.as_ref().unwrap().downcast_ref::<Element>().unwrap();
|
|
||||||
let demuxer = element.get_impl().downcast_ref::<Demuxer>().unwrap();
|
|
||||||
|
|
||||||
match event.view() {
|
|
||||||
EventView::Eos(..) => {
|
|
||||||
let demuxer_impl = &mut demuxer.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_debug!(demuxer.cat, obj: element, "End of stream");
|
|
||||||
match demuxer_impl.end_of_stream(element) {
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(demuxer.cat, obj: element, "Failed end of stream: {:?}", msg);
|
|
||||||
element.post_error_message(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pad.event_default(parent.as_ref(), event)
|
|
||||||
}
|
|
||||||
EventView::Segment(..) => pad.event_default(parent.as_ref(), event),
|
|
||||||
_ => pad.event_default(parent.as_ref(), event),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn src_query(pad: &gst::Pad, parent: &Option<gst::Object>, query: &mut gst::QueryRef) -> bool {
|
|
||||||
use gst::QueryView;
|
|
||||||
|
|
||||||
let element = parent.as_ref().unwrap().downcast_ref::<Element>().unwrap();
|
|
||||||
let demuxer = element.get_impl().downcast_ref::<Demuxer>().unwrap();
|
|
||||||
|
|
||||||
match query.view_mut() {
|
|
||||||
QueryView::Position(ref mut q) => {
|
|
||||||
let fmt = q.get_format();
|
|
||||||
if fmt == gst::Format::Time {
|
|
||||||
let demuxer_impl = &demuxer.imp.lock().unwrap();
|
|
||||||
|
|
||||||
let position = demuxer_impl.get_position(&element);
|
|
||||||
gst_trace!(
|
|
||||||
demuxer.cat,
|
|
||||||
obj: element,
|
|
||||||
"Returning position {:?}",
|
|
||||||
position
|
|
||||||
);
|
|
||||||
|
|
||||||
match *position {
|
|
||||||
None => return false,
|
|
||||||
Some(_) => {
|
|
||||||
q.set(position);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QueryView::Duration(ref mut q) => {
|
|
||||||
let fmt = q.get_format();
|
|
||||||
if fmt == gst::Format::Time {
|
|
||||||
let demuxer_impl = &demuxer.imp.lock().unwrap();
|
|
||||||
|
|
||||||
let duration = demuxer_impl.get_duration(&element);
|
|
||||||
gst_trace!(
|
|
||||||
demuxer.cat,
|
|
||||||
obj: element,
|
|
||||||
"Returning duration {:?}",
|
|
||||||
duration
|
|
||||||
);
|
|
||||||
|
|
||||||
match *duration {
|
|
||||||
None => return false,
|
|
||||||
Some(_) => {
|
|
||||||
q.set(duration);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Have to do it outside the match because otherwise query is already mutably
|
|
||||||
// borrowed by the query view.
|
|
||||||
pad.query_default(parent.as_ref(), query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn src_event(pad: &gst::Pad, parent: &Option<gst::Object>, event: gst::Event) -> bool {
|
|
||||||
use gst::EventView;
|
|
||||||
|
|
||||||
match event.view() {
|
|
||||||
EventView::Seek(..) => {
|
|
||||||
// TODO: Implement
|
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => pad.event_default(parent.as_ref(), event),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn seek(
|
|
||||||
&self,
|
|
||||||
element: &Element,
|
|
||||||
start: gst::ClockTime,
|
|
||||||
stop: gst::ClockTime,
|
|
||||||
offset: &mut u64,
|
|
||||||
) -> bool {
|
|
||||||
gst_debug!(self.cat, obj: element, "Seeking to {:?}-{:?}", start, stop);
|
|
||||||
|
|
||||||
let res = {
|
|
||||||
let demuxer_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
match demuxer_impl.seek(element, start, stop) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: element, "Failed to seek: {:?}", msg);
|
|
||||||
element.post_error_message(msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match res {
|
|
||||||
SeekResult::TooEarly => {
|
|
||||||
gst_debug!(self.cat, obj: element, "Seeked too early");
|
|
||||||
false
|
|
||||||
}
|
|
||||||
SeekResult::Ok(off) => {
|
|
||||||
gst_trace!(self.cat, obj: element, "Seeked successfully");
|
|
||||||
*offset = off;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
SeekResult::Eos => {
|
|
||||||
gst_debug!(self.cat, obj: element, "Seeked after EOS");
|
|
||||||
*offset = u64::MAX;
|
|
||||||
|
|
||||||
self.stream_eos(element, None);
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectImpl<Element> for Demuxer {}
|
|
||||||
|
|
||||||
impl ElementImpl<Element> for Demuxer {
|
|
||||||
fn change_state(
|
|
||||||
&self,
|
|
||||||
element: &Element,
|
|
||||||
transition: gst::StateChange,
|
|
||||||
) -> gst::StateChangeReturn {
|
|
||||||
let mut ret = gst::StateChangeReturn::Success;
|
|
||||||
|
|
||||||
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
|
||||||
|
|
||||||
match transition {
|
|
||||||
gst::StateChange::ReadyToPaused => {
|
|
||||||
// TODO
|
|
||||||
*self.group_id.lock().unwrap() = gst::util_group_id_next();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = element.parent_change_state(transition);
|
|
||||||
if ret == gst::StateChangeReturn::Failure {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
match transition {
|
|
||||||
gst::StateChange::PausedToReady => {
|
|
||||||
self.flow_combiner.lock().unwrap().clear();
|
|
||||||
let mut srcpads = self.srcpads.lock().unwrap();
|
|
||||||
for (_, pad) in srcpads.iter().by_ref() {
|
|
||||||
element.remove_pad(pad).unwrap();
|
|
||||||
}
|
|
||||||
srcpads.clear();
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DemuxerStatic {
|
|
||||||
name: String,
|
|
||||||
demuxer_info: DemuxerInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImplTypeStatic<Element> for DemuxerStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
self.name.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
Demuxer::init(element, &self.demuxer_info)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut ElementClass) {
|
|
||||||
Demuxer::class_init(klass, &self.demuxer_info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn demuxer_register(
|
|
||||||
plugin: &gst::Plugin,
|
|
||||||
demuxer_info: DemuxerInfo,
|
|
||||||
) -> Result<(), glib::BoolError> {
|
|
||||||
let name = demuxer_info.name.clone();
|
|
||||||
let rank = demuxer_info.rank;
|
|
||||||
|
|
||||||
let demuxer_static = DemuxerStatic {
|
|
||||||
name: format!("Demuxer-{}", name),
|
|
||||||
demuxer_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
let type_ = register_type(demuxer_static);
|
|
||||||
gst::Element::register(plugin, &name, rank, type_)
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright (C) 2016-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::error::Error;
|
|
||||||
use std::fmt::Error as FmtError;
|
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use gst;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct UriError {
|
|
||||||
error: gst::URIError,
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UriError {
|
|
||||||
pub fn new<T: Into<String>>(error: gst::URIError, message: T) -> UriError {
|
|
||||||
UriError {
|
|
||||||
error,
|
|
||||||
message: message.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn message(&self) -> &str {
|
|
||||||
&self.message
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error(&self) -> gst::URIError {
|
|
||||||
self.error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<glib::Error> for UriError {
|
|
||||||
fn into(self) -> glib::Error {
|
|
||||||
(&self).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Into<glib::Error> for &'a UriError {
|
|
||||||
fn into(self) -> glib::Error {
|
|
||||||
glib::Error::new(self.error, &self.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for UriError {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
|
|
||||||
f.write_fmt(format_args!("{}: {}", self.description(), self.message))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for UriError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match self.error {
|
|
||||||
gst::URIError::UnsupportedProtocol => "Unsupported protocol",
|
|
||||||
gst::URIError::BadUri => "Bad URI",
|
|
||||||
gst::URIError::BadState => "Bad State",
|
|
||||||
gst::URIError::BadReference => "Bad Reference",
|
|
||||||
_ => "Unknown",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
extern crate glib;
|
|
||||||
extern crate gobject_subclass;
|
|
||||||
extern crate gst_plugin;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate gstreamer as gst;
|
|
||||||
extern crate gstreamer_base as gst_base;
|
|
||||||
|
|
||||||
extern crate url;
|
|
||||||
|
|
||||||
pub mod demuxer;
|
|
||||||
pub mod error;
|
|
||||||
pub mod sink;
|
|
||||||
pub mod source;
|
|
||||||
|
|
||||||
pub type UriValidator = Fn(&url::Url) -> Result<(), error::UriError> + Send + Sync + 'static;
|
|
|
@ -1,303 +0,0 @@
|
||||||
// Copyright (C) 2016-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://opensink.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
use gst_base::prelude::*;
|
|
||||||
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
use gst_plugin::base_sink::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
use gst_plugin::error::*;
|
|
||||||
use gst_plugin::uri_handler::*;
|
|
||||||
|
|
||||||
pub use gst_plugin::base_sink::BaseSink;
|
|
||||||
|
|
||||||
use error::*;
|
|
||||||
|
|
||||||
use UriValidator;
|
|
||||||
|
|
||||||
pub trait SinkImpl: Send + 'static {
|
|
||||||
fn uri_validator(&self) -> Box<UriValidator>;
|
|
||||||
|
|
||||||
fn start(&mut self, sink: &BaseSink, uri: Url) -> Result<(), gst::ErrorMessage>;
|
|
||||||
fn stop(&mut self, sink: &BaseSink) -> Result<(), gst::ErrorMessage>;
|
|
||||||
fn render(&mut self, sink: &BaseSink, buffer: &gst::BufferRef) -> Result<(), FlowError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Sink {
|
|
||||||
cat: gst::DebugCategory,
|
|
||||||
uri: Mutex<(Option<Url>, bool)>,
|
|
||||||
uri_validator: Box<UriValidator>,
|
|
||||||
imp: Mutex<Box<SinkImpl>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
static PROPERTIES: [Property; 1] = [Property::String(
|
|
||||||
"uri",
|
|
||||||
"URI",
|
|
||||||
"URI to read from",
|
|
||||||
None,
|
|
||||||
PropertyMutability::ReadWrite,
|
|
||||||
)];
|
|
||||||
|
|
||||||
impl Sink {
|
|
||||||
fn new(sink: &BaseSink, sink_info: &SinkInfo) -> Self {
|
|
||||||
let sink_impl = (sink_info.create_instance)(sink);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"rssink",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Rust sink base class",
|
|
||||||
),
|
|
||||||
uri: Mutex::new((None, false)),
|
|
||||||
uri_validator: sink_impl.uri_validator(),
|
|
||||||
imp: Mutex::new(sink_impl),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(klass: &mut BaseSinkClass, sink_info: &SinkInfo) {
|
|
||||||
klass.set_metadata(
|
|
||||||
&sink_info.long_name,
|
|
||||||
&sink_info.classification,
|
|
||||||
&sink_info.description,
|
|
||||||
&sink_info.author,
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
let pad_template = gst::PadTemplate::new(
|
|
||||||
"sink",
|
|
||||||
gst::PadDirection::Sink,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &BaseSink, sink_info: &SinkInfo) -> Box<BaseSinkImpl<BaseSink>> {
|
|
||||||
element.set_blocksize(4096);
|
|
||||||
|
|
||||||
let imp = Self::new(element, sink_info);
|
|
||||||
Box::new(imp)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_uri(&self, _element: &glib::Object) -> Option<String> {
|
|
||||||
let uri_storage = &self.uri.lock().unwrap();
|
|
||||||
uri_storage.0.as_ref().map(|uri| String::from(uri.as_str()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_uri(&self, element: &glib::Object, uri_str: Option<String>) -> Result<(), glib::Error> {
|
|
||||||
let sink = element.clone().dynamic_cast::<BaseSink>().unwrap();
|
|
||||||
|
|
||||||
let uri_storage = &mut self.uri.lock().unwrap();
|
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: &sink, "Setting URI {:?}", uri_str);
|
|
||||||
|
|
||||||
if uri_storage.1 {
|
|
||||||
return Err(
|
|
||||||
UriError::new(gst::URIError::BadState, "Already started".to_string()).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
uri_storage.0 = None;
|
|
||||||
|
|
||||||
if let Some(uri_str) = uri_str {
|
|
||||||
match Url::parse(uri_str.as_str()) {
|
|
||||||
Ok(uri) => {
|
|
||||||
try!((self.uri_validator)(&uri).map_err(|e| e.into()));
|
|
||||||
uri_storage.0 = Some(uri);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(err) => Err(UriError::new(
|
|
||||||
gst::URIError::BadUri,
|
|
||||||
format!("Failed to parse URI '{}': {}", uri_str, err),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectImpl<BaseSink> for Sink {
|
|
||||||
fn set_property(&self, obj: &glib::Object, id: u32, value: &glib::Value) {
|
|
||||||
let prop = &PROPERTIES[id as usize];
|
|
||||||
|
|
||||||
match *prop {
|
|
||||||
Property::String("uri", ..) => {
|
|
||||||
self.set_uri(obj, value.get()).unwrap();
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_property(&self, obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
|
||||||
let prop = &PROPERTIES[id as usize];
|
|
||||||
|
|
||||||
match *prop {
|
|
||||||
Property::String("uri", ..) => Ok(self.get_uri(obj).to_value()),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementImpl<BaseSink> for Sink {}
|
|
||||||
|
|
||||||
impl BaseSinkImpl<BaseSink> for Sink {
|
|
||||||
fn start(&self, sink: &BaseSink) -> bool {
|
|
||||||
gst_debug!(self.cat, obj: sink, "Starting");
|
|
||||||
|
|
||||||
// Don't keep the URI locked while we call start later
|
|
||||||
let uri = match *self.uri.lock().unwrap() {
|
|
||||||
(Some(ref uri), ref mut started) => {
|
|
||||||
*started = true;
|
|
||||||
uri.clone()
|
|
||||||
}
|
|
||||||
(None, _) => {
|
|
||||||
gst_error!(self.cat, obj: sink, "No URI given");
|
|
||||||
gst_element_error!(sink, gst::ResourceError::OpenRead, ["No URI given"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let sink_impl = &mut self.imp.lock().unwrap();
|
|
||||||
match sink_impl.start(sink, uri) {
|
|
||||||
Ok(..) => {
|
|
||||||
gst_trace!(self.cat, obj: sink, "Started successfully");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: sink, "Failed to start: {:?}", msg);
|
|
||||||
|
|
||||||
self.uri.lock().unwrap().1 = false;
|
|
||||||
sink.post_error_message(msg);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, sink: &BaseSink) -> bool {
|
|
||||||
let sink_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: sink, "Stopping");
|
|
||||||
|
|
||||||
match sink_impl.stop(sink) {
|
|
||||||
Ok(..) => {
|
|
||||||
gst_trace!(self.cat, obj: sink, "Stopped successfully");
|
|
||||||
self.uri.lock().unwrap().1 = false;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: sink, "Failed to stop: {:?}", msg);
|
|
||||||
|
|
||||||
sink.post_error_message(msg);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&self, sink: &BaseSink, buffer: &gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
let sink_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_trace!(self.cat, obj: sink, "Rendering buffer {:?}", buffer,);
|
|
||||||
|
|
||||||
match sink_impl.render(sink, buffer) {
|
|
||||||
Ok(()) => gst::FlowReturn::Ok,
|
|
||||||
Err(flow_error) => {
|
|
||||||
gst_error!(self.cat, obj: sink, "Failed to render: {:?}", flow_error);
|
|
||||||
match flow_error {
|
|
||||||
FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
|
|
||||||
sink.post_error_message(msg);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
flow_error.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl URIHandlerImpl for Sink {
|
|
||||||
fn get_uri(&self, element: &gst::URIHandler) -> Option<String> {
|
|
||||||
Sink::get_uri(self, &element.clone().upcast())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_uri(&self, element: &gst::URIHandler, uri: Option<String>) -> Result<(), glib::Error> {
|
|
||||||
Sink::set_uri(self, &element.clone().upcast(), uri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SinkInfo {
|
|
||||||
pub name: String,
|
|
||||||
pub long_name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub classification: String,
|
|
||||||
pub author: String,
|
|
||||||
pub rank: u32,
|
|
||||||
pub create_instance: fn(&BaseSink) -> Box<SinkImpl>,
|
|
||||||
pub protocols: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SinkStatic {
|
|
||||||
name: String,
|
|
||||||
sink_info: SinkInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImplTypeStatic<BaseSink> for SinkStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
self.name.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &BaseSink) -> Box<BaseSinkImpl<BaseSink>> {
|
|
||||||
Sink::init(element, &self.sink_info)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut BaseSinkClass) {
|
|
||||||
Sink::class_init(klass, &self.sink_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_init(&self, token: &TypeInitToken, type_: glib::Type) {
|
|
||||||
register_uri_handler(token, type_, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl URIHandlerImplStatic<BaseSink> for SinkStatic {
|
|
||||||
fn get_impl<'a>(&self, imp: &'a Box<BaseSinkImpl<BaseSink>>) -> &'a URIHandlerImpl {
|
|
||||||
imp.downcast_ref::<Sink>().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_type(&self) -> gst::URIType {
|
|
||||||
gst::URIType::Sink
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_protocols(&self) -> Vec<String> {
|
|
||||||
self.sink_info.protocols.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sink_register(plugin: &gst::Plugin, sink_info: SinkInfo) -> Result<(), glib::BoolError> {
|
|
||||||
let name = sink_info.name.clone();
|
|
||||||
let rank = sink_info.rank;
|
|
||||||
|
|
||||||
let sink_static = SinkStatic {
|
|
||||||
name: format!("Sink-{}", name),
|
|
||||||
sink_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
let type_ = register_type(sink_static);
|
|
||||||
gst::Element::register(plugin, &name, rank, type_)
|
|
||||||
}
|
|
|
@ -1,390 +0,0 @@
|
||||||
// Copyright (C) 2016-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::u64;
|
|
||||||
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
use gst_base::prelude::*;
|
|
||||||
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
use gst_plugin::base_src::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
use gst_plugin::error::*;
|
|
||||||
use gst_plugin::uri_handler::*;
|
|
||||||
|
|
||||||
pub use gst_plugin::base_src::BaseSrc;
|
|
||||||
|
|
||||||
use error::*;
|
|
||||||
|
|
||||||
use UriValidator;
|
|
||||||
|
|
||||||
pub trait SourceImpl: Send + 'static {
|
|
||||||
fn uri_validator(&self) -> Box<UriValidator>;
|
|
||||||
|
|
||||||
fn is_seekable(&self, src: &BaseSrc) -> bool;
|
|
||||||
fn get_size(&self, src: &BaseSrc) -> Option<u64>;
|
|
||||||
|
|
||||||
fn start(&mut self, src: &BaseSrc, uri: Url) -> Result<(), gst::ErrorMessage>;
|
|
||||||
fn stop(&mut self, src: &BaseSrc) -> Result<(), gst::ErrorMessage>;
|
|
||||||
fn fill(
|
|
||||||
&mut self,
|
|
||||||
src: &BaseSrc,
|
|
||||||
offset: u64,
|
|
||||||
length: u32,
|
|
||||||
buffer: &mut gst::BufferRef,
|
|
||||||
) -> Result<(), FlowError>;
|
|
||||||
fn seek(
|
|
||||||
&mut self,
|
|
||||||
src: &BaseSrc,
|
|
||||||
start: u64,
|
|
||||||
stop: Option<u64>,
|
|
||||||
) -> Result<(), gst::ErrorMessage>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Source {
|
|
||||||
cat: gst::DebugCategory,
|
|
||||||
uri: Mutex<(Option<Url>, bool)>,
|
|
||||||
uri_validator: Box<UriValidator>,
|
|
||||||
imp: Mutex<Box<SourceImpl>>,
|
|
||||||
push_only: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
static PROPERTIES: [Property; 1] = [Property::String(
|
|
||||||
"uri",
|
|
||||||
"URI",
|
|
||||||
"URI to read from",
|
|
||||||
None,
|
|
||||||
PropertyMutability::ReadWrite,
|
|
||||||
)];
|
|
||||||
|
|
||||||
impl Source {
|
|
||||||
fn new(source: &BaseSrc, source_info: &SourceInfo) -> Self {
|
|
||||||
let source_impl = (source_info.create_instance)(source);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"rssource",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Rust source base class",
|
|
||||||
),
|
|
||||||
uri: Mutex::new((None, false)),
|
|
||||||
uri_validator: source_impl.uri_validator(),
|
|
||||||
imp: Mutex::new(source_impl),
|
|
||||||
push_only: source_info.push_only,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(klass: &mut BaseSrcClass, source_info: &SourceInfo) {
|
|
||||||
klass.set_metadata(
|
|
||||||
&source_info.long_name,
|
|
||||||
&source_info.classification,
|
|
||||||
&source_info.description,
|
|
||||||
&source_info.author,
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
let pad_template = gst::PadTemplate::new(
|
|
||||||
"src",
|
|
||||||
gst::PadDirection::Src,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &BaseSrc, source_info: &SourceInfo) -> Box<BaseSrcImpl<BaseSrc>> {
|
|
||||||
element.set_blocksize(4096);
|
|
||||||
|
|
||||||
let imp = Self::new(element, source_info);
|
|
||||||
Box::new(imp)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_uri(&self, _element: &glib::Object) -> Option<String> {
|
|
||||||
let uri_storage = &self.uri.lock().unwrap();
|
|
||||||
uri_storage.0.as_ref().map(|uri| String::from(uri.as_str()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_uri(&self, element: &glib::Object, uri_str: Option<String>) -> Result<(), glib::Error> {
|
|
||||||
let src = element.clone().dynamic_cast::<BaseSrc>().unwrap();
|
|
||||||
|
|
||||||
let uri_storage = &mut self.uri.lock().unwrap();
|
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: &src, "Setting URI {:?}", uri_str);
|
|
||||||
|
|
||||||
if uri_storage.1 {
|
|
||||||
return Err(
|
|
||||||
UriError::new(gst::URIError::BadState, "Already started".to_string()).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
uri_storage.0 = None;
|
|
||||||
|
|
||||||
if let Some(uri_str) = uri_str {
|
|
||||||
match Url::parse(uri_str.as_str()) {
|
|
||||||
Ok(uri) => {
|
|
||||||
try!((self.uri_validator)(&uri).map_err(|e| e.into()));
|
|
||||||
uri_storage.0 = Some(uri);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(err) => Err(UriError::new(
|
|
||||||
gst::URIError::BadUri,
|
|
||||||
format!("Failed to parse URI '{}': {}", uri_str, err),
|
|
||||||
)
|
|
||||||
.into()),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ObjectImpl<BaseSrc> for Source {
|
|
||||||
fn set_property(&self, obj: &glib::Object, id: u32, value: &glib::Value) {
|
|
||||||
let prop = &PROPERTIES[id as usize];
|
|
||||||
|
|
||||||
match *prop {
|
|
||||||
Property::String("uri", ..) => {
|
|
||||||
self.set_uri(obj, value.get()).unwrap();
|
|
||||||
}
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_property(&self, obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
|
||||||
let prop = &PROPERTIES[id as usize];
|
|
||||||
|
|
||||||
match *prop {
|
|
||||||
Property::String("uri", ..) => Ok(self.get_uri(obj).to_value()),
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementImpl<BaseSrc> for Source {}
|
|
||||||
|
|
||||||
impl BaseSrcImpl<BaseSrc> for Source {
|
|
||||||
fn start(&self, src: &BaseSrc) -> bool {
|
|
||||||
gst_debug!(self.cat, obj: src, "Starting");
|
|
||||||
|
|
||||||
// Don't keep the URI locked while we call start later
|
|
||||||
let uri = match *self.uri.lock().unwrap() {
|
|
||||||
(Some(ref uri), ref mut started) => {
|
|
||||||
*started = true;
|
|
||||||
uri.clone()
|
|
||||||
}
|
|
||||||
(None, _) => {
|
|
||||||
gst_error!(self.cat, obj: src, "No URI given");
|
|
||||||
gst_element_error!(src, gst::ResourceError::OpenRead, ["No URI given"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let source_impl = &mut self.imp.lock().unwrap();
|
|
||||||
match source_impl.start(src, uri) {
|
|
||||||
Ok(..) => {
|
|
||||||
gst_trace!(self.cat, obj: src, "Started successfully");
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: src, "Failed to start: {:?}", msg);
|
|
||||||
|
|
||||||
self.uri.lock().unwrap().1 = false;
|
|
||||||
src.post_error_message(msg);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, src: &BaseSrc) -> bool {
|
|
||||||
let source_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: src, "Stopping");
|
|
||||||
|
|
||||||
match source_impl.stop(src) {
|
|
||||||
Ok(..) => {
|
|
||||||
gst_trace!(self.cat, obj: src, "Stopped successfully");
|
|
||||||
self.uri.lock().unwrap().1 = false;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: src, "Failed to stop: {:?}", msg);
|
|
||||||
|
|
||||||
src.post_error_message(msg);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, src: &BaseSrc, query: &mut gst::QueryRef) -> bool {
|
|
||||||
use gst::QueryView;
|
|
||||||
|
|
||||||
match query.view_mut() {
|
|
||||||
QueryView::Scheduling(ref mut q) if self.push_only => {
|
|
||||||
q.set(gst::SchedulingFlags::SEQUENTIAL, 1, -1, 0);
|
|
||||||
q.add_scheduling_modes(&[gst::PadMode::Push]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseSrcBase::parent_query(src, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill(
|
|
||||||
&self,
|
|
||||||
src: &BaseSrc,
|
|
||||||
offset: u64,
|
|
||||||
length: u32,
|
|
||||||
buffer: &mut gst::BufferRef,
|
|
||||||
) -> gst::FlowReturn {
|
|
||||||
let source_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
gst_trace!(
|
|
||||||
self.cat,
|
|
||||||
obj: src,
|
|
||||||
"Filling buffer {:?} with offset {} and length {}",
|
|
||||||
buffer,
|
|
||||||
offset,
|
|
||||||
length
|
|
||||||
);
|
|
||||||
|
|
||||||
match source_impl.fill(src, offset, length, buffer) {
|
|
||||||
Ok(()) => gst::FlowReturn::Ok,
|
|
||||||
Err(flow_error) => {
|
|
||||||
gst_error!(self.cat, obj: src, "Failed to fill: {:?}", flow_error);
|
|
||||||
match flow_error {
|
|
||||||
FlowError::NotNegotiated(ref msg) | FlowError::Error(ref msg) => {
|
|
||||||
src.post_error_message(msg);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
flow_error.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_seek(&self, src: &BaseSrc, segment: &mut gst::Segment) -> bool {
|
|
||||||
let source_impl = &mut self.imp.lock().unwrap();
|
|
||||||
|
|
||||||
let segment = match segment.downcast_ref::<gst::format::Bytes>() {
|
|
||||||
None => return false,
|
|
||||||
Some(segment) => segment,
|
|
||||||
};
|
|
||||||
|
|
||||||
let start = match segment.get_start().0 {
|
|
||||||
None => return false,
|
|
||||||
Some(start) => start,
|
|
||||||
};
|
|
||||||
let stop = segment.get_stop().0;
|
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: src, "Seeking to {:?}-{:?}", start, stop);
|
|
||||||
|
|
||||||
match source_impl.seek(src, start, stop) {
|
|
||||||
Ok(..) => true,
|
|
||||||
Err(ref msg) => {
|
|
||||||
gst_error!(self.cat, obj: src, "Failed to seek {:?}", msg);
|
|
||||||
src.post_error_message(msg);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_seekable(&self, src: &BaseSrc) -> bool {
|
|
||||||
let source_impl = &self.imp.lock().unwrap();
|
|
||||||
source_impl.is_seekable(src)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_size(&self, src: &BaseSrc) -> Option<u64> {
|
|
||||||
let source_impl = &self.imp.lock().unwrap();
|
|
||||||
source_impl.get_size(src)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl URIHandlerImpl for Source {
|
|
||||||
fn get_uri(&self, element: &gst::URIHandler) -> Option<String> {
|
|
||||||
Source::get_uri(self, &element.clone().upcast())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_uri(&self, element: &gst::URIHandler, uri: Option<String>) -> Result<(), glib::Error> {
|
|
||||||
Source::set_uri(self, &element.clone().upcast(), uri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SourceInfo {
|
|
||||||
pub name: String,
|
|
||||||
pub long_name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub classification: String,
|
|
||||||
pub author: String,
|
|
||||||
pub rank: u32,
|
|
||||||
pub create_instance: fn(&BaseSrc) -> Box<SourceImpl>,
|
|
||||||
pub protocols: Vec<String>,
|
|
||||||
pub push_only: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SourceStatic {
|
|
||||||
name: String,
|
|
||||||
source_info: SourceInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImplTypeStatic<BaseSrc> for SourceStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
self.name.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &BaseSrc) -> Box<BaseSrcImpl<BaseSrc>> {
|
|
||||||
Source::init(element, &self.source_info)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut BaseSrcClass) {
|
|
||||||
Source::class_init(klass, &self.source_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_init(&self, token: &TypeInitToken, type_: glib::Type) {
|
|
||||||
register_uri_handler(token, type_, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl URIHandlerImplStatic<BaseSrc> for SourceStatic {
|
|
||||||
fn get_impl<'a>(&self, imp: &'a Box<BaseSrcImpl<BaseSrc>>) -> &'a URIHandlerImpl {
|
|
||||||
imp.downcast_ref::<Source>().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_type(&self) -> gst::URIType {
|
|
||||||
gst::URIType::Src
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_protocols(&self) -> Vec<String> {
|
|
||||||
self.source_info.protocols.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source_register(
|
|
||||||
plugin: &gst::Plugin,
|
|
||||||
source_info: SourceInfo,
|
|
||||||
) -> Result<(), glib::BoolError> {
|
|
||||||
let name = source_info.name.clone();
|
|
||||||
let rank = source_info.rank;
|
|
||||||
|
|
||||||
let source_static = SourceStatic {
|
|
||||||
name: format!("Source-{}", name),
|
|
||||||
source_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
let type_ = register_type(source_static);
|
|
||||||
gst::Element::register(plugin, &name, rank, type_)
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
# Changelog
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
|
|
||||||
specifically the [variant used by Rust](http://doc.crates.io/manifest.html#the-version-field).
|
|
||||||
|
|
||||||
## [0.3.2] - 2018-11-26
|
|
||||||
### Changed
|
|
||||||
- Fix various links in the README.md
|
|
||||||
- Link to the correct location for the documentation
|
|
||||||
|
|
||||||
## [0.3.1] - 2018-11-19
|
|
||||||
### Fixed
|
|
||||||
- Override vfuncs of all parent classes correctly.
|
|
||||||
|
|
||||||
## [0.3.0] - 2018-09-08
|
|
||||||
### Added
|
|
||||||
- Support for subclassing pads, ghost pads, aggregator and aggregator pads
|
|
||||||
- Support for implementing child proxy interface
|
|
||||||
- Generic catch_panic_pad_function() that allows wrapping around pad functions
|
|
||||||
for catching their panics and converting them into error messages
|
|
||||||
- More Rust-like FlowError enum that can be used to simplify implementations
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Use ptr::NonNull in various places
|
|
||||||
- Move to standalone gobject-subclass crate and refactor for its API changes
|
|
||||||
- Removed CallbackGuard as unwinding across FFI boundaries is not undefined
|
|
||||||
behaviour anymore and will cause an immediate panic instead
|
|
||||||
- Use new Object::downcast_ref() to prevent some unneeded clones
|
|
||||||
|
|
||||||
## [0.2.1] - 2018-05-09
|
|
||||||
### Fixed
|
|
||||||
- Fix memory leak in ElementClass::add_pad_template() related to floating
|
|
||||||
reference handling.
|
|
||||||
|
|
||||||
## [0.2.0] - 2018-03-20
|
|
||||||
### Changed
|
|
||||||
- Update to gstreamer-rs 0.11
|
|
||||||
- BaseTransform::transform_caps() takes caps by reference instead of value
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Send+Sync impls for all wrapper types
|
|
||||||
|
|
||||||
## [0.1.4] - 2018-02-12
|
|
||||||
### Fixed
|
|
||||||
- Fix BaseSrc::unlock_stop() and the same in BaseSink. It was calling unlock()
|
|
||||||
instead of unlock_stop() before, making it rather useless.
|
|
||||||
|
|
||||||
## [0.1.3] - 2018-01-15
|
|
||||||
### Fixed
|
|
||||||
- Only require GStreamer >= 1.8, not >= 1.10. We didn't use any 1.10 API
|
|
||||||
anymore since quite a while
|
|
||||||
- Don't call BaseTransform::transform_ip in passthrough mode with a mutable
|
|
||||||
reference, but call a new transform_ip_passthrough with an immutable
|
|
||||||
reference. The mutable reference would've failed all mutable operations.
|
|
||||||
|
|
||||||
## [0.1.2] - 2018-01-03
|
|
||||||
### Fixed
|
|
||||||
- BaseTransform::transform_caps() caps parameter is not owned when chainging
|
|
||||||
to the parent class' implementation either
|
|
||||||
|
|
||||||
## [0.1.1] - 2018-01-03
|
|
||||||
### Fixed
|
|
||||||
- BaseTransform::transform_caps() caps parameter is not owned
|
|
||||||
|
|
||||||
## [0.1.0] - 2017-12-22
|
|
||||||
- Initial release of the `gst-plugin` crate.
|
|
||||||
|
|
||||||
[Unreleased]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.3.2...HEAD
|
|
||||||
[0.3.2]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.3.1...0.3.2
|
|
||||||
[0.3.1]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.3.0...0.3.1
|
|
||||||
[0.3.0]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.2.1...0.3.0
|
|
||||||
[0.2.1]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.2.0...0.2.1
|
|
||||||
[0.2.0]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.1.4...0.2.0
|
|
||||||
[0.1.4]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.1.3...0.1.4
|
|
||||||
[0.1.3]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.1.2...0.1.3
|
|
||||||
[0.1.2]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.1.1...0.1.2
|
|
||||||
[0.1.1]: https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/compare/0.1.0...0.1.1
|
|
|
@ -1,35 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "gst-plugin"
|
|
||||||
version = "0.4.0"
|
|
||||||
authors = ["Sebastian Dröge <sebastian@centricular.com>"]
|
|
||||||
categories = ["multimedia", "api-bindings"]
|
|
||||||
description = "Infrastructure for writing GStreamer plugins in Rust"
|
|
||||||
documentation = "https://slomo.pages.freedesktop.org/rustdocs/gst-plugin/gst_plugin"
|
|
||||||
repository = "https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/tree/master/gst-plugin"
|
|
||||||
license = "MIT/Apache-2.0"
|
|
||||||
readme = "README.md"
|
|
||||||
homepage = "https://gstreamer.freedesktop.org"
|
|
||||||
keywords = ["gstreamer", "multimedia", "audio", "video", "gnome"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
libc = "0.2"
|
|
||||||
lazy_static = "1.0"
|
|
||||||
byteorder = "1.0"
|
|
||||||
gobject-subclass = { git = "https://github.com/gtk-rs/gobject-subclass" }
|
|
||||||
glib-sys = { git = "https://github.com/gtk-rs/sys" }
|
|
||||||
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
|
|
||||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
|
|
||||||
gstreamer-base-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
|
|
||||||
glib = { git = "https://github.com/gtk-rs/glib" }
|
|
||||||
gstreamer = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
|
||||||
gstreamer-base = { git = "https://gitlab.freedesktop.org/gstreamer/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"]
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
# NOTE: The canonical repository for gst-plugins-rs has moved to [freedesktop.org GitLab](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs)!
|
|
||||||
|
|
||||||
# gst-plugins-rs [![crates.io](https://img.shields.io/crates/v/gst-plugin.svg)](https://crates.io/crates/gst-plugin) [![pipeline status](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/badges/master/pipeline.svg)](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/commits/master)
|
|
||||||
|
|
||||||
Infrastructure for writing [GStreamer](https://gstreamer.freedesktop.org/)
|
|
||||||
plugins and elements in the [Rust programming
|
|
||||||
language](https://www.rust-lang.org/), and a collection of various GStreamer
|
|
||||||
plugins.
|
|
||||||
|
|
||||||
Documentation for the crate containing the infrastructure for writing
|
|
||||||
GStreamer plugins in Rust, [`gst-plugin`](gst-plugin), can be found
|
|
||||||
[here](https://slomo.pages.freedesktop.org/rustdocs/gst-plugin/gst_plugin). The whole
|
|
||||||
API builds upon the [application-side GStreamer bindings](https://gitlab.freedesktop.org/gstreamer/gstreamer-rs).
|
|
||||||
Check the README.md of that repository also for details about how to set-up
|
|
||||||
your development environment.
|
|
||||||
|
|
||||||
Various example plugins can be found in the [GIT repository](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/). A blog post series about writing GStreamer plugins/elements can be found [here](https://coaxion.net/blog/2018/01/how-to-write-gstreamer-elements-in-rust-part-1-a-video-filter-for-converting-rgb-to-grayscale/)[2](https://coaxion.net/blog/2018/02/how-to-write-gstreamer-elements-in-rust-part-2-a-raw-audio-sine-wave-source/).
|
|
||||||
|
|
||||||
For background and motivation, see the [announcement
|
|
||||||
blogpost](https://coaxion.net/blog/2016/05/writing-gstreamer-plugins-and-elements-in-rust/)
|
|
||||||
and the follow-up blogposts
|
|
||||||
[1](https://coaxion.net/blog/2016/09/writing-gstreamer-elements-in-rust-part-2-dont-panic-we-have-better-assertions-now-and-other-updates/),
|
|
||||||
[2](https://coaxion.net/blog/2016/11/writing-gstreamer-elements-in-rust-part-3-parsing-data-from-untrusted-sources-like-its-2016/),
|
|
||||||
[3](https://coaxion.net/blog/2017/03/writing-gstreamer-elements-in-rust-part-4-logging-cows-and-plugins/).
|
|
||||||
Note that the overall implementation has changed completely since those
|
|
||||||
blogposts were written.
|
|
||||||
|
|
||||||
## LICENSE
|
|
||||||
|
|
||||||
gst-plugins-rs and all crates contained in here that are not listed below are
|
|
||||||
licensed under either of
|
|
||||||
|
|
||||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
||||||
http://opensource.org/licenses/MIT)
|
|
||||||
|
|
||||||
at your option.
|
|
||||||
|
|
||||||
gst-plugin-togglerecord is licensed under the Lesser General Public License
|
|
||||||
([LICENSE-LGPLv2](LICENSE-LGPLv2)) version 2.1 or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
GStreamer itself is licensed under the Lesser General Public License version
|
|
||||||
2.1 or (at your option) any later version:
|
|
||||||
https://www.gnu.org/licenses/lgpl-2.1.html
|
|
||||||
|
|
||||||
## Contribution
|
|
||||||
|
|
||||||
Any kinds of contributions are welcome as a pull request.
|
|
||||||
|
|
||||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
|
||||||
for inclusion in gst-plugins-rs by you, as defined in the Apache-2.0 license, shall be
|
|
||||||
dual licensed as above, without any additional terms or conditions.
|
|
|
@ -1,334 +0,0 @@
|
||||||
// Copyright (C) 2016-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::cmp;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
use gst;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref CAT: gst::DebugCategory = {
|
|
||||||
gst::DebugCategory::new(
|
|
||||||
"rsadapter",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Rust buffer adapter",
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
|
||||||
pub struct Adapter {
|
|
||||||
deque: VecDeque<gst::MappedBuffer<gst::buffer::Readable>>,
|
|
||||||
size: usize,
|
|
||||||
skip: usize,
|
|
||||||
scratch: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub enum AdapterError {
|
|
||||||
NotEnoughData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for AdapterError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "Not enough data")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for AdapterError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
"Not enough data"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Adapter {
|
|
||||||
pub fn new() -> Adapter {
|
|
||||||
Adapter {
|
|
||||||
deque: VecDeque::new(),
|
|
||||||
size: 0,
|
|
||||||
skip: 0,
|
|
||||||
scratch: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, buffer: gst::Buffer) {
|
|
||||||
let size = buffer.get_size();
|
|
||||||
|
|
||||||
self.size += size;
|
|
||||||
gst_trace!(
|
|
||||||
CAT,
|
|
||||||
"Storing {:?} of size {}, now have size {}",
|
|
||||||
buffer,
|
|
||||||
size,
|
|
||||||
self.size
|
|
||||||
);
|
|
||||||
self.deque
|
|
||||||
.push_back(buffer.into_mapped_buffer_readable().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.deque.clear();
|
|
||||||
self.size = 0;
|
|
||||||
self.skip = 0;
|
|
||||||
self.scratch.clear();
|
|
||||||
gst_trace!(CAT, "Cleared adapter");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_available(&self) -> usize {
|
|
||||||
self.size
|
|
||||||
}
|
|
||||||
|
|
||||||
fn copy_data(
|
|
||||||
deque: &VecDeque<gst::MappedBuffer<gst::buffer::Readable>>,
|
|
||||||
skip: usize,
|
|
||||||
data: &mut [u8],
|
|
||||||
size: usize,
|
|
||||||
) {
|
|
||||||
let mut skip = skip;
|
|
||||||
let mut left = size;
|
|
||||||
let mut idx = 0;
|
|
||||||
|
|
||||||
gst_trace!(CAT, "Copying {} bytes", size);
|
|
||||||
|
|
||||||
for item in deque {
|
|
||||||
let data_item = item.as_slice();
|
|
||||||
|
|
||||||
let to_copy = cmp::min(left, data_item.len() - skip);
|
|
||||||
gst_trace!(
|
|
||||||
CAT,
|
|
||||||
"Copying {} bytes from {:?}, {} more to go",
|
|
||||||
to_copy,
|
|
||||||
item.get_buffer(),
|
|
||||||
left - to_copy
|
|
||||||
);
|
|
||||||
|
|
||||||
data[idx..idx + to_copy].copy_from_slice(&data_item[skip..skip + to_copy]);
|
|
||||||
skip = 0;
|
|
||||||
idx += to_copy;
|
|
||||||
left -= to_copy;
|
|
||||||
if left == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert_eq!(left, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn peek_into(&self, data: &mut [u8]) -> Result<(), AdapterError> {
|
|
||||||
let size = data.len();
|
|
||||||
|
|
||||||
if self.size < size {
|
|
||||||
gst_debug!(
|
|
||||||
CAT,
|
|
||||||
"Peeking {} bytes into, not enough data: have {}",
|
|
||||||
size,
|
|
||||||
self.size
|
|
||||||
);
|
|
||||||
return Err(AdapterError::NotEnoughData);
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_trace!(CAT, "Peeking {} bytes into", size);
|
|
||||||
if size == 0 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::copy_data(&self.deque, self.skip, data, size);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn peek(&mut self, size: usize) -> Result<&[u8], AdapterError> {
|
|
||||||
if self.size < size {
|
|
||||||
gst_debug!(
|
|
||||||
CAT,
|
|
||||||
"Peeking {} bytes, not enough data: have {}",
|
|
||||||
size,
|
|
||||||
self.size
|
|
||||||
);
|
|
||||||
return Err(AdapterError::NotEnoughData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if size == 0 {
|
|
||||||
return Ok(&[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(front) = self.deque.front() {
|
|
||||||
gst_trace!(CAT, "Peeking {} bytes, subbuffer of first", size);
|
|
||||||
if front.get_size() - self.skip >= size {
|
|
||||||
return Ok(&front.as_slice()[self.skip..self.skip + size]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_trace!(CAT, "Peeking {} bytes, copy to scratch", size);
|
|
||||||
|
|
||||||
self.scratch.truncate(0);
|
|
||||||
self.scratch.reserve(size);
|
|
||||||
{
|
|
||||||
let data = self.scratch.as_mut_slice();
|
|
||||||
Self::copy_data(&self.deque, self.skip, data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(self.scratch.as_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_buffer(&mut self, size: usize) -> Result<gst::Buffer, AdapterError> {
|
|
||||||
if self.size < size {
|
|
||||||
gst_debug!(
|
|
||||||
CAT,
|
|
||||||
"Get buffer of {} bytes, not enough data: have {}",
|
|
||||||
size,
|
|
||||||
self.size
|
|
||||||
);
|
|
||||||
return Err(AdapterError::NotEnoughData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if size == 0 {
|
|
||||||
return Ok(gst::Buffer::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
let sub = self.deque.front().and_then(|front| {
|
|
||||||
if front.get_size() - self.skip >= size {
|
|
||||||
gst_trace!(CAT, "Get buffer of {} bytes, subbuffer of first", size);
|
|
||||||
let new = front
|
|
||||||
.get_buffer()
|
|
||||||
.copy_region(*gst::BUFFER_COPY_ALL, self.skip, Some(size))
|
|
||||||
.unwrap();
|
|
||||||
Some(new)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(s) = sub {
|
|
||||||
self.flush(size).unwrap();
|
|
||||||
return Ok(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_trace!(CAT, "Get buffer of {} bytes, copy into new buffer", size);
|
|
||||||
let mut new = gst::Buffer::with_size(size).unwrap();
|
|
||||||
{
|
|
||||||
let mut map = new.get_mut().unwrap().map_writable().unwrap();
|
|
||||||
let data = map.as_mut_slice();
|
|
||||||
Self::copy_data(&self.deque, self.skip, data, size);
|
|
||||||
}
|
|
||||||
self.flush(size).unwrap();
|
|
||||||
Ok(new)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flush(&mut self, size: usize) -> Result<(), AdapterError> {
|
|
||||||
if self.size < size {
|
|
||||||
gst_debug!(
|
|
||||||
CAT,
|
|
||||||
"Flush {} bytes, not enough data: have {}",
|
|
||||||
size,
|
|
||||||
self.size
|
|
||||||
);
|
|
||||||
return Err(AdapterError::NotEnoughData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if size == 0 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_trace!(CAT, "Flushing {} bytes, have {}", size, self.size);
|
|
||||||
|
|
||||||
let mut left = size;
|
|
||||||
while left > 0 {
|
|
||||||
let front_size = self.deque.front().unwrap().get_size() - self.skip;
|
|
||||||
|
|
||||||
if front_size <= left {
|
|
||||||
gst_trace!(
|
|
||||||
CAT,
|
|
||||||
"Flushing whole {:?}, {} more to go",
|
|
||||||
self.deque.front().map(|b| b.get_buffer()),
|
|
||||||
left - front_size
|
|
||||||
);
|
|
||||||
self.deque.pop_front();
|
|
||||||
self.size -= front_size;
|
|
||||||
self.skip = 0;
|
|
||||||
left -= front_size;
|
|
||||||
} else {
|
|
||||||
gst_trace!(
|
|
||||||
CAT,
|
|
||||||
"Flushing partial {:?}, {} more left",
|
|
||||||
self.deque.front().map(|b| b.get_buffer()),
|
|
||||||
front_size - left
|
|
||||||
);
|
|
||||||
self.skip += left;
|
|
||||||
self.size -= left;
|
|
||||||
left = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl io::Read for Adapter {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
|
|
||||||
let mut len = self.size;
|
|
||||||
|
|
||||||
if len == 0 {
|
|
||||||
return Err(io::Error::new(
|
|
||||||
io::ErrorKind::WouldBlock,
|
|
||||||
format!(
|
|
||||||
"Missing data: requesting {} but only got {}.",
|
|
||||||
buf.len(),
|
|
||||||
len
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if buf.len() < len {
|
|
||||||
len = buf.len();
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::copy_data(&self.deque, self.skip, buf, len);
|
|
||||||
self.flush(len).unwrap();
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use gst;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_push_get() {
|
|
||||||
gst::init().unwrap();
|
|
||||||
|
|
||||||
let mut a = Adapter::new();
|
|
||||||
|
|
||||||
a.push(gst::Buffer::with_size(100).unwrap());
|
|
||||||
assert_eq!(a.get_available(), 100);
|
|
||||||
a.push(gst::Buffer::with_size(20).unwrap());
|
|
||||||
assert_eq!(a.get_available(), 120);
|
|
||||||
|
|
||||||
let b = a.get_buffer(20).unwrap();
|
|
||||||
assert_eq!(a.get_available(), 100);
|
|
||||||
assert_eq!(b.get_size(), 20);
|
|
||||||
let b = a.get_buffer(90).unwrap();
|
|
||||||
assert_eq!(a.get_available(), 10);
|
|
||||||
assert_eq!(b.get_size(), 90);
|
|
||||||
|
|
||||||
a.push(gst::Buffer::with_size(20).unwrap());
|
|
||||||
assert_eq!(a.get_available(), 30);
|
|
||||||
|
|
||||||
let b = a.get_buffer(20).unwrap();
|
|
||||||
assert_eq!(a.get_available(), 10);
|
|
||||||
assert_eq!(b.get_size(), 20);
|
|
||||||
let b = a.get_buffer(10).unwrap();
|
|
||||||
assert_eq!(a.get_available(), 0);
|
|
||||||
assert_eq!(b.get_size(), 10);
|
|
||||||
|
|
||||||
let b = a.get_buffer(1);
|
|
||||||
assert_eq!(b.err().unwrap(), AdapterError::NotEnoughData);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,867 +0,0 @@
|
||||||
// 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::FlowError> {
|
|
||||||
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::FlowError> {
|
|
||||||
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));
|
|
||||||
flow_ret.into_result_value(|| from_glib_full(out_caps))
|
|
||||||
})
|
|
||||||
.unwrap_or(Err(gst::FlowError::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) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
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()
|
|
||||||
}
|
|
|
@ -1,190 +0,0 @@
|
||||||
// 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_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 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) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
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()
|
|
||||||
}
|
|
|
@ -1,553 +0,0 @@
|
||||||
// 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 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 BaseSinkImpl<T: BaseSinkBase>:
|
|
||||||
AnyImpl + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn start(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn;
|
|
||||||
|
|
||||||
fn prepare(&self, _element: &T, _buffer: &gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
gst::FlowReturn::Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
|
|
||||||
for buffer in list.iter() {
|
|
||||||
let ret = self.render(element, buffer);
|
|
||||||
if ret != gst::FlowReturn::Ok {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gst::FlowReturn::Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
|
|
||||||
for buffer in list.iter() {
|
|
||||||
let ret = self.prepare(element, buffer);
|
|
||||||
if ret != gst::FlowReturn::Ok {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gst::FlowReturn::Ok
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
|
|
||||||
element.parent_query(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
element.parent_event(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_caps(&self, element: &T, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
|
|
||||||
element.parent_get_caps(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_caps(&self, element: &T, caps: &gst::CapsRef) -> bool {
|
|
||||||
element.parent_set_caps(caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fixate(&self, element: &T, caps: gst::Caps) -> gst::Caps {
|
|
||||||
element.parent_fixate(caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock_stop(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(BaseSinkBase, BaseSinkImpl, PanicPoison);
|
|
||||||
|
|
||||||
pub unsafe trait BaseSinkBase:
|
|
||||||
IsA<gst::Element> + IsA<gst_base::BaseSink> + ObjectType
|
|
||||||
{
|
|
||||||
fn parent_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::GstBaseSinkClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.query
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_event(&self, event: gst::Event) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.event
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, event.into_ptr())))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_get_caps(&self, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
|
|
||||||
let filter_ptr = if let Some(filter) = filter {
|
|
||||||
filter.as_mut_ptr()
|
|
||||||
} else {
|
|
||||||
ptr::null_mut()
|
|
||||||
};
|
|
||||||
|
|
||||||
(*parent_klass)
|
|
||||||
.get_caps
|
|
||||||
.map(|f| from_glib_full(f(self.to_glib_none().0, filter_ptr)))
|
|
||||||
.unwrap_or(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_set_caps(&self, caps: &gst::CapsRef) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.set_caps
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, caps.as_mut_ptr())))
|
|
||||||
.unwrap_or(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSinkClass;
|
|
||||||
|
|
||||||
match (*parent_klass).fixate {
|
|
||||||
Some(fixate) => from_glib_full(fixate(self.to_glib_none().0, caps.into_ptr())),
|
|
||||||
None => caps,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait BaseSinkClassExt<T: BaseSinkBase>
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
|
||||||
unsafe {
|
|
||||||
let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseSinkClass);
|
|
||||||
klass.start = Some(base_sink_start::<T>);
|
|
||||||
klass.stop = Some(base_sink_stop::<T>);
|
|
||||||
klass.render = Some(base_sink_render::<T>);
|
|
||||||
klass.render_list = Some(base_sink_render_list::<T>);
|
|
||||||
klass.prepare = Some(base_sink_prepare::<T>);
|
|
||||||
klass.prepare_list = Some(base_sink_prepare_list::<T>);
|
|
||||||
klass.query = Some(base_sink_query::<T>);
|
|
||||||
klass.event = Some(base_sink_event::<T>);
|
|
||||||
klass.get_caps = Some(base_sink_get_caps::<T>);
|
|
||||||
klass.set_caps = Some(base_sink_set_caps::<T>);
|
|
||||||
klass.fixate = Some(base_sink_fixate::<T>);
|
|
||||||
klass.unlock = Some(base_sink_unlock::<T>);
|
|
||||||
klass.unlock_stop = Some(base_sink_unlock_stop::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct BaseSink(Object<ElementInstanceStruct<BaseSink>>):
|
|
||||||
[gst_base::BaseSink => gst_base_ffi::GstBaseSink,
|
|
||||||
gst::Element => gst_ffi::GstElement,
|
|
||||||
gst::Object => gst_ffi::GstObject];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<BaseSink>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Element> + IsA<gst_base::BaseSink> + ObjectType> BaseSinkBase for T {}
|
|
||||||
pub type BaseSinkClass = ClassStruct<BaseSink>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl BaseSinkClassExt<BaseSink> for BaseSinkClass {}
|
|
||||||
unsafe impl ElementClassExt<BaseSink> for BaseSinkClass {}
|
|
||||||
unsafe impl ObjectClassExt<BaseSink> for BaseSinkClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for BaseSink {}
|
|
||||||
unsafe impl Sync for BaseSink {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_base_sink_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_element_impl!($name);
|
|
||||||
|
|
||||||
impl<T: BaseSinkBase> BaseSinkImpl<T> for Box<$name<T>>
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison
|
|
||||||
{
|
|
||||||
fn start(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.start(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.stop(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.render(element, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare(&self, element: &T, buffer: &gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.prepare(element, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.render_list(element, list)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prepare_list(&self, element: &T, list: &gst::BufferListRef) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.prepare_list(element, list)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
BaseSinkImpl::query(imp, element, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.event(element, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_caps(&self, element: &T, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.get_caps(element, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_caps(&self, element: &T, caps: &gst::CapsRef) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.set_caps(element, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fixate(&self, element: &T, caps: gst::Caps) -> gst::Caps {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.fixate(element, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.unlock(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock_stop(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.unlock_stop(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
box_base_sink_impl!(BaseSinkImpl);
|
|
||||||
|
|
||||||
impl ObjectType for BaseSink {
|
|
||||||
const NAME: &'static str = "RsBaseSink";
|
|
||||||
type ParentType = gst_base::BaseSink;
|
|
||||||
type ImplType = Box<BaseSinkImpl<Self>>;
|
|
||||||
type InstanceStructType = ElementInstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut BaseSinkClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
ElementClassExt::override_vfuncs(klass, token);
|
|
||||||
BaseSinkClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_start<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.start(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_stop<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.stop(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_render<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
buffer: *mut gst_ffi::GstBuffer,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let buffer = gst::BufferRef::from_ptr(buffer);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
imp.render(&wrap, buffer)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_prepare<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
buffer: *mut gst_ffi::GstBuffer,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let buffer = gst::BufferRef::from_ptr(buffer);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
imp.prepare(&wrap, buffer)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_render_list<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
list: *mut gst_ffi::GstBufferList,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let list = gst::BufferListRef::from_ptr(list);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
imp.render_list(&wrap, list)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_prepare_list<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
list: *mut gst_ffi::GstBufferList,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let list = gst::BufferListRef::from_ptr(list);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
imp.prepare_list(&wrap, list)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_query<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
query_ptr: *mut gst_ffi::GstQuery,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let query = gst::QueryRef::from_mut_ptr(query_ptr);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
BaseSinkImpl::query(imp, &wrap, query)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_event<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
event_ptr: *mut gst_ffi::GstEvent,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.event(&wrap, from_glib_full(event_ptr))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_get_caps<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
filter: *mut gst_ffi::GstCaps,
|
|
||||||
) -> *mut gst_ffi::GstCaps
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let filter = if filter.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(gst::CapsRef::from_ptr(filter))
|
|
||||||
};
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), None, {
|
|
||||||
imp.get_caps(&wrap, filter)
|
|
||||||
})
|
|
||||||
.map(|caps| caps.into_ptr())
|
|
||||||
.unwrap_or(ptr::null_mut())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_set_caps<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let caps = gst::CapsRef::from_ptr(caps);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.set_caps(&wrap, caps)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_fixate<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
) -> *mut gst_ffi::GstCaps
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let caps = from_glib_full(caps);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::Caps::new_empty(), {
|
|
||||||
imp.fixate(&wrap, caps)
|
|
||||||
})
|
|
||||||
.into_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_unlock<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.unlock(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_sink_unlock_stop<T: BaseSinkBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSink,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSinkImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.unlock_stop(&wrap)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
|
@ -1,668 +0,0 @@
|
||||||
// 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 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 BaseSrcImpl<T: BaseSrcBase>:
|
|
||||||
AnyImpl + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn start(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_seekable(&self, _element: &T) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_size(&self, _element: &T) -> Option<u64> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill(
|
|
||||||
&self,
|
|
||||||
_element: &T,
|
|
||||||
_offset: u64,
|
|
||||||
_length: u32,
|
|
||||||
_buffer: &mut gst::BufferRef,
|
|
||||||
) -> gst::FlowReturn {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(&self, element: &T, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> {
|
|
||||||
element.parent_create(offset, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_seek(&self, element: &T, segment: &mut gst::Segment) -> bool {
|
|
||||||
element.parent_do_seek(segment)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
|
|
||||||
element.parent_query(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&self, element: &T, event: &gst::Event) -> bool {
|
|
||||||
element.parent_event(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_caps(&self, element: &T, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
|
|
||||||
element.parent_get_caps(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn negotiate(&self, element: &T) -> bool {
|
|
||||||
element.parent_negotiate()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_caps(&self, element: &T, caps: &gst::CapsRef) -> bool {
|
|
||||||
element.parent_set_caps(caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fixate(&self, element: &T, caps: gst::Caps) -> gst::Caps {
|
|
||||||
element.parent_fixate(caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock_stop(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(BaseSrcBase, BaseSrcImpl, PanicPoison);
|
|
||||||
|
|
||||||
pub unsafe trait BaseSrcBase:
|
|
||||||
IsA<gst::Element> + IsA<gst_base::BaseSrc> + ObjectType
|
|
||||||
{
|
|
||||||
fn parent_create(&self, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.create
|
|
||||||
.map(|f| {
|
|
||||||
let mut buffer: *mut gst_ffi::GstBuffer = ptr::null_mut();
|
|
||||||
// FIXME: Wrong signature in -sys bindings
|
|
||||||
// https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
|
|
||||||
let buffer_ref = &mut buffer as *mut _ as *mut gst_ffi::GstBuffer;
|
|
||||||
let ret: gst::FlowReturn =
|
|
||||||
from_glib(f(self.to_glib_none().0, offset, length, buffer_ref));
|
|
||||||
|
|
||||||
ret.into_result_value(|| from_glib_full(buffer))
|
|
||||||
})
|
|
||||||
.unwrap_or(Err(gst::FlowError::Error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_do_seek(&self, segment: &mut gst::Segment) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.do_seek
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, segment.to_glib_none_mut().0)))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_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::GstBaseSrcClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.query
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_event(&self, event: &gst::Event) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.event
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, event.to_glib_none().0)))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_get_caps(&self, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
|
|
||||||
let filter_ptr = if let Some(filter) = filter {
|
|
||||||
filter.as_mut_ptr()
|
|
||||||
} else {
|
|
||||||
ptr::null_mut()
|
|
||||||
};
|
|
||||||
|
|
||||||
(*parent_klass)
|
|
||||||
.get_caps
|
|
||||||
.map(|f| from_glib_full(f(self.to_glib_none().0, filter_ptr)))
|
|
||||||
.unwrap_or(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_negotiate(&self) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.negotiate
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0)))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_set_caps(&self, caps: &gst::CapsRef) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.set_caps
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, caps.as_mut_ptr())))
|
|
||||||
.unwrap_or(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
|
|
||||||
|
|
||||||
match (*parent_klass).fixate {
|
|
||||||
Some(fixate) => from_glib_full(fixate(self.to_glib_none().0, caps.into_ptr())),
|
|
||||||
None => caps,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait BaseSrcClassExt<T: BaseSrcBase>
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
|
||||||
unsafe {
|
|
||||||
let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseSrcClass);
|
|
||||||
klass.start = Some(base_src_start::<T>);
|
|
||||||
klass.stop = Some(base_src_stop::<T>);
|
|
||||||
klass.is_seekable = Some(base_src_is_seekable::<T>);
|
|
||||||
klass.get_size = Some(base_src_get_size::<T>);
|
|
||||||
klass.fill = Some(base_src_fill::<T>);
|
|
||||||
klass.create = Some(base_src_create::<T>);
|
|
||||||
klass.do_seek = Some(base_src_do_seek::<T>);
|
|
||||||
klass.query = Some(base_src_query::<T>);
|
|
||||||
klass.event = Some(base_src_event::<T>);
|
|
||||||
klass.get_caps = Some(base_src_get_caps::<T>);
|
|
||||||
klass.negotiate = Some(base_src_negotiate::<T>);
|
|
||||||
klass.set_caps = Some(base_src_set_caps::<T>);
|
|
||||||
klass.fixate = Some(base_src_fixate::<T>);
|
|
||||||
klass.unlock = Some(base_src_unlock::<T>);
|
|
||||||
klass.unlock_stop = Some(base_src_unlock_stop::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct BaseSrc(Object<ElementInstanceStruct<BaseSrc>>):
|
|
||||||
[gst_base::BaseSrc => gst_base_ffi::GstBaseSrc,
|
|
||||||
gst::Element => gst_ffi::GstElement,
|
|
||||||
gst::Object => gst_ffi::GstObject];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<BaseSrc>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Element> + IsA<gst_base::BaseSrc> + ObjectType> BaseSrcBase for T {}
|
|
||||||
pub type BaseSrcClass = ClassStruct<BaseSrc>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl BaseSrcClassExt<BaseSrc> for BaseSrcClass {}
|
|
||||||
unsafe impl ElementClassExt<BaseSrc> for BaseSrcClass {}
|
|
||||||
unsafe impl ObjectClassExt<BaseSrc> for BaseSrcClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for BaseSrc {}
|
|
||||||
unsafe impl Sync for BaseSrc {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_base_src_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_element_impl!($name);
|
|
||||||
|
|
||||||
impl<T: BaseSrcBase> BaseSrcImpl<T> for Box<$name<T>>
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison
|
|
||||||
{
|
|
||||||
fn start(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.start(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.stop(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_seekable(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.is_seekable(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_size(&self, element: &T) -> Option<u64> {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.get_size(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill(
|
|
||||||
&self,
|
|
||||||
element: &T,
|
|
||||||
offset: u64,
|
|
||||||
length: u32,
|
|
||||||
buffer: &mut gst::BufferRef,
|
|
||||||
) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.fill(element, offset, length, buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(
|
|
||||||
&self,
|
|
||||||
element: &T,
|
|
||||||
offset: u64,
|
|
||||||
length: u32,
|
|
||||||
) -> Result<gst::Buffer, gst::FlowError> {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.create(element, offset, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_seek(&self, element: &T, segment: &mut gst::Segment) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.do_seek(element, segment)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
BaseSrcImpl::query(imp, element, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn event(&self, element: &T, event: &gst::Event) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.event(element, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_caps(&self, element: &T, filter: Option<&gst::CapsRef>) -> Option<gst::Caps> {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.get_caps(element, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn negotiate(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.negotiate(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_caps(&self, element: &T, caps: &gst::CapsRef) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.set_caps(element, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fixate(&self, element: &T, caps: gst::Caps) -> gst::Caps {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.fixate(element, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.unlock(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock_stop(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.unlock_stop(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
box_base_src_impl!(BaseSrcImpl);
|
|
||||||
|
|
||||||
impl ObjectType for BaseSrc {
|
|
||||||
const NAME: &'static str = "RsBaseSrc";
|
|
||||||
type ParentType = gst_base::BaseSrc;
|
|
||||||
type ImplType = Box<BaseSrcImpl<Self>>;
|
|
||||||
type InstanceStructType = ElementInstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut BaseSrcClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
ElementClassExt::override_vfuncs(klass, token);
|
|
||||||
BaseSrcClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_start<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.start(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_stop<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.stop(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_is_seekable<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.is_seekable(&wrap)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_get_size<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
size: *mut u64,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
match imp.get_size(&wrap) {
|
|
||||||
Some(s) => {
|
|
||||||
*size = s;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_fill<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
offset: u64,
|
|
||||||
length: u32,
|
|
||||||
buffer: *mut gst_ffi::GstBuffer,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let buffer = gst::BufferRef::from_mut_ptr(buffer);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
imp.fill(&wrap, offset, length, buffer)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_create<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
offset: u64,
|
|
||||||
length: u32,
|
|
||||||
buffer_ptr: *mut gst_ffi::GstBuffer,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
// FIXME: Wrong signature in -sys bindings
|
|
||||||
// https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3
|
|
||||||
let buffer_ptr = buffer_ptr as *mut *mut gst_ffi::GstBuffer;
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
match imp.create(&wrap, offset, length) {
|
|
||||||
Ok(buffer) => {
|
|
||||||
*buffer_ptr = buffer.into_ptr();
|
|
||||||
gst::FlowReturn::Ok
|
|
||||||
}
|
|
||||||
Err(err) => gst::FlowReturn::from(err),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_do_seek<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
segment: *mut gst_ffi::GstSegment,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.do_seek(&wrap, &mut from_glib_borrow(segment))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_query<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
query_ptr: *mut gst_ffi::GstQuery,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let query = gst::QueryRef::from_mut_ptr(query_ptr);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
BaseSrcImpl::query(imp, &wrap, query)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_event<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
event_ptr: *mut gst_ffi::GstEvent,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.event(&wrap, &from_glib_borrow(event_ptr))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_get_caps<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
filter: *mut gst_ffi::GstCaps,
|
|
||||||
) -> *mut gst_ffi::GstCaps
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let filter = if filter.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(gst::CapsRef::from_ptr(filter))
|
|
||||||
};
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), None, {
|
|
||||||
imp.get_caps(&wrap, filter)
|
|
||||||
})
|
|
||||||
.map(|caps| caps.into_ptr())
|
|
||||||
.unwrap_or(ptr::null_mut())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_negotiate<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.negotiate(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_set_caps<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let caps = gst::CapsRef::from_ptr(caps);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.set_caps(&wrap, caps)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_fixate<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
) -> *mut gst_ffi::GstCaps
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let caps = from_glib_full(caps);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::Caps::new_empty(), {
|
|
||||||
imp.fixate(&wrap, caps)
|
|
||||||
})
|
|
||||||
.into_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_unlock<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.unlock(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_src_unlock_stop<T: BaseSrcBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseSrc,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseSrcImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.unlock_stop(&wrap)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
|
@ -1,741 +0,0 @@
|
||||||
// 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 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 BaseTransformImpl<T: BaseTransformBase>:
|
|
||||||
AnyImpl + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn start(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, _element: &T) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_caps(
|
|
||||||
&self,
|
|
||||||
element: &T,
|
|
||||||
direction: gst::PadDirection,
|
|
||||||
caps: &gst::Caps,
|
|
||||||
filter: Option<&gst::Caps>,
|
|
||||||
) -> gst::Caps {
|
|
||||||
element.parent_transform_caps(direction, caps, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fixate_caps(
|
|
||||||
&self,
|
|
||||||
element: &T,
|
|
||||||
direction: gst::PadDirection,
|
|
||||||
caps: &gst::Caps,
|
|
||||||
othercaps: gst::Caps,
|
|
||||||
) -> gst::Caps {
|
|
||||||
element.parent_fixate_caps(direction, caps, othercaps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_caps(&self, _element: &T, _incaps: &gst::Caps, _outcaps: &gst::Caps) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn accept_caps(&self, element: &T, direction: gst::PadDirection, caps: &gst::Caps) -> bool {
|
|
||||||
element.parent_accept_caps(direction, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, direction: gst::PadDirection, query: &mut gst::QueryRef) -> bool {
|
|
||||||
element.parent_query(direction, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_size(
|
|
||||||
&self,
|
|
||||||
element: &T,
|
|
||||||
direction: gst::PadDirection,
|
|
||||||
caps: &gst::Caps,
|
|
||||||
size: usize,
|
|
||||||
othercaps: &gst::Caps,
|
|
||||||
) -> Option<usize> {
|
|
||||||
element.parent_transform_size(direction, caps, size, othercaps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_unit_size(&self, _element: &T, _caps: &gst::Caps) -> Option<usize> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sink_event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
element.parent_sink_event(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn src_event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
element.parent_src_event(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform(
|
|
||||||
&self,
|
|
||||||
_element: &T,
|
|
||||||
_inbuf: &gst::Buffer,
|
|
||||||
_outbuf: &mut gst::BufferRef,
|
|
||||||
) -> gst::FlowReturn {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_ip(&self, _element: &T, _buf: &mut gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_ip_passthrough(&self, _element: &T, _buf: &gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(BaseTransformBase, BaseTransformImpl, PanicPoison);
|
|
||||||
|
|
||||||
pub unsafe trait BaseTransformBase:
|
|
||||||
IsA<gst::Element> + IsA<gst_base::BaseTransform> + ObjectType
|
|
||||||
where
|
|
||||||
Self::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn parent_transform_caps(
|
|
||||||
&self,
|
|
||||||
direction: gst::PadDirection,
|
|
||||||
caps: &gst::Caps,
|
|
||||||
filter: Option<&gst::Caps>,
|
|
||||||
) -> gst::Caps {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass =
|
|
||||||
(*klass).get_parent_class() as *const gst_base_ffi::GstBaseTransformClass;
|
|
||||||
match (*parent_klass).transform_caps {
|
|
||||||
Some(f) => from_glib_full(f(
|
|
||||||
self.to_glib_none().0,
|
|
||||||
direction.to_glib(),
|
|
||||||
caps.to_glib_none().0,
|
|
||||||
filter.to_glib_none().0,
|
|
||||||
)),
|
|
||||||
None => caps.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_fixate_caps(
|
|
||||||
&self,
|
|
||||||
direction: gst::PadDirection,
|
|
||||||
caps: &gst::Caps,
|
|
||||||
othercaps: gst::Caps,
|
|
||||||
) -> gst::Caps {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass =
|
|
||||||
(*klass).get_parent_class() as *const gst_base_ffi::GstBaseTransformClass;
|
|
||||||
match (*parent_klass).fixate_caps {
|
|
||||||
Some(f) => from_glib_full(f(
|
|
||||||
self.to_glib_none().0,
|
|
||||||
direction.to_glib(),
|
|
||||||
caps.to_glib_none().0,
|
|
||||||
othercaps.into_ptr(),
|
|
||||||
)),
|
|
||||||
None => othercaps,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_accept_caps(&self, direction: gst::PadDirection, caps: &gst::Caps) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass =
|
|
||||||
(*klass).get_parent_class() as *const gst_base_ffi::GstBaseTransformClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.accept_caps
|
|
||||||
.map(|f| {
|
|
||||||
from_glib(f(
|
|
||||||
self.to_glib_none().0,
|
|
||||||
direction.to_glib(),
|
|
||||||
caps.to_glib_none().0,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_query(&self, direction: gst::PadDirection, query: &mut gst::QueryRef) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass =
|
|
||||||
(*klass).get_parent_class() as *const gst_base_ffi::GstBaseTransformClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.query
|
|
||||||
.map(|f| {
|
|
||||||
from_glib(f(
|
|
||||||
self.to_glib_none().0,
|
|
||||||
direction.to_glib(),
|
|
||||||
query.as_mut_ptr(),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_transform_size(
|
|
||||||
&self,
|
|
||||||
direction: gst::PadDirection,
|
|
||||||
caps: &gst::Caps,
|
|
||||||
size: usize,
|
|
||||||
othercaps: &gst::Caps,
|
|
||||||
) -> Option<usize> {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass =
|
|
||||||
(*klass).get_parent_class() as *const gst_base_ffi::GstBaseTransformClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.transform_size
|
|
||||||
.map(|f| {
|
|
||||||
let mut othersize = 0;
|
|
||||||
let res: bool = from_glib(f(
|
|
||||||
self.to_glib_none().0,
|
|
||||||
direction.to_glib(),
|
|
||||||
caps.to_glib_none().0,
|
|
||||||
size,
|
|
||||||
othercaps.to_glib_none().0,
|
|
||||||
&mut othersize,
|
|
||||||
));
|
|
||||||
if res {
|
|
||||||
Some(othersize)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_sink_event(&self, event: gst::Event) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass =
|
|
||||||
(*klass).get_parent_class() as *const gst_base_ffi::GstBaseTransformClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.sink_event
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, event.into_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::GstBaseTransformClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.src_event
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, event.into_ptr())))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum BaseTransformMode {
|
|
||||||
AlwaysInPlace,
|
|
||||||
NeverInPlace,
|
|
||||||
Both,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait BaseTransformClassExt<T: BaseTransformBase>
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn configure(
|
|
||||||
&mut self,
|
|
||||||
mode: BaseTransformMode,
|
|
||||||
passthrough_on_same_caps: bool,
|
|
||||||
transform_ip_on_passthrough: bool,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseTransformClass);
|
|
||||||
|
|
||||||
klass.passthrough_on_same_caps = passthrough_on_same_caps.to_glib();
|
|
||||||
klass.transform_ip_on_passthrough = transform_ip_on_passthrough.to_glib();
|
|
||||||
|
|
||||||
match mode {
|
|
||||||
BaseTransformMode::AlwaysInPlace => {
|
|
||||||
klass.transform_ip = Some(base_transform_transform_ip::<T>);
|
|
||||||
}
|
|
||||||
BaseTransformMode::NeverInPlace => {
|
|
||||||
klass.transform = Some(base_transform_transform::<T>);
|
|
||||||
}
|
|
||||||
BaseTransformMode::Both => {
|
|
||||||
klass.transform = Some(base_transform_transform::<T>);
|
|
||||||
klass.transform_ip = Some(base_transform_transform_ip::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
|
||||||
unsafe {
|
|
||||||
let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseTransformClass);
|
|
||||||
klass.start = Some(base_transform_start::<T>);
|
|
||||||
klass.stop = Some(base_transform_stop::<T>);
|
|
||||||
klass.transform_caps = Some(base_transform_transform_caps::<T>);
|
|
||||||
klass.fixate_caps = Some(base_transform_fixate_caps::<T>);
|
|
||||||
klass.set_caps = Some(base_transform_set_caps::<T>);
|
|
||||||
klass.accept_caps = Some(base_transform_accept_caps::<T>);
|
|
||||||
klass.query = Some(base_transform_query::<T>);
|
|
||||||
klass.transform_size = Some(base_transform_transform_size::<T>);
|
|
||||||
klass.get_unit_size = Some(base_transform_get_unit_size::<T>);
|
|
||||||
klass.sink_event = Some(base_transform_sink_event::<T>);
|
|
||||||
klass.src_event = Some(base_transform_src_event::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct BaseTransform(Object<ElementInstanceStruct<BaseTransform>>):
|
|
||||||
[gst_base::BaseTransform => gst_base_ffi::GstBaseTransform,
|
|
||||||
gst::Element => gst_ffi::GstElement,
|
|
||||||
gst::Object => gst_ffi::GstObject];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<BaseTransform>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Element> + IsA<gst_base::BaseTransform> + ObjectType> BaseTransformBase
|
|
||||||
for T
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
pub type BaseTransformClass = ClassStruct<BaseTransform>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl BaseTransformClassExt<BaseTransform> for BaseTransformClass {}
|
|
||||||
unsafe impl ElementClassExt<BaseTransform> for BaseTransformClass {}
|
|
||||||
unsafe impl ObjectClassExt<BaseTransform> for BaseTransformClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for BaseTransform {}
|
|
||||||
unsafe impl Sync for BaseTransform {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_base_transform_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_element_impl!($name);
|
|
||||||
|
|
||||||
impl<T: BaseTransformBase> BaseTransformImpl<T> for Box<$name<T>>
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison
|
|
||||||
{
|
|
||||||
fn start(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.start(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop(&self, element: &T) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.stop(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_caps(&self, element: &T, direction: gst::PadDirection, caps: &gst::Caps, filter: Option<&gst::Caps>) -> gst::Caps {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.transform_caps(element, direction, caps, filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fixate_caps(&self, element: &T, direction: gst::PadDirection, caps: &gst::Caps, othercaps: gst::Caps) -> gst::Caps {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.fixate_caps(element, direction, caps, othercaps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_caps(&self, element: &T, incaps: &gst::Caps, outcaps: &gst::Caps) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.set_caps(element, incaps, outcaps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn accept_caps(&self, element: &T, direction: gst::PadDirection, caps: &gst::Caps) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.accept_caps(element, direction, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, direction: gst::PadDirection, query: &mut gst::QueryRef) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
BaseTransformImpl::query(imp, element, direction, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_size(&self, element: &T, direction: gst::PadDirection, caps: &gst::Caps, size: usize, othercaps: &gst::Caps) -> Option<usize> {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.transform_size(element, direction, caps, size, othercaps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_unit_size(&self, element: &T, caps: &gst::Caps) -> Option<usize> {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.get_unit_size(element, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sink_event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.sink_event(element, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn src_event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.src_event(element, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform(&self, element: &T, inbuf: &gst::Buffer, outbuf: &mut gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.transform(element, inbuf, outbuf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_ip(&self, element: &T, buf: &mut gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.transform_ip(element, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transform_ip_passthrough(&self, element: &T, buf: &gst::BufferRef) -> gst::FlowReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.transform_ip_passthrough(element, buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
box_base_transform_impl!(BaseTransformImpl);
|
|
||||||
|
|
||||||
impl ObjectType for BaseTransform {
|
|
||||||
const NAME: &'static str = "RsBaseTransform";
|
|
||||||
type ParentType = gst_base::BaseTransform;
|
|
||||||
type ImplType = Box<BaseTransformImpl<Self>>;
|
|
||||||
type InstanceStructType = ElementInstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut BaseTransformClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
ElementClassExt::override_vfuncs(klass, token);
|
|
||||||
BaseTransformClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_start<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.start(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_stop<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, { imp.stop(&wrap) }).to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_transform_caps<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
direction: gst_ffi::GstPadDirection,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
filter: *mut gst_ffi::GstCaps,
|
|
||||||
) -> *mut gst_ffi::GstCaps
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::Caps::new_empty(), {
|
|
||||||
let filter = if filter.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(from_glib_borrow(filter))
|
|
||||||
};
|
|
||||||
|
|
||||||
imp.transform_caps(
|
|
||||||
&wrap,
|
|
||||||
from_glib(direction),
|
|
||||||
&from_glib_borrow(caps),
|
|
||||||
filter.as_ref(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.into_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_fixate_caps<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
direction: gst_ffi::GstPadDirection,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
othercaps: *mut gst_ffi::GstCaps,
|
|
||||||
) -> *mut gst_ffi::GstCaps
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::Caps::new_empty(), {
|
|
||||||
imp.fixate_caps(
|
|
||||||
&wrap,
|
|
||||||
from_glib(direction),
|
|
||||||
&from_glib_borrow(caps),
|
|
||||||
from_glib_full(othercaps),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.into_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_set_caps<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
incaps: *mut gst_ffi::GstCaps,
|
|
||||||
outcaps: *mut gst_ffi::GstCaps,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.set_caps(&wrap, &from_glib_borrow(incaps), &from_glib_borrow(outcaps))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_accept_caps<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
direction: gst_ffi::GstPadDirection,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.accept_caps(&wrap, from_glib(direction), &from_glib_borrow(caps))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_query<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
direction: gst_ffi::GstPadDirection,
|
|
||||||
query: *mut gst_ffi::GstQuery,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
BaseTransformImpl::query(
|
|
||||||
imp,
|
|
||||||
&wrap,
|
|
||||||
from_glib(direction),
|
|
||||||
gst::QueryRef::from_mut_ptr(query),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_transform_size<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
direction: gst_ffi::GstPadDirection,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
size: usize,
|
|
||||||
othercaps: *mut gst_ffi::GstCaps,
|
|
||||||
othersize: *mut usize,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
match imp.transform_size(
|
|
||||||
&wrap,
|
|
||||||
from_glib(direction),
|
|
||||||
&from_glib_borrow(caps),
|
|
||||||
size,
|
|
||||||
&from_glib_borrow(othercaps),
|
|
||||||
) {
|
|
||||||
Some(s) => {
|
|
||||||
*othersize = s;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_get_unit_size<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
caps: *mut gst_ffi::GstCaps,
|
|
||||||
size: *mut usize,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
match imp.get_unit_size(&wrap, &from_glib_borrow(caps)) {
|
|
||||||
Some(s) => {
|
|
||||||
*size = s;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_sink_event<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
event: *mut gst_ffi::GstEvent,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.sink_event(&wrap, from_glib_full(event))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_src_event<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
event: *mut gst_ffi::GstEvent,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.src_event(&wrap, from_glib_full(event))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_transform<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
inbuf: *mut gst_ffi::GstBuffer,
|
|
||||||
outbuf: *mut gst_ffi::GstBuffer,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
imp.transform(
|
|
||||||
&wrap,
|
|
||||||
&from_glib_borrow(inbuf),
|
|
||||||
gst::BufferRef::from_mut_ptr(outbuf),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn base_transform_transform_ip<T: BaseTransformBase>(
|
|
||||||
ptr: *mut gst_base_ffi::GstBaseTransform,
|
|
||||||
buf: *mut *mut gst_ffi::GstBuffer,
|
|
||||||
) -> gst_ffi::GstFlowReturn
|
|
||||||
where
|
|
||||||
T::ImplType: BaseTransformImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
// FIXME: Wrong signature in FFI
|
|
||||||
let buf = buf as *mut gst_ffi::GstBuffer;
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), gst::FlowReturn::Error, {
|
|
||||||
if from_glib(gst_base_ffi::gst_base_transform_is_passthrough(ptr)) {
|
|
||||||
imp.transform_ip_passthrough(&wrap, gst::BufferRef::from_ptr(buf))
|
|
||||||
} else {
|
|
||||||
imp.transform_ip(&wrap, gst::BufferRef::from_mut_ptr(buf))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
|
@ -1,215 +0,0 @@
|
||||||
// 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 glib_ffi;
|
|
||||||
use gobject_ffi;
|
|
||||||
use gst_ffi;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use glib::translate::*;
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
|
|
||||||
use gobject_subclass::anyimpl::*;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
use element::*;
|
|
||||||
use object::*;
|
|
||||||
|
|
||||||
pub trait BinImpl<T: BinBase>:
|
|
||||||
AnyImpl + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn add_element(&self, bin: &T, element: &gst::Element) -> bool {
|
|
||||||
bin.parent_add_element(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_element(&self, bin: &T, element: &gst::Element) -> bool {
|
|
||||||
bin.parent_remove_element(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_message(&self, bin: &T, message: gst::Message) {
|
|
||||||
bin.parent_handle_message(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(BinBase, BinImpl, PanicPoison);
|
|
||||||
|
|
||||||
pub unsafe trait BinBase: IsA<gst::Element> + IsA<gst::Bin> + ObjectType {
|
|
||||||
fn parent_add_element(&self, element: &gst::Element) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstBinClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.add_element
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, element.to_glib_none().0)))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_remove_element(&self, element: &gst::Element) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstBinClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.remove_element
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, element.to_glib_none().0)))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_handle_message(&self, message: gst::Message) {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstBinClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.handle_message
|
|
||||||
.map(move |f| f(self.to_glib_none().0, message.into_ptr()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait BinClassExt<T: BinBase>
|
|
||||||
where
|
|
||||||
T::ImplType: BinImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
|
||||||
unsafe {
|
|
||||||
let klass = &mut *(self as *const Self as *mut gst_ffi::GstBinClass);
|
|
||||||
klass.add_element = Some(bin_add_element::<T>);
|
|
||||||
klass.remove_element = Some(bin_remove_element::<T>);
|
|
||||||
klass.handle_message = Some(bin_handle_message::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct Bin(Object<ElementInstanceStruct<Bin>>):
|
|
||||||
[gst::Bin => gst_ffi::GstBin,
|
|
||||||
gst::Element => gst_ffi::GstElement,
|
|
||||||
gst::Object => gst_ffi::GstObject,
|
|
||||||
gst::ChildProxy => gst_ffi::GstChildProxy];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<Bin>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Element> + IsA<gst::Bin> + ObjectType> BinBase for T {}
|
|
||||||
pub type BinClass = ClassStruct<Bin>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl BinClassExt<Bin> for BinClass {}
|
|
||||||
unsafe impl ElementClassExt<Bin> for BinClass {}
|
|
||||||
unsafe impl ObjectClassExt<Bin> for BinClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for Bin {}
|
|
||||||
unsafe impl Sync for Bin {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_bin_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_element_impl!($name);
|
|
||||||
|
|
||||||
impl<T: BinBase> BinImpl<T> for Box<$name<T>>
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison
|
|
||||||
{
|
|
||||||
fn add_element(&self, bin: &T, element: &gst::Element) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.add_element(bin, element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_element(&self, bin: &T, element: &gst::Element) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.remove_element(bin, element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_message(&self, bin: &T, message: gst::Message) {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.handle_message(bin, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
box_bin_impl!(BinImpl);
|
|
||||||
|
|
||||||
impl ObjectType for Bin {
|
|
||||||
const NAME: &'static str = "RsBin";
|
|
||||||
type ParentType = gst::Bin;
|
|
||||||
type ImplType = Box<BinImpl<Self>>;
|
|
||||||
type InstanceStructType = ElementInstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut BinClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
ElementClassExt::override_vfuncs(klass, token);
|
|
||||||
BinClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn bin_add_element<T: BinBase>(
|
|
||||||
ptr: *mut gst_ffi::GstBin,
|
|
||||||
element: *mut gst_ffi::GstElement,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BinImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let bin = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = bin.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &bin.panicked(), false, {
|
|
||||||
imp.add_element(&wrap, &from_glib_borrow(element))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn bin_remove_element<T: BinBase>(
|
|
||||||
ptr: *mut gst_ffi::GstBin,
|
|
||||||
element: *mut gst_ffi::GstElement,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: BinImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let bin = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = bin.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &bin.panicked(), false, {
|
|
||||||
imp.remove_element(&wrap, &from_glib_borrow(element))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn bin_handle_message<T: BinBase>(
|
|
||||||
ptr: *mut gst_ffi::GstBin,
|
|
||||||
message: *mut gst_ffi::GstMessage,
|
|
||||||
) where
|
|
||||||
T::ImplType: BinImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let bin = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = bin.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &bin.panicked(), (), {
|
|
||||||
imp.handle_message(&wrap, from_glib_full(message))
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
// Copyright (C) 2016-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.
|
|
||||||
|
|
||||||
pub use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
pub trait ReadBytesExtShort: io::Read {
|
|
||||||
fn read_u16le(&mut self) -> io::Result<u16> {
|
|
||||||
self.read_u16::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_i16le(&mut self) -> io::Result<i16> {
|
|
||||||
self.read_i16::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_u32le(&mut self) -> io::Result<u32> {
|
|
||||||
self.read_u32::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_i32le(&mut self) -> io::Result<i32> {
|
|
||||||
self.read_i32::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_u64le(&mut self) -> io::Result<u64> {
|
|
||||||
self.read_u64::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_i64le(&mut self) -> io::Result<i64> {
|
|
||||||
self.read_i64::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_uintle(&mut self, nbytes: usize) -> io::Result<u64> {
|
|
||||||
self.read_uint::<LittleEndian>(nbytes)
|
|
||||||
}
|
|
||||||
fn read_intle(&mut self, nbytes: usize) -> io::Result<i64> {
|
|
||||||
self.read_int::<LittleEndian>(nbytes)
|
|
||||||
}
|
|
||||||
fn read_f32le(&mut self) -> io::Result<f32> {
|
|
||||||
self.read_f32::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_f64le(&mut self) -> io::Result<f64> {
|
|
||||||
self.read_f64::<LittleEndian>()
|
|
||||||
}
|
|
||||||
fn read_u16be(&mut self) -> io::Result<u16> {
|
|
||||||
self.read_u16::<BigEndian>()
|
|
||||||
}
|
|
||||||
fn read_i16be(&mut self) -> io::Result<i16> {
|
|
||||||
self.read_i16::<BigEndian>()
|
|
||||||
}
|
|
||||||
fn read_u32be(&mut self) -> io::Result<u32> {
|
|
||||||
self.read_u32::<BigEndian>()
|
|
||||||
}
|
|
||||||
fn read_i32be(&mut self) -> io::Result<i32> {
|
|
||||||
self.read_i32::<BigEndian>()
|
|
||||||
}
|
|
||||||
fn read_u64be(&mut self) -> io::Result<u64> {
|
|
||||||
self.read_u64::<BigEndian>()
|
|
||||||
}
|
|
||||||
fn read_i64be(&mut self) -> io::Result<i64> {
|
|
||||||
self.read_i64::<BigEndian>()
|
|
||||||
}
|
|
||||||
fn read_uintbe(&mut self, nbytes: usize) -> io::Result<u64> {
|
|
||||||
self.read_uint::<BigEndian>(nbytes)
|
|
||||||
}
|
|
||||||
fn read_intbe(&mut self, nbytes: usize) -> io::Result<i64> {
|
|
||||||
self.read_int::<BigEndian>(nbytes)
|
|
||||||
}
|
|
||||||
fn read_f32be(&mut self) -> io::Result<f32> {
|
|
||||||
self.read_f32::<BigEndian>()
|
|
||||||
}
|
|
||||||
fn read_f64be(&mut self) -> io::Result<f64> {
|
|
||||||
self.read_f64::<BigEndian>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ReadBytesExtShort for T where T: ReadBytesExt {}
|
|
||||||
|
|
||||||
pub trait WriteBytesExtShort: WriteBytesExt {
|
|
||||||
fn write_u16le(&mut self, n: u16) -> io::Result<()> {
|
|
||||||
self.write_u16::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_i16le(&mut self, n: i16) -> io::Result<()> {
|
|
||||||
self.write_i16::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_u32le(&mut self, n: u32) -> io::Result<()> {
|
|
||||||
self.write_u32::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_i32le(&mut self, n: i32) -> io::Result<()> {
|
|
||||||
self.write_i32::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_u64le(&mut self, n: u64) -> io::Result<()> {
|
|
||||||
self.write_u64::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_i64le(&mut self, n: i64) -> io::Result<()> {
|
|
||||||
self.write_i64::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_uintle(&mut self, n: u64, nbytes: usize) -> io::Result<()> {
|
|
||||||
self.write_uint::<LittleEndian>(n, nbytes)
|
|
||||||
}
|
|
||||||
fn write_intle(&mut self, n: i64, nbytes: usize) -> io::Result<()> {
|
|
||||||
self.write_int::<LittleEndian>(n, nbytes)
|
|
||||||
}
|
|
||||||
fn write_f32le(&mut self, n: f32) -> io::Result<()> {
|
|
||||||
self.write_f32::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_f64le(&mut self, n: f64) -> io::Result<()> {
|
|
||||||
self.write_f64::<LittleEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_u16be(&mut self, n: u16) -> io::Result<()> {
|
|
||||||
self.write_u16::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_i16be(&mut self, n: i16) -> io::Result<()> {
|
|
||||||
self.write_i16::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_u32be(&mut self, n: u32) -> io::Result<()> {
|
|
||||||
self.write_u32::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_i32be(&mut self, n: i32) -> io::Result<()> {
|
|
||||||
self.write_i32::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_u64be(&mut self, n: u64) -> io::Result<()> {
|
|
||||||
self.write_u64::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_i64be(&mut self, n: i64) -> io::Result<()> {
|
|
||||||
self.write_i64::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_uintbe(&mut self, n: u64, nbytes: usize) -> io::Result<()> {
|
|
||||||
self.write_uint::<BigEndian>(n, nbytes)
|
|
||||||
}
|
|
||||||
fn write_intbe(&mut self, n: i64, nbytes: usize) -> io::Result<()> {
|
|
||||||
self.write_int::<BigEndian>(n, nbytes)
|
|
||||||
}
|
|
||||||
fn write_f32be(&mut self, n: f32) -> io::Result<()> {
|
|
||||||
self.write_f32::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
fn write_f64be(&mut self, n: f64) -> io::Result<()> {
|
|
||||||
self.write_f64::<BigEndian>(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> WriteBytesExtShort for T where T: WriteBytesExt {}
|
|
|
@ -1,194 +0,0 @@
|
||||||
// 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 glib_ffi;
|
|
||||||
use gobject_ffi;
|
|
||||||
use gst_ffi;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use glib::translate::*;
|
|
||||||
use gst;
|
|
||||||
use libc;
|
|
||||||
|
|
||||||
use gobject_subclass::anyimpl::*;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
pub trait ChildProxyImpl: AnyImpl + Send + Sync + 'static {
|
|
||||||
fn get_child_by_name(&self, object: &gst::ChildProxy, name: &str) -> Option<glib::Object> {
|
|
||||||
unsafe {
|
|
||||||
let type_ = gst_ffi::gst_child_proxy_get_type();
|
|
||||||
let iface = gobject_ffi::g_type_default_interface_ref(type_)
|
|
||||||
as *mut gst_ffi::GstChildProxyInterface;
|
|
||||||
assert!(!iface.is_null());
|
|
||||||
|
|
||||||
let ret = ((*iface).get_child_by_name.as_ref().unwrap())(
|
|
||||||
object.to_glib_none().0,
|
|
||||||
name.to_glib_none().0,
|
|
||||||
);
|
|
||||||
|
|
||||||
gobject_ffi::g_type_default_interface_unref(iface as glib_ffi::gpointer);
|
|
||||||
|
|
||||||
from_glib_full(ret)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_child_by_index(&self, object: &gst::ChildProxy, index: u32) -> Option<glib::Object>;
|
|
||||||
fn get_children_count(&self, object: &gst::ChildProxy) -> u32;
|
|
||||||
|
|
||||||
fn child_added(&self, object: &gst::ChildProxy, child: &glib::Object, name: &str);
|
|
||||||
fn child_removed(&self, object: &gst::ChildProxy, child: &glib::Object, name: &str);
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(ChildProxyImpl);
|
|
||||||
|
|
||||||
pub trait ChildProxyImplStatic<T: ObjectType>: Send + Sync + 'static {
|
|
||||||
fn get_impl<'a>(&self, imp: &'a T::ImplType) -> &'a ChildProxyImpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ChildProxyStatic<T: ObjectType> {
|
|
||||||
imp_static: *const ChildProxyImplStatic<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn child_proxy_get_child_by_name<T: ObjectType>(
|
|
||||||
child_proxy: *mut gst_ffi::GstChildProxy,
|
|
||||||
name: *const libc::c_char,
|
|
||||||
) -> *mut gobject_ffi::GObject {
|
|
||||||
floating_reference_guard!(child_proxy);
|
|
||||||
|
|
||||||
let klass = &**(child_proxy as *const *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_child_proxy_get_type())
|
|
||||||
as *const ChildProxyStatic<T>;
|
|
||||||
|
|
||||||
let instance = &*(child_proxy as *const T::InstanceStructType);
|
|
||||||
let imp = instance.get_impl();
|
|
||||||
let imp = (*(*interface_static).imp_static).get_impl(imp);
|
|
||||||
|
|
||||||
imp.get_child_by_name(
|
|
||||||
&from_glib_borrow(child_proxy),
|
|
||||||
String::from_glib_none(name).as_str(),
|
|
||||||
)
|
|
||||||
.to_glib_full()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn child_proxy_get_child_by_index<T: ObjectType>(
|
|
||||||
child_proxy: *mut gst_ffi::GstChildProxy,
|
|
||||||
index: u32,
|
|
||||||
) -> *mut gobject_ffi::GObject {
|
|
||||||
floating_reference_guard!(child_proxy);
|
|
||||||
|
|
||||||
let klass = &**(child_proxy as *const *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_child_proxy_get_type())
|
|
||||||
as *const ChildProxyStatic<T>;
|
|
||||||
|
|
||||||
let instance = &*(child_proxy as *const T::InstanceStructType);
|
|
||||||
let imp = instance.get_impl();
|
|
||||||
let imp = (*(*interface_static).imp_static).get_impl(imp);
|
|
||||||
|
|
||||||
imp.get_child_by_index(&from_glib_borrow(child_proxy), index)
|
|
||||||
.to_glib_full()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn child_proxy_get_children_count<T: ObjectType>(
|
|
||||||
child_proxy: *mut gst_ffi::GstChildProxy,
|
|
||||||
) -> u32 {
|
|
||||||
floating_reference_guard!(child_proxy);
|
|
||||||
|
|
||||||
let klass = &**(child_proxy as *const *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_child_proxy_get_type())
|
|
||||||
as *const ChildProxyStatic<T>;
|
|
||||||
|
|
||||||
let instance = &*(child_proxy as *const T::InstanceStructType);
|
|
||||||
let imp = instance.get_impl();
|
|
||||||
let imp = (*(*interface_static).imp_static).get_impl(imp);
|
|
||||||
|
|
||||||
imp.get_children_count(&from_glib_borrow(child_proxy))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn child_proxy_child_added<T: ObjectType>(
|
|
||||||
child_proxy: *mut gst_ffi::GstChildProxy,
|
|
||||||
child: *mut gobject_ffi::GObject,
|
|
||||||
name: *const libc::c_char,
|
|
||||||
) {
|
|
||||||
floating_reference_guard!(child_proxy);
|
|
||||||
|
|
||||||
let klass = &**(child_proxy as *const *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_child_proxy_get_type())
|
|
||||||
as *const ChildProxyStatic<T>;
|
|
||||||
|
|
||||||
let instance = &*(child_proxy as *const T::InstanceStructType);
|
|
||||||
let imp = instance.get_impl();
|
|
||||||
let imp = (*(*interface_static).imp_static).get_impl(imp);
|
|
||||||
|
|
||||||
imp.child_added(
|
|
||||||
&from_glib_borrow(child_proxy),
|
|
||||||
&from_glib_borrow(child),
|
|
||||||
String::from_glib_none(name).as_str(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn child_proxy_child_removed<T: ObjectType>(
|
|
||||||
child_proxy: *mut gst_ffi::GstChildProxy,
|
|
||||||
child: *mut gobject_ffi::GObject,
|
|
||||||
name: *const libc::c_char,
|
|
||||||
) {
|
|
||||||
floating_reference_guard!(child_proxy);
|
|
||||||
|
|
||||||
let klass = &**(child_proxy as *const *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_child_proxy_get_type())
|
|
||||||
as *const ChildProxyStatic<T>;
|
|
||||||
|
|
||||||
let instance = &*(child_proxy as *const T::InstanceStructType);
|
|
||||||
let imp = instance.get_impl();
|
|
||||||
let imp = (*(*interface_static).imp_static).get_impl(imp);
|
|
||||||
|
|
||||||
imp.child_removed(
|
|
||||||
&from_glib_borrow(child_proxy),
|
|
||||||
&from_glib_borrow(child),
|
|
||||||
String::from_glib_none(name).as_str(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn child_proxy_init<T: ObjectType>(
|
|
||||||
iface: glib_ffi::gpointer,
|
|
||||||
iface_data: glib_ffi::gpointer,
|
|
||||||
) {
|
|
||||||
let child_proxy_iface = &mut *(iface as *mut gst_ffi::GstChildProxyInterface);
|
|
||||||
|
|
||||||
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<T>);
|
|
||||||
let interfaces_static = &mut *(klass.interfaces_static as *mut Vec<_>);
|
|
||||||
interfaces_static.push((iface_type, iface_data));
|
|
||||||
|
|
||||||
child_proxy_iface.get_child_by_name = Some(child_proxy_get_child_by_name::<T>);
|
|
||||||
child_proxy_iface.get_child_by_index = Some(child_proxy_get_child_by_index::<T>);
|
|
||||||
child_proxy_iface.get_children_count = Some(child_proxy_get_children_count::<T>);
|
|
||||||
child_proxy_iface.child_added = Some(child_proxy_child_added::<T>);
|
|
||||||
child_proxy_iface.child_removed = Some(child_proxy_child_removed::<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_child_proxy<T: ObjectType, I: ChildProxyImplStatic<T>>(
|
|
||||||
_: &TypeInitToken,
|
|
||||||
type_: glib::Type,
|
|
||||||
imp: &I,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
let imp = imp as &ChildProxyImplStatic<T> as *const ChildProxyImplStatic<T>;
|
|
||||||
let interface_static = Box::new(ChildProxyStatic { imp_static: imp });
|
|
||||||
|
|
||||||
let iface_info = gobject_ffi::GInterfaceInfo {
|
|
||||||
interface_init: Some(child_proxy_init::<T>),
|
|
||||||
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_child_proxy_get_type(),
|
|
||||||
&iface_info,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,415 +0,0 @@
|
||||||
// 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::any::Any;
|
|
||||||
use std::mem;
|
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use libc;
|
|
||||||
|
|
||||||
use glib_ffi;
|
|
||||||
use gobject_ffi;
|
|
||||||
use gst_ffi;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use glib::translate::*;
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
|
|
||||||
use gobject_subclass::anyimpl::*;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
use object::*;
|
|
||||||
|
|
||||||
pub trait ElementImpl<T: ElementBase>: ObjectImpl<T> + AnyImpl + Send + Sync + 'static
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn change_state(&self, element: &T, transition: gst::StateChange) -> gst::StateChangeReturn {
|
|
||||||
element.parent_change_state(transition)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_new_pad(
|
|
||||||
&self,
|
|
||||||
_element: &T,
|
|
||||||
_templ: &gst::PadTemplate,
|
|
||||||
_name: Option<String>,
|
|
||||||
_caps: Option<&gst::CapsRef>,
|
|
||||||
) -> Option<gst::Pad> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release_pad(&self, _element: &T, _pad: &gst::Pad) {}
|
|
||||||
|
|
||||||
fn send_event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
element.parent_send_event(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
|
|
||||||
element.parent_query(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_context(&self, element: &T, context: &gst::Context) {
|
|
||||||
element.parent_set_context(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ElementImplExt<T> {
|
|
||||||
fn catch_panic_pad_function<R, F: FnOnce(&Self, &T) -> R, G: FnOnce() -> R>(
|
|
||||||
parent: &Option<gst::Object>,
|
|
||||||
fallback: G,
|
|
||||||
f: F,
|
|
||||||
) -> R;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: ElementImpl<T>, T: ObjectType + glib::IsA<gst::Element> + glib::IsA<gst::Object>>
|
|
||||||
ElementImplExt<T> for S
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn catch_panic_pad_function<R, F: FnOnce(&Self, &T) -> R, G: FnOnce() -> R>(
|
|
||||||
parent: &Option<gst::Object>,
|
|
||||||
fallback: G,
|
|
||||||
f: F,
|
|
||||||
) -> R {
|
|
||||||
// FIXME: Does this work for element subclasses?
|
|
||||||
let element = parent.as_ref().unwrap().downcast_ref::<T>().unwrap();
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let imp = Any::downcast_ref::<Box<ElementImpl<T> + 'static>>(imp).unwrap();
|
|
||||||
let imp = imp.downcast_ref::<S>().unwrap();
|
|
||||||
element.catch_panic(fallback, |element| f(imp, element))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(ElementBase, ElementImpl, PanicPoison);
|
|
||||||
|
|
||||||
pub unsafe trait ElementBase: IsA<gst::Element> + ObjectType
|
|
||||||
where
|
|
||||||
Self::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn parent_change_state(&self, transition: gst::StateChange) -> gst::StateChangeReturn {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.change_state
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, transition.to_glib())))
|
|
||||||
.unwrap_or(gst::StateChangeReturn::Success)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_send_event(&self, event: gst::Event) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.send_event
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, event.into_ptr())))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.query
|
|
||||||
.map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_set_context(&self, context: &gst::Context) {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstElementClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.set_context
|
|
||||||
.map(|f| f(self.to_glib_none().0, context.to_glib_none().0))
|
|
||||||
.unwrap_or(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn catch_panic<T, F: FnOnce(&Self) -> T, G: FnOnce() -> T>(&self, fallback: G, f: F) -> T {
|
|
||||||
let panicked = unsafe { &(*self.get_instance()).panicked() };
|
|
||||||
panic_to_error!(self, panicked, fallback(), { f(self) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait ElementClassExt<T: ElementBase>
|
|
||||||
where
|
|
||||||
T::ImplType: ElementImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn add_pad_template(&mut self, pad_template: gst::PadTemplate) {
|
|
||||||
unsafe {
|
|
||||||
gst_ffi::gst_element_class_add_pad_template(
|
|
||||||
self as *const Self as *mut gst_ffi::GstElementClass,
|
|
||||||
pad_template.to_glib_none().0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_metadata(
|
|
||||||
&mut self,
|
|
||||||
long_name: &str,
|
|
||||||
classification: &str,
|
|
||||||
description: &str,
|
|
||||||
author: &str,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
gst_ffi::gst_element_class_set_metadata(
|
|
||||||
self as *const Self as *mut gst_ffi::GstElementClass,
|
|
||||||
long_name.to_glib_none().0,
|
|
||||||
classification.to_glib_none().0,
|
|
||||||
description.to_glib_none().0,
|
|
||||||
author.to_glib_none().0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
|
||||||
unsafe {
|
|
||||||
let klass = &mut *(self as *const Self as *mut gst_ffi::GstElementClass);
|
|
||||||
klass.change_state = Some(element_change_state::<T>);
|
|
||||||
klass.request_new_pad = Some(element_request_new_pad::<T>);
|
|
||||||
klass.release_pad = Some(element_release_pad::<T>);
|
|
||||||
klass.send_event = Some(element_send_event::<T>);
|
|
||||||
klass.query = Some(element_query::<T>);
|
|
||||||
klass.set_context = Some(element_set_context::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct Element(Object<ElementInstanceStruct<Element>>):
|
|
||||||
[gst::Element => gst_ffi::GstElement,
|
|
||||||
gst::Object => gst_ffi::GstObject];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<Element>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Element> + ObjectType> ElementBase for T where
|
|
||||||
Self::InstanceStructType: PanicPoison
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type ElementClass = ClassStruct<Element>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl ElementClassExt<Element> for ElementClass {}
|
|
||||||
unsafe impl ObjectClassExt<Element> for ElementClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for Element {}
|
|
||||||
unsafe impl Sync for Element {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_element_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_object_impl!($name, PanicPoison);
|
|
||||||
|
|
||||||
impl<T: ElementBase> ElementImpl<T> for Box<$name<T>>
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison
|
|
||||||
{
|
|
||||||
fn change_state(
|
|
||||||
&self,
|
|
||||||
element: &T,
|
|
||||||
transition: gst::StateChange,
|
|
||||||
) -> gst::StateChangeReturn {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.change_state(element, transition)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_new_pad(&self, element: &T, templ: &gst::PadTemplate, name: Option<String>, caps: Option<&gst::CapsRef>) -> Option<gst::Pad> {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.request_new_pad(element, templ, name, caps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release_pad(&self, element: &T, pad: &gst::Pad) {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.release_pad(element, pad)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_event(&self, element: &T, event: gst::Event) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.send_event(element, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
ElementImpl::query(imp, element, query)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_context(&self, element: &T, context: &gst::Context) {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.set_context(element, context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
box_element_impl!(ElementImpl);
|
|
||||||
|
|
||||||
impl ObjectType for Element {
|
|
||||||
const NAME: &'static str = "RsElement";
|
|
||||||
type ParentType = gst::Element;
|
|
||||||
type ImplType = Box<ElementImpl<Self>>;
|
|
||||||
type InstanceStructType = ElementInstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut ElementClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
ElementClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_change_state<T: ElementBase>(
|
|
||||||
ptr: *mut gst_ffi::GstElement,
|
|
||||||
transition: gst_ffi::GstStateChange,
|
|
||||||
) -> gst_ffi::GstStateChangeReturn
|
|
||||||
where
|
|
||||||
T::ImplType: ElementImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
// *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 {
|
|
||||||
gst::StateChange::PlayingToPaused
|
|
||||||
| gst::StateChange::PausedToReady
|
|
||||||
| gst::StateChange::ReadyToNull => gst::StateChangeReturn::Success,
|
|
||||||
_ => gst::StateChangeReturn::Failure,
|
|
||||||
};
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), fallback, {
|
|
||||||
imp.change_state(&wrap, transition)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_request_new_pad<T: ElementBase>(
|
|
||||||
ptr: *mut gst_ffi::GstElement,
|
|
||||||
templ: *mut gst_ffi::GstPadTemplate,
|
|
||||||
name: *const libc::c_char,
|
|
||||||
caps: *const gst_ffi::GstCaps,
|
|
||||||
) -> *mut gst_ffi::GstPad
|
|
||||||
where
|
|
||||||
T::ImplType: ElementImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let caps = if caps.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(gst::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 = panic_to_error!(&wrap, &element.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(gst::Object::from_glib_borrow(
|
|
||||||
ptr as *mut gst_ffi::GstObject
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pad.to_glib_none().0
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_release_pad<T: ElementBase>(
|
|
||||||
ptr: *mut gst_ffi::GstElement,
|
|
||||||
pad: *mut gst_ffi::GstPad,
|
|
||||||
) where
|
|
||||||
T::ImplType: ElementImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), (), {
|
|
||||||
imp.release_pad(&wrap, &from_glib_borrow(pad))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_send_event<T: ElementBase>(
|
|
||||||
ptr: *mut gst_ffi::GstElement,
|
|
||||||
event: *mut gst_ffi::GstEvent,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: ElementImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.send_event(&wrap, from_glib_full(event))
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_query<T: ElementBase>(
|
|
||||||
ptr: *mut gst_ffi::GstElement,
|
|
||||||
query: *mut gst_ffi::GstQuery,
|
|
||||||
) -> glib_ffi::gboolean
|
|
||||||
where
|
|
||||||
T::ImplType: ElementImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
let query = gst::QueryRef::from_mut_ptr(query);
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), false, {
|
|
||||||
imp.query(&wrap, query)
|
|
||||||
})
|
|
||||||
.to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn element_set_context<T: ElementBase>(
|
|
||||||
ptr: *mut gst_ffi::GstElement,
|
|
||||||
context: *mut gst_ffi::GstContext,
|
|
||||||
) where
|
|
||||||
T::ImplType: ElementImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let element = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = element.get_impl();
|
|
||||||
|
|
||||||
panic_to_error!(&wrap, &element.panicked(), (), {
|
|
||||||
imp.set_context(&wrap, &from_glib_borrow(context))
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
// Copyright (C) 2016-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::error::Error;
|
|
||||||
use std::fmt::Error as FmtError;
|
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
|
|
||||||
use gst;
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! panic_to_error(
|
|
||||||
($element:expr, $panicked:expr, $ret:expr, $code:block) => {{
|
|
||||||
use std::panic::{self, AssertUnwindSafe};
|
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
if $panicked.load(Ordering::Relaxed) {
|
|
||||||
$element.post_error_message(&gst_error_msg!(gst::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!(gst::LibraryError::Failed, ["Panicked: {}", cause]));
|
|
||||||
} else if let Some(cause) = err.downcast_ref::<String>() {
|
|
||||||
$element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked: {}", cause]));
|
|
||||||
} else {
|
|
||||||
$element.post_error_message(&gst_error_msg!(gst::LibraryError::Failed, ["Panicked"]));
|
|
||||||
}
|
|
||||||
$ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub enum FlowError {
|
|
||||||
Flushing,
|
|
||||||
Eos,
|
|
||||||
NotNegotiated(gst::ErrorMessage),
|
|
||||||
Error(gst::ErrorMessage),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FlowError> for gst::FlowReturn {
|
|
||||||
fn from(err: FlowError) -> Self {
|
|
||||||
gst::FlowReturn::from(&err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a FlowError> for gst::FlowReturn {
|
|
||||||
fn from(err: &FlowError) -> gst::FlowReturn {
|
|
||||||
match *err {
|
|
||||||
FlowError::Flushing => gst::FlowReturn::Flushing,
|
|
||||||
FlowError::Eos => gst::FlowReturn::Eos,
|
|
||||||
FlowError::NotNegotiated(..) => gst::FlowReturn::NotNegotiated,
|
|
||||||
FlowError::Error(..) => gst::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",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
// 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 glib;
|
|
||||||
use glib::translate::*;
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
|
|
||||||
use gobject_subclass::anyimpl::*;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
use pad::*;
|
|
||||||
|
|
||||||
pub trait GhostPadImpl<T: GhostPadBase>:
|
|
||||||
AnyImpl + ObjectImpl<T> + PadImpl<T> + Send + Sync + 'static
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(GhostPadBase, GhostPadImpl);
|
|
||||||
|
|
||||||
pub unsafe trait GhostPadBase: IsA<gst::GhostPad> + IsA<gst::Pad> + ObjectType {}
|
|
||||||
|
|
||||||
pub unsafe trait GhostPadClassExt<T: GhostPadBase>
|
|
||||||
where
|
|
||||||
T::ImplType: GhostPadImpl<T>,
|
|
||||||
{
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct GhostPad(Object<InstanceStruct<GhostPad>>):
|
|
||||||
[gst::GhostPad => gst_ffi::GstGhostPad,
|
|
||||||
gst::ProxyPad => gst_ffi::GstProxyPad,
|
|
||||||
gst::Pad => gst_ffi::GstPad,
|
|
||||||
gst::Object => gst_ffi::GstObject];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<GhostPad>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::GhostPad> + IsA<gst::Pad> + ObjectType> GhostPadBase for T {}
|
|
||||||
pub type GhostPadClass = ClassStruct<GhostPad>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl GhostPadClassExt<GhostPad> for GhostPadClass {}
|
|
||||||
unsafe impl PadClassExt<GhostPad> for GhostPadClass {}
|
|
||||||
unsafe impl ObjectClassExt<GhostPad> for GhostPadClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for GhostPad {}
|
|
||||||
unsafe impl Sync for GhostPad {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_ghost_pad_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_pad_impl!($name);
|
|
||||||
|
|
||||||
impl<T: GhostPadBase> GhostPadImpl<T> for Box<$name<T>>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
box_ghost_pad_impl!(GhostPadImpl);
|
|
||||||
|
|
||||||
impl ObjectType for GhostPad {
|
|
||||||
const NAME: &'static str = "RsGhostPad";
|
|
||||||
type ParentType = gst::GhostPad;
|
|
||||||
type ImplType = Box<GhostPadImpl<Self>>;
|
|
||||||
type InstanceStructType = InstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut GhostPadClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
PadClassExt::override_vfuncs(klass, token);
|
|
||||||
GhostPadClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
// Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com>
|
|
||||||
// 2016 Luis de Bethencourt <luisbg@osg.samsung.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.
|
|
||||||
#![cfg_attr(feature = "cargo-clippy", allow(cast_ptr_alignment))]
|
|
||||||
|
|
||||||
extern crate byteorder;
|
|
||||||
|
|
||||||
pub extern crate glib_sys as glib_ffi;
|
|
||||||
pub extern crate gobject_sys as gobject_ffi;
|
|
||||||
extern crate gstreamer_base_sys as gst_base_ffi;
|
|
||||||
pub extern crate gstreamer_sys as gst_ffi;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
pub extern crate glib;
|
|
||||||
#[macro_use]
|
|
||||||
pub extern crate gstreamer as gst;
|
|
||||||
extern crate gstreamer_base as gst_base;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate gobject_subclass;
|
|
||||||
|
|
||||||
pub mod object;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
pub mod error;
|
|
||||||
pub mod adapter;
|
|
||||||
#[macro_use]
|
|
||||||
pub mod plugin;
|
|
||||||
pub mod bytes;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
pub mod element;
|
|
||||||
#[macro_use]
|
|
||||||
pub mod bin;
|
|
||||||
#[macro_use]
|
|
||||||
pub mod pipeline;
|
|
||||||
#[macro_use]
|
|
||||||
pub mod base_src;
|
|
||||||
#[macro_use]
|
|
||||||
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;
|
|
|
@ -1,41 +0,0 @@
|
||||||
use std::ptr;
|
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
|
|
||||||
use glib::wrapper::Wrapper;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct ElementInstanceStruct<T: ObjectType> {
|
|
||||||
_parent: <T::ParentType as Wrapper>::GlibType,
|
|
||||||
_imp: ptr::NonNull<T::ImplType>,
|
|
||||||
|
|
||||||
_panicked: AtomicBool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PanicPoison {
|
|
||||||
fn panicked(&self) -> &AtomicBool;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: ObjectType> Instance<T> for ElementInstanceStruct<T> {
|
|
||||||
fn parent(&self) -> &<T::ParentType as Wrapper>::GlibType {
|
|
||||||
&self._parent
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_impl(&self) -> &T::ImplType {
|
|
||||||
unsafe { self._imp.as_ref() }
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn set_impl(&mut self, imp: ptr::NonNull<T::ImplType>) {
|
|
||||||
self._imp = imp;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_class(&self) -> *const ClassStruct<T> {
|
|
||||||
*(self as *const _ as *const *const ClassStruct<T>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ObjectType> PanicPoison for ElementInstanceStruct<T> {
|
|
||||||
fn panicked(&self) -> &AtomicBool {
|
|
||||||
&self._panicked
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
// 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 glib;
|
|
||||||
use glib::translate::*;
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
|
|
||||||
use gobject_subclass::anyimpl::*;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
pub trait PadImpl<T: PadBase>: AnyImpl + ObjectImpl<T> + Send + Sync + 'static {
|
|
||||||
fn linked(&self, pad: &T, peer: &gst::Pad) {
|
|
||||||
pad.parent_linked(peer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlinked(&self, pad: &T, peer: &gst::Pad) {
|
|
||||||
pad.parent_unlinked(peer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(PadBase, PadImpl);
|
|
||||||
|
|
||||||
pub unsafe trait PadBase: IsA<gst::Pad> + ObjectType {
|
|
||||||
fn parent_linked(&self, peer: &gst::Pad) {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstPadClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.linked
|
|
||||||
.map(|f| f(self.to_glib_none().0, peer.to_glib_none().0))
|
|
||||||
.unwrap_or(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_unlinked(&self, peer: &gst::Pad) {
|
|
||||||
unsafe {
|
|
||||||
let klass = self.get_class();
|
|
||||||
let parent_klass = (*klass).get_parent_class() as *const gst_ffi::GstPadClass;
|
|
||||||
(*parent_klass)
|
|
||||||
.unlinked
|
|
||||||
.map(|f| f(self.to_glib_none().0, peer.to_glib_none().0))
|
|
||||||
.unwrap_or(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait PadClassExt<T: PadBase>
|
|
||||||
where
|
|
||||||
T::ImplType: PadImpl<T>,
|
|
||||||
{
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {
|
|
||||||
unsafe {
|
|
||||||
let klass = &mut *(self as *const Self as *mut gst_ffi::GstPadClass);
|
|
||||||
klass.linked = Some(pad_linked::<T>);
|
|
||||||
klass.unlinked = Some(pad_unlinked::<T>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct Pad(Object<InstanceStruct<Pad>>):
|
|
||||||
[gst::Pad => gst_ffi::GstPad,
|
|
||||||
gst::Object => gst_ffi::GstObject];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<Pad>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Pad> + ObjectType> PadBase for T {}
|
|
||||||
pub type PadClass = ClassStruct<Pad>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl PadClassExt<Pad> for PadClass {}
|
|
||||||
unsafe impl ObjectClassExt<Pad> for PadClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for Pad {}
|
|
||||||
unsafe impl Sync for Pad {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_pad_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_object_impl!($name);
|
|
||||||
|
|
||||||
impl<T: PadBase> PadImpl<T> for Box<$name<T>>
|
|
||||||
{
|
|
||||||
fn linked(&self, pad: &T, peer: &gst::Pad) {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.linked(pad, peer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlinked(&self, pad: &T, peer: &gst::Pad) {
|
|
||||||
let imp: &$name<T> = self.as_ref();
|
|
||||||
imp.unlinked(pad, peer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
box_pad_impl!(PadImpl);
|
|
||||||
|
|
||||||
impl ObjectType for Pad {
|
|
||||||
const NAME: &'static str = "RsPad";
|
|
||||||
type ParentType = gst::Pad;
|
|
||||||
type ImplType = Box<PadImpl<Self>>;
|
|
||||||
type InstanceStructType = InstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut PadClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
PadClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn pad_linked<T: PadBase>(ptr: *mut gst_ffi::GstPad, peer: *mut gst_ffi::GstPad)
|
|
||||||
where
|
|
||||||
T::ImplType: PadImpl<T>,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let pad = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = pad.get_impl();
|
|
||||||
|
|
||||||
imp.linked(&wrap, &from_glib_borrow(peer))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn pad_unlinked<T: PadBase>(ptr: *mut gst_ffi::GstPad, peer: *mut gst_ffi::GstPad)
|
|
||||||
where
|
|
||||||
T::ImplType: PadImpl<T>,
|
|
||||||
{
|
|
||||||
floating_reference_guard!(ptr);
|
|
||||||
let pad = &*(ptr as *mut T::InstanceStructType);
|
|
||||||
let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType);
|
|
||||||
let imp = pad.get_impl();
|
|
||||||
|
|
||||||
imp.unlinked(&wrap, &from_glib_borrow(peer))
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
// 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 glib_ffi;
|
|
||||||
use gobject_ffi;
|
|
||||||
use gst_ffi;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use glib::translate::*;
|
|
||||||
use gst;
|
|
||||||
use gst::prelude::*;
|
|
||||||
|
|
||||||
use gobject_subclass::anyimpl::*;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
use bin::*;
|
|
||||||
use element::*;
|
|
||||||
use object::*;
|
|
||||||
|
|
||||||
pub trait PipelineImpl<T: PipelineBase>:
|
|
||||||
AnyImpl + ObjectImpl<T> + ElementImpl<T> + BinImpl<T> + Send + Sync + 'static
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(PipelineBase, PipelineImpl, PanicPoison);
|
|
||||||
|
|
||||||
pub unsafe trait PipelineBase:
|
|
||||||
IsA<gst::Element> + IsA<gst::Bin> + IsA<gst::Pipeline> + ObjectType
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe trait PipelineClassExt<T: PipelineBase>
|
|
||||||
where
|
|
||||||
T::ImplType: PipelineImpl<T>,
|
|
||||||
T::InstanceStructType: PanicPoison,
|
|
||||||
{
|
|
||||||
fn override_vfuncs(&mut self, _: &ClassInitToken) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib_wrapper! {
|
|
||||||
pub struct Pipeline(Object<ElementInstanceStruct<Pipeline>>):
|
|
||||||
[gst::Pipeline => gst_ffi::GstPipeline,
|
|
||||||
gst::Bin => gst_ffi::GstBin,
|
|
||||||
gst::Element => gst_ffi::GstElement,
|
|
||||||
gst::Object => gst_ffi::GstObject,
|
|
||||||
gst::ChildProxy => gst_ffi::GstChildProxy];
|
|
||||||
|
|
||||||
match fn {
|
|
||||||
get_type => || get_type::<Pipeline>(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: IsA<gst::Element> + IsA<gst::Bin> + IsA<gst::Pipeline> + ObjectType> PipelineBase
|
|
||||||
for T
|
|
||||||
{
|
|
||||||
}
|
|
||||||
pub type PipelineClass = ClassStruct<Pipeline>;
|
|
||||||
|
|
||||||
// FIXME: Boilerplate
|
|
||||||
unsafe impl PipelineClassExt<Pipeline> for PipelineClass {}
|
|
||||||
unsafe impl BinClassExt<Pipeline> for PipelineClass {}
|
|
||||||
unsafe impl ElementClassExt<Pipeline> for PipelineClass {}
|
|
||||||
unsafe impl ObjectClassExt<Pipeline> for PipelineClass {}
|
|
||||||
|
|
||||||
unsafe impl Send for Pipeline {}
|
|
||||||
unsafe impl Sync for Pipeline {}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! box_pipeline_impl(
|
|
||||||
($name:ident) => {
|
|
||||||
box_bin_impl!($name);
|
|
||||||
|
|
||||||
impl<T: PipelineBase> PipelineImpl<T> for Box<$name<T>>
|
|
||||||
where
|
|
||||||
T::InstanceStructType: PanicPoison
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
box_pipeline_impl!(PipelineImpl);
|
|
||||||
|
|
||||||
impl ObjectType for Pipeline {
|
|
||||||
const NAME: &'static str = "RsPipeline";
|
|
||||||
type ParentType = gst::Pipeline;
|
|
||||||
type ImplType = Box<PipelineImpl<Self>>;
|
|
||||||
type InstanceStructType = ElementInstanceStruct<Self>;
|
|
||||||
|
|
||||||
fn class_init(token: &ClassInitToken, klass: &mut PipelineClass) {
|
|
||||||
ObjectClassExt::override_vfuncs(klass, token);
|
|
||||||
ElementClassExt::override_vfuncs(klass, token);
|
|
||||||
BinClassExt::override_vfuncs(klass, token);
|
|
||||||
PipelineClassExt::override_vfuncs(klass, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_type_fns!();
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
// Copyright (C) 2016-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.
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! 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::gst_ffi::GstPluginDesc);
|
|
||||||
unsafe impl Sync for GstPluginDesc {}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub static gst_plugin_desc: GstPluginDesc = GstPluginDesc($crate::gst_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::gst_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::gst_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::gst::DebugCategory::get("GST_PLUGIN_LOADING").unwrap();
|
|
||||||
gst_error!(cat, "Failed to register plugin: {}", err);
|
|
||||||
$crate::glib_ffi::GFALSE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let cat = $crate::gst::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::<String>() {
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
);
|
|
|
@ -1,148 +0,0 @@
|
||||||
// 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 glib_ffi;
|
|
||||||
use gobject_ffi;
|
|
||||||
use gst_ffi;
|
|
||||||
|
|
||||||
use glib;
|
|
||||||
use glib::translate::*;
|
|
||||||
use gst;
|
|
||||||
use libc;
|
|
||||||
|
|
||||||
use gobject_subclass::anyimpl::*;
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
|
|
||||||
pub trait URIHandlerImpl: AnyImpl + Send + Sync + 'static {
|
|
||||||
fn get_uri(&self, element: &gst::URIHandler) -> Option<String>;
|
|
||||||
fn set_uri(&self, element: &gst::URIHandler, uri: Option<String>) -> Result<(), glib::Error>;
|
|
||||||
}
|
|
||||||
|
|
||||||
any_impl!(URIHandlerImpl);
|
|
||||||
|
|
||||||
pub trait URIHandlerImplStatic<T: ObjectType>: Send + Sync + 'static {
|
|
||||||
fn get_impl<'a>(&self, imp: &'a T::ImplType) -> &'a URIHandlerImpl;
|
|
||||||
fn get_type(&self) -> gst::URIType;
|
|
||||||
fn get_protocols(&self) -> Vec<String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct URIHandlerStatic<T: ObjectType> {
|
|
||||||
imp_static: *const URIHandlerImplStatic<T>,
|
|
||||||
protocols: *const Vec<*const libc::c_char>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn uri_handler_get_type<T: ObjectType>(
|
|
||||||
type_: glib_ffi::GType,
|
|
||||||
) -> gst_ffi::GstURIType {
|
|
||||||
let klass = gobject_ffi::g_type_class_peek(type_);
|
|
||||||
let klass = &*(klass as *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type())
|
|
||||||
as *const URIHandlerStatic<T>;
|
|
||||||
(*(*interface_static).imp_static).get_type().to_glib()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn uri_handler_get_protocols<T: ObjectType>(
|
|
||||||
type_: glib_ffi::GType,
|
|
||||||
) -> *const *const libc::c_char {
|
|
||||||
let klass = gobject_ffi::g_type_class_peek(type_);
|
|
||||||
let klass = &*(klass as *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type())
|
|
||||||
as *const URIHandlerStatic<T>;
|
|
||||||
(*(*interface_static).protocols).as_ptr()
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn uri_handler_get_uri<T: ObjectType>(
|
|
||||||
uri_handler: *mut gst_ffi::GstURIHandler,
|
|
||||||
) -> *mut libc::c_char {
|
|
||||||
floating_reference_guard!(uri_handler);
|
|
||||||
|
|
||||||
let klass = &**(uri_handler as *const *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type())
|
|
||||||
as *const URIHandlerStatic<T>;
|
|
||||||
|
|
||||||
let instance = &*(uri_handler as *const T::InstanceStructType);
|
|
||||||
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<T: ObjectType>(
|
|
||||||
uri_handler: *mut gst_ffi::GstURIHandler,
|
|
||||||
uri: *const libc::c_char,
|
|
||||||
err: *mut *mut glib_ffi::GError,
|
|
||||||
) -> glib_ffi::gboolean {
|
|
||||||
floating_reference_guard!(uri_handler);
|
|
||||||
|
|
||||||
let klass = &**(uri_handler as *const *const ClassStruct<T>);
|
|
||||||
let interface_static = klass.get_interface_static(gst_ffi::gst_uri_handler_get_type())
|
|
||||||
as *const URIHandlerStatic<T>;
|
|
||||||
|
|
||||||
let instance = &*(uri_handler as *const T::InstanceStructType);
|
|
||||||
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<T: ObjectType>(
|
|
||||||
iface: glib_ffi::gpointer,
|
|
||||||
iface_data: glib_ffi::gpointer,
|
|
||||||
) {
|
|
||||||
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<T>);
|
|
||||||
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::<T>);
|
|
||||||
uri_handler_iface.get_protocols = Some(uri_handler_get_protocols::<T>);
|
|
||||||
uri_handler_iface.get_uri = Some(uri_handler_get_uri::<T>);
|
|
||||||
uri_handler_iface.set_uri = Some(uri_handler_set_uri::<T>);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_uri_handler<T: ObjectType, I: URIHandlerImplStatic<T>>(
|
|
||||||
_: &TypeInitToken,
|
|
||||||
type_: glib::Type,
|
|
||||||
imp: &I,
|
|
||||||
) {
|
|
||||||
unsafe {
|
|
||||||
let mut protocols: Vec<_> = imp
|
|
||||||
.get_protocols()
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.to_glib_full())
|
|
||||||
.collect();
|
|
||||||
protocols.push(ptr::null());
|
|
||||||
|
|
||||||
let imp = imp as &URIHandlerImplStatic<T> as *const URIHandlerImplStatic<T>;
|
|
||||||
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::<T>),
|
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue