mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-01-11 03:35:26 +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]
|
||||
|
||||
members = [
|
||||
"gst-plugin",
|
||||
"gst-plugin-simple",
|
||||
"gst-plugin-file",
|
||||
"gst-plugin-http",
|
||||
"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