mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-11-23 12:01:01 +00:00
Port threadshare plugin to new subclassing API
This commit is contained in:
parent
4d87c11293
commit
e64a9b4a1a
7 changed files with 1088 additions and 990 deletions
|
@ -12,10 +12,8 @@ gio-sys = { git = "https://github.com/gtk-rs/sys" }
|
||||||
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
|
gstreamer-sys = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys" }
|
||||||
glib = { git = "https://github.com/gtk-rs/glib", features = ["subclassing"] }
|
glib = { git = "https://github.com/gtk-rs/glib", features = ["subclassing"] }
|
||||||
gio = { git = "https://github.com/gtk-rs/gio" }
|
gio = { git = "https://github.com/gtk-rs/gio" }
|
||||||
gstreamer = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
gstreamer = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["subclassing"] }
|
||||||
gstreamer-check = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
gstreamer-check = { git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
|
||||||
gobject-subclass = { git = "https://github.com/gtk-rs/gobject-subclass" }
|
|
||||||
gst-plugin = { path = "../gst-plugin" }
|
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
tokio-reactor = "0.1"
|
tokio-reactor = "0.1"
|
||||||
tokio-executor = "0.1"
|
tokio-executor = "0.1"
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
use glib;
|
use glib;
|
||||||
use glib::prelude::*;
|
use glib::prelude::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use glib::subclass::prelude::*;
|
||||||
use gst;
|
use gst;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
use gst::subclass::prelude::*;
|
||||||
use gobject_subclass::object::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::u32;
|
use std::u32;
|
||||||
|
@ -63,44 +63,56 @@ impl Default for Settings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PROPERTIES: [Property; 5] = [
|
static PROPERTIES: [subclass::Property; 5] = [
|
||||||
Property::String(
|
subclass::Property("context", || {
|
||||||
"context",
|
glib::ParamSpec::string(
|
||||||
"Context",
|
"context",
|
||||||
"Context name to share threads with",
|
"Context",
|
||||||
Some(DEFAULT_CONTEXT),
|
"Context name to share threads with",
|
||||||
PropertyMutability::ReadWrite,
|
Some(DEFAULT_CONTEXT),
|
||||||
),
|
glib::ParamFlags::READWRITE,
|
||||||
Property::UInt(
|
)
|
||||||
"context-wait",
|
}),
|
||||||
"Context Wait",
|
subclass::Property("context-wait", || {
|
||||||
"Throttle poll loop to run at most once every this many ms",
|
glib::ParamSpec::uint(
|
||||||
(0, 1000),
|
"context-wait",
|
||||||
DEFAULT_CONTEXT_WAIT,
|
"Context Wait",
|
||||||
PropertyMutability::ReadWrite,
|
"Throttle poll loop to run at most once every this many ms",
|
||||||
),
|
0,
|
||||||
Property::UInt(
|
1000,
|
||||||
"max-buffers",
|
DEFAULT_CONTEXT_WAIT,
|
||||||
"Max Buffers",
|
glib::ParamFlags::READWRITE,
|
||||||
"Maximum number of buffers to queue up",
|
)
|
||||||
(1, u32::MAX),
|
}),
|
||||||
DEFAULT_MAX_BUFFERS,
|
subclass::Property("max-buffers", || {
|
||||||
PropertyMutability::ReadWrite,
|
glib::ParamSpec::uint(
|
||||||
),
|
"max-buffers",
|
||||||
Property::Boxed(
|
"Max Buffers",
|
||||||
"caps",
|
"Maximum number of buffers to queue up",
|
||||||
"Caps",
|
1,
|
||||||
"Caps to use",
|
u32::MAX,
|
||||||
gst::Caps::static_type,
|
DEFAULT_MAX_BUFFERS,
|
||||||
PropertyMutability::ReadWrite,
|
glib::ParamFlags::READWRITE,
|
||||||
),
|
)
|
||||||
Property::Boolean(
|
}),
|
||||||
"do-timestamp",
|
subclass::Property("caps", || {
|
||||||
"Do Timestamp",
|
glib::ParamSpec::boxed(
|
||||||
"Timestamp buffers with the current running time on arrival",
|
"caps",
|
||||||
DEFAULT_DO_TIMESTAMP,
|
"Caps",
|
||||||
PropertyMutability::ReadWrite,
|
"Caps to use",
|
||||||
),
|
gst::Caps::static_type(),
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
subclass::Property("do-timestamp", || {
|
||||||
|
glib::ParamSpec::boolean(
|
||||||
|
"do-timestamp",
|
||||||
|
"Do Timestamp",
|
||||||
|
"Timestamp buffers with the current running time on arrival",
|
||||||
|
DEFAULT_DO_TIMESTAMP,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
|
@ -133,88 +145,6 @@ struct AppSrc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppSrc {
|
impl AppSrc {
|
||||||
fn class_init(klass: &mut ElementClass) {
|
|
||||||
klass.set_metadata(
|
|
||||||
"Thread-sharing app source",
|
|
||||||
"Source/Generic",
|
|
||||||
"Thread-sharing app source",
|
|
||||||
"Sebastian Dröge <sebastian@centricular.com>",
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
|
|
||||||
let src_pad_template = gst::PadTemplate::new(
|
|
||||||
"src",
|
|
||||||
gst::PadDirection::Src,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(src_pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES);
|
|
||||||
|
|
||||||
klass.add_action_signal(
|
|
||||||
"push-buffer",
|
|
||||||
&[gst::Buffer::static_type()],
|
|
||||||
bool::static_type(),
|
|
||||||
|args| {
|
|
||||||
let element = args[0]
|
|
||||||
.get::<gst::Element>()
|
|
||||||
.unwrap()
|
|
||||||
.downcast::<Element>()
|
|
||||||
.unwrap();
|
|
||||||
let buffer = args[1].get::<gst::Buffer>().unwrap();
|
|
||||||
let appsrc = element.get_impl().downcast_ref::<AppSrc>().unwrap();
|
|
||||||
|
|
||||||
Some(appsrc.push_buffer(&element, buffer).to_value())
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
klass.add_action_signal("end-of-stream", &[], bool::static_type(), |args| {
|
|
||||||
let element = args[0]
|
|
||||||
.get::<gst::Element>()
|
|
||||||
.unwrap()
|
|
||||||
.downcast::<Element>()
|
|
||||||
.unwrap();
|
|
||||||
let appsrc = element.get_impl().downcast_ref::<AppSrc>().unwrap();
|
|
||||||
Some(appsrc.end_of_stream(&element).to_value())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
let templ = element.get_pad_template("src").unwrap();
|
|
||||||
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
|
||||||
|
|
||||||
src_pad.set_event_function(|pad, parent, event| {
|
|
||||||
AppSrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.src_event(pad, element, event),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
src_pad.set_query_function(|pad, parent, query| {
|
|
||||||
AppSrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.src_query(pad, element, query),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
element.add_pad(&src_pad).unwrap();
|
|
||||||
|
|
||||||
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
|
||||||
|
|
||||||
Box::new(Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"ts-appsrc",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Thread-sharing app source",
|
|
||||||
),
|
|
||||||
src_pad: src_pad,
|
|
||||||
state: Mutex::new(State::default()),
|
|
||||||
settings: Mutex::new(Settings::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_io_context_event(state: &State) -> Option<gst::Event> {
|
fn create_io_context_event(state: &State) -> Option<gst::Event> {
|
||||||
if let (&Some(ref pending_future_id), &Some(ref io_context)) =
|
if let (&Some(ref pending_future_id), &Some(ref io_context)) =
|
||||||
(&state.pending_future_id, &state.io_context)
|
(&state.pending_future_id, &state.io_context)
|
||||||
|
@ -232,7 +162,7 @@ impl AppSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_event(&self, pad: &gst::Pad, element: &Element, event: gst::Event) -> bool {
|
fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool {
|
||||||
use gst::EventView;
|
use gst::EventView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
||||||
|
@ -265,7 +195,12 @@ impl AppSrc {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_query(&self, pad: &gst::Pad, _element: &Element, query: &mut gst::QueryRef) -> bool {
|
fn src_query(
|
||||||
|
&self,
|
||||||
|
pad: &gst::Pad,
|
||||||
|
_element: &gst::Element,
|
||||||
|
query: &mut gst::QueryRef,
|
||||||
|
) -> bool {
|
||||||
use gst::QueryView;
|
use gst::QueryView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
||||||
|
@ -306,7 +241,7 @@ impl AppSrc {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_buffer(&self, element: &Element, mut buffer: gst::Buffer) -> bool {
|
fn push_buffer(&self, element: &gst::Element, mut buffer: gst::Buffer) -> bool {
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
let settings = self.settings.lock().unwrap().clone();
|
||||||
|
|
||||||
if settings.do_timestamp {
|
if settings.do_timestamp {
|
||||||
|
@ -337,7 +272,7 @@ impl AppSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_of_stream(&self, element: &Element) -> bool {
|
fn end_of_stream(&self, element: &gst::Element) -> bool {
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
if let Some(ref mut channel) = state.channel {
|
if let Some(ref mut channel) = state.channel {
|
||||||
match channel.try_send(Either::Right(gst::Event::new_eos().build())) {
|
match channel.try_send(Either::Right(gst::Event::new_eos().build())) {
|
||||||
|
@ -354,7 +289,7 @@ impl AppSrc {
|
||||||
|
|
||||||
fn push_item(
|
fn push_item(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
item: Either<gst::Buffer, gst::Event>,
|
item: Either<gst::Buffer, gst::Event>,
|
||||||
) -> future::Either<
|
) -> future::Either<
|
||||||
Box<Future<Item = (), Error = ()> + Send + 'static>,
|
Box<Future<Item = (), Error = ()> + Send + 'static>,
|
||||||
|
@ -449,7 +384,7 @@ impl AppSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&self, element: &Element) -> Result<(), gst::ErrorMessage> {
|
fn prepare(&self, element: &gst::Element) -> Result<(), gst::ErrorMessage> {
|
||||||
gst_debug!(self.cat, obj: element, "Preparing");
|
gst_debug!(self.cat, obj: element, "Preparing");
|
||||||
|
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
let settings = self.settings.lock().unwrap().clone();
|
||||||
|
@ -480,7 +415,7 @@ impl AppSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unprepare(&self, element: &Element) -> Result<(), ()> {
|
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Unpreparing");
|
gst_debug!(self.cat, obj: element, "Unpreparing");
|
||||||
|
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
@ -498,7 +433,7 @@ impl AppSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&self, element: &Element) -> Result<(), ()> {
|
fn start(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Starting");
|
gst_debug!(self.cat, obj: element, "Starting");
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
let settings = self.settings.lock().unwrap().clone();
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
@ -515,7 +450,7 @@ impl AppSrc {
|
||||||
|
|
||||||
let element_clone = element.clone();
|
let element_clone = element.clone();
|
||||||
let future = channel_receiver.for_each(move |item| {
|
let future = channel_receiver.for_each(move |item| {
|
||||||
let appsrc = element_clone.get_impl().downcast_ref::<AppSrc>().unwrap();
|
let appsrc = Self::from_instance(&element_clone);
|
||||||
appsrc.push_item(&element_clone, item)
|
appsrc.push_item(&element_clone, item)
|
||||||
});
|
});
|
||||||
io_context.spawn(future);
|
io_context.spawn(future);
|
||||||
|
@ -526,7 +461,7 @@ impl AppSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self, element: &Element) -> Result<(), ()> {
|
fn stop(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Stopping");
|
gst_debug!(self.cat, obj: element, "Stopping");
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -539,28 +474,114 @@ impl AppSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl<Element> for AppSrc {
|
impl ObjectSubclass for AppSrc {
|
||||||
fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
|
const NAME: &'static str = "RsTsAppSrc";
|
||||||
let prop = &PROPERTIES[id as usize];
|
type ParentType = gst::Element;
|
||||||
|
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
|
||||||
|
klass.set_metadata(
|
||||||
|
"Thread-sharing app source",
|
||||||
|
"Source/Generic",
|
||||||
|
"Thread-sharing app source",
|
||||||
|
"Sebastian Dröge <sebastian@centricular.com>",
|
||||||
|
);
|
||||||
|
|
||||||
|
let caps = gst::Caps::new_any();
|
||||||
|
|
||||||
|
let src_pad_template = gst::PadTemplate::new(
|
||||||
|
"src",
|
||||||
|
gst::PadDirection::Src,
|
||||||
|
gst::PadPresence::Always,
|
||||||
|
&caps,
|
||||||
|
);
|
||||||
|
klass.add_pad_template(src_pad_template);
|
||||||
|
|
||||||
|
klass.install_properties(&PROPERTIES);
|
||||||
|
|
||||||
|
klass.add_action_signal(
|
||||||
|
"push-buffer",
|
||||||
|
&[gst::Buffer::static_type()],
|
||||||
|
bool::static_type(),
|
||||||
|
|args| {
|
||||||
|
let element = args[0].get::<gst::Element>().unwrap();
|
||||||
|
let buffer = args[1].get::<gst::Buffer>().unwrap();
|
||||||
|
let appsrc = Self::from_instance(&element);
|
||||||
|
|
||||||
|
Some(appsrc.push_buffer(&element, buffer).to_value())
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
klass.add_action_signal("end-of-stream", &[], bool::static_type(), |args| {
|
||||||
|
let element = args[0].get::<gst::Element>().unwrap();
|
||||||
|
let appsrc = Self::from_instance(&element);
|
||||||
|
Some(appsrc.end_of_stream(&element).to_value())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
|
||||||
|
let templ = klass.get_pad_template("src").unwrap();
|
||||||
|
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
||||||
|
|
||||||
|
src_pad.set_event_function(|pad, parent, event| {
|
||||||
|
AppSrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.src_event(pad, element, event),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
src_pad.set_query_function(|pad, parent, query| {
|
||||||
|
AppSrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.src_query(pad, element, query),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cat: gst::DebugCategory::new(
|
||||||
|
"ts-appsrc",
|
||||||
|
gst::DebugColorFlags::empty(),
|
||||||
|
"Thread-sharing app source",
|
||||||
|
),
|
||||||
|
src_pad: src_pad,
|
||||||
|
state: Mutex::new(State::default()),
|
||||||
|
settings: Mutex::new(Settings::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for AppSrc {
|
||||||
|
glib_object_impl!();
|
||||||
|
|
||||||
|
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context = value.get().unwrap_or_else(|| "".into());
|
settings.context = value.get().unwrap_or_else(|| "".into());
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context_wait = value.get().unwrap();
|
settings.context_wait = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::Boxed("caps", ..) => {
|
subclass::Property("caps", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.caps = value.get();
|
settings.caps = value.get();
|
||||||
}
|
}
|
||||||
Property::UInt("max-buffers", ..) => {
|
subclass::Property("max-buffers", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.max_buffers = value.get().unwrap();
|
settings.max_buffers = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::Boolean("do-timestamp", ..) => {
|
subclass::Property("do-timestamp", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.do_timestamp = value.get().unwrap();
|
settings.do_timestamp = value.get().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -568,39 +589,48 @@ impl ObjectImpl<Element> for AppSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||||
let prop = &PROPERTIES[id as usize];
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context.to_value())
|
Ok(settings.context.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context_wait.to_value())
|
Ok(settings.context_wait.to_value())
|
||||||
}
|
}
|
||||||
Property::Boxed("caps", ..) => {
|
subclass::Property("caps", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.caps.to_value())
|
Ok(settings.caps.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("max-buffers", ..) => {
|
subclass::Property("max-buffers", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.max_buffers.to_value())
|
Ok(settings.max_buffers.to_value())
|
||||||
}
|
}
|
||||||
Property::Boolean("do-timestamp", ..) => {
|
subclass::Property("do-timestamp", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.do_timestamp.to_value())
|
Ok(settings.do_timestamp.to_value())
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &glib::Object) {
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
|
||||||
|
let element = obj.downcast_ref::<gst::Element>().unwrap();
|
||||||
|
element.add_pad(&self.src_pad).unwrap();
|
||||||
|
|
||||||
|
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementImpl<Element> for AppSrc {
|
impl ElementImpl for AppSrc {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
||||||
|
@ -624,7 +654,7 @@ impl ElementImpl<Element> for AppSrc {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret = element.parent_change_state(transition);
|
let mut ret = self.parent_change_state(element, transition);
|
||||||
if ret == gst::StateChangeReturn::Failure {
|
if ret == gst::StateChangeReturn::Failure {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -648,23 +678,6 @@ impl ElementImpl<Element> for AppSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppSrcStatic;
|
|
||||||
|
|
||||||
impl ImplTypeStatic<Element> for AppSrcStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
"AppSrc"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
AppSrc::init(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut ElementClass) {
|
|
||||||
AppSrc::class_init(klass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
let type_ = register_type(AppSrcStatic);
|
gst::Element::register(plugin, "ts-appsrc", 0, AppSrc::get_type())
|
||||||
gst::Element::register(plugin, "ts-appsrc", 0, type_)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,6 @@ extern crate gstreamer_sys as gst_ffi;
|
||||||
extern crate gio;
|
extern crate gio;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate glib;
|
extern crate glib;
|
||||||
extern crate gobject_subclass;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate gst_plugin;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate gstreamer as gst;
|
extern crate gstreamer as gst;
|
||||||
|
|
||||||
|
@ -73,16 +70,16 @@ fn plugin_init(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin_define!(
|
gst_plugin_define!(
|
||||||
b"threadshare\0",
|
"threadshare",
|
||||||
b"Threadshare Plugin\0",
|
"Threadshare Plugin",
|
||||||
plugin_init,
|
plugin_init,
|
||||||
b"0.1.0\0",
|
"0.1.0",
|
||||||
b"LGPL\0",
|
"LGPL",
|
||||||
b"threadshare\0",
|
"threadshare",
|
||||||
b"threadshare\0",
|
"threadshare",
|
||||||
b"https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs\0",
|
"https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs",
|
||||||
b"2018-03-01\0"
|
"2018-03-01"
|
||||||
);
|
);
|
||||||
|
|
||||||
pub fn set_element_flags<T: glib::IsA<gst::Object> + glib::IsA<gst::Element>>(
|
pub fn set_element_flags<T: glib::IsA<gst::Object> + glib::IsA<gst::Element>>(
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
use glib;
|
use glib;
|
||||||
use glib::prelude::*;
|
use glib::prelude::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use glib::subclass::prelude::*;
|
||||||
use gst;
|
use gst;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
use gst::subclass::prelude::*;
|
||||||
use gobject_subclass::object::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
@ -87,62 +87,80 @@ impl Default for SettingsSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PROPERTIES_SRC: [Property; 6] = [
|
static PROPERTIES_SRC: [subclass::Property; 6] = [
|
||||||
Property::UInt(
|
subclass::Property("max-size-buffers", || {
|
||||||
"max-size-buffers",
|
glib::ParamSpec::uint(
|
||||||
"Max Size Buffers",
|
"max-size-buffers",
|
||||||
"Maximum number of buffers to queue (0=unlimited)",
|
"Max Size Buffers",
|
||||||
(0, u32::MAX),
|
"Maximum number of buffers to queue (0=unlimited)",
|
||||||
DEFAULT_MAX_SIZE_BUFFERS,
|
0,
|
||||||
PropertyMutability::ReadWrite,
|
u32::MAX,
|
||||||
),
|
DEFAULT_MAX_SIZE_BUFFERS,
|
||||||
Property::UInt(
|
glib::ParamFlags::READWRITE,
|
||||||
"max-size-bytes",
|
)
|
||||||
"Max Size Bytes",
|
}),
|
||||||
"Maximum number of bytes to queue (0=unlimited)",
|
subclass::Property("max-size-bytes", || {
|
||||||
(0, u32::MAX),
|
glib::ParamSpec::uint(
|
||||||
DEFAULT_MAX_SIZE_BYTES,
|
"max-size-bytes",
|
||||||
PropertyMutability::ReadWrite,
|
"Max Size Bytes",
|
||||||
),
|
"Maximum number of bytes to queue (0=unlimited)",
|
||||||
Property::UInt64(
|
0,
|
||||||
"max-size-time",
|
u32::MAX,
|
||||||
"Max Size Time",
|
DEFAULT_MAX_SIZE_BYTES,
|
||||||
"Maximum number of nanoseconds to queue (0=unlimited)",
|
glib::ParamFlags::READWRITE,
|
||||||
(0, u64::MAX - 1),
|
)
|
||||||
DEFAULT_MAX_SIZE_TIME,
|
}),
|
||||||
PropertyMutability::ReadWrite,
|
subclass::Property("max-size-time", || {
|
||||||
),
|
glib::ParamSpec::uint64(
|
||||||
Property::String(
|
"max-size-time",
|
||||||
"context",
|
"Max Size Time",
|
||||||
"Context",
|
"Maximum number of nanoseconds to queue (0=unlimited)",
|
||||||
"Context name to share threads with",
|
0,
|
||||||
Some(DEFAULT_CONTEXT),
|
u64::MAX - 1,
|
||||||
PropertyMutability::ReadWrite,
|
DEFAULT_MAX_SIZE_TIME,
|
||||||
),
|
glib::ParamFlags::READWRITE,
|
||||||
Property::UInt(
|
)
|
||||||
"context-wait",
|
}),
|
||||||
"Context Wait",
|
subclass::Property("context", || {
|
||||||
"Throttle poll loop to run at most once every this many ms",
|
glib::ParamSpec::string(
|
||||||
(0, 1000),
|
"context",
|
||||||
DEFAULT_CONTEXT_WAIT,
|
"Context",
|
||||||
PropertyMutability::ReadWrite,
|
"Context name to share threads with",
|
||||||
),
|
Some(DEFAULT_CONTEXT),
|
||||||
Property::String(
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
subclass::Property("context-wait", || {
|
||||||
|
glib::ParamSpec::uint(
|
||||||
|
"context-wait",
|
||||||
|
"Context Wait",
|
||||||
|
"Throttle poll loop to run at most once every this many ms",
|
||||||
|
0,
|
||||||
|
1000,
|
||||||
|
DEFAULT_CONTEXT_WAIT,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
subclass::Property("proxy-context", || {
|
||||||
|
glib::ParamSpec::string(
|
||||||
|
"proxy-context",
|
||||||
|
"Proxy Context",
|
||||||
|
"Context name of the proxy to share with",
|
||||||
|
Some(DEFAULT_PROXY_CONTEXT),
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
static PROPERTIES_SINK: [subclass::Property; 1] = [subclass::Property("proxy-context", || {
|
||||||
|
glib::ParamSpec::string(
|
||||||
"proxy-context",
|
"proxy-context",
|
||||||
"Proxy Context",
|
"Proxy Context",
|
||||||
"Context name of the proxy to share with",
|
"Context name of the proxy to share with",
|
||||||
Some(DEFAULT_PROXY_CONTEXT),
|
Some(DEFAULT_PROXY_CONTEXT),
|
||||||
PropertyMutability::ReadWrite,
|
glib::ParamFlags::READWRITE,
|
||||||
),
|
)
|
||||||
];
|
})];
|
||||||
|
|
||||||
static PROPERTIES_SINK: [Property; 1] = [Property::String(
|
|
||||||
"proxy-context",
|
|
||||||
"Proxy Context",
|
|
||||||
"Context name of the proxy to share with",
|
|
||||||
Some(DEFAULT_PROXY_CONTEXT),
|
|
||||||
PropertyMutability::ReadWrite,
|
|
||||||
)];
|
|
||||||
|
|
||||||
// TODO: Refactor into a Sender and Receiver instead of the have_ booleans
|
// TODO: Refactor into a Sender and Receiver instead of the have_ booleans
|
||||||
|
|
||||||
|
@ -273,80 +291,10 @@ struct ProxySink {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProxySink {
|
impl ProxySink {
|
||||||
fn class_init(klass: &mut ElementClass) {
|
|
||||||
klass.set_metadata(
|
|
||||||
"Thread-sharing proxy sink",
|
|
||||||
"Sink/Generic",
|
|
||||||
"Thread-sharing proxy sink",
|
|
||||||
"Sebastian Dröge <sebastian@centricular.com>",
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
|
|
||||||
let sink_pad_template = gst::PadTemplate::new(
|
|
||||||
"sink",
|
|
||||||
gst::PadDirection::Sink,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(sink_pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES_SINK);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
let templ = element.get_pad_template("sink").unwrap();
|
|
||||||
let sink_pad = gst::Pad::new_from_template(&templ, "sink");
|
|
||||||
|
|
||||||
sink_pad.set_chain_function(|pad, parent, buffer| {
|
|
||||||
ProxySink::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| gst::FlowReturn::Error,
|
|
||||||
|queue, element| queue.sink_chain(pad, element, buffer),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
sink_pad.set_chain_list_function(|pad, parent, list| {
|
|
||||||
ProxySink::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| gst::FlowReturn::Error,
|
|
||||||
|queue, element| queue.sink_chain_list(pad, element, list),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
sink_pad.set_event_function(|pad, parent, event| {
|
|
||||||
ProxySink::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.sink_event(pad, element, event),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
sink_pad.set_query_function(|pad, parent, query| {
|
|
||||||
ProxySink::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.sink_query(pad, element, query),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
element.add_pad(&sink_pad).unwrap();
|
|
||||||
|
|
||||||
::set_element_flags(element, gst::ElementFlags::SINK);
|
|
||||||
|
|
||||||
Box::new(Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"ts-proxysink",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Thread-sharing proxy sink",
|
|
||||||
),
|
|
||||||
sink_pad: sink_pad,
|
|
||||||
state: Mutex::new(StateSink::default()),
|
|
||||||
settings: Mutex::new(SettingsSink::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enqueue_item(
|
fn enqueue_item(
|
||||||
&self,
|
&self,
|
||||||
_pad: &gst::Pad,
|
_pad: &gst::Pad,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
item: DataQueueItem,
|
item: DataQueueItem,
|
||||||
) -> gst::FlowReturn {
|
) -> gst::FlowReturn {
|
||||||
let wait_future = {
|
let wait_future = {
|
||||||
|
@ -426,10 +374,7 @@ impl ProxySink {
|
||||||
|
|
||||||
let element_clone = element.clone();
|
let element_clone = element.clone();
|
||||||
let future = future::poll_fn(move || {
|
let future = future::poll_fn(move || {
|
||||||
let sink = element_clone
|
let sink = Self::from_instance(&element_clone);
|
||||||
.get_impl()
|
|
||||||
.downcast_ref::<ProxySink>()
|
|
||||||
.unwrap();
|
|
||||||
let state = sink.state.lock().unwrap();
|
let state = sink.state.lock().unwrap();
|
||||||
|
|
||||||
gst_log!(
|
gst_log!(
|
||||||
|
@ -549,7 +494,7 @@ impl ProxySink {
|
||||||
fn sink_chain(
|
fn sink_chain(
|
||||||
&self,
|
&self,
|
||||||
pad: &gst::Pad,
|
pad: &gst::Pad,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
buffer: gst::Buffer,
|
buffer: gst::Buffer,
|
||||||
) -> gst::FlowReturn {
|
) -> gst::FlowReturn {
|
||||||
gst_log!(self.cat, obj: pad, "Handling buffer {:?}", buffer);
|
gst_log!(self.cat, obj: pad, "Handling buffer {:?}", buffer);
|
||||||
|
@ -559,14 +504,14 @@ impl ProxySink {
|
||||||
fn sink_chain_list(
|
fn sink_chain_list(
|
||||||
&self,
|
&self,
|
||||||
pad: &gst::Pad,
|
pad: &gst::Pad,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
list: gst::BufferList,
|
list: gst::BufferList,
|
||||||
) -> gst::FlowReturn {
|
) -> gst::FlowReturn {
|
||||||
gst_log!(self.cat, obj: pad, "Handling buffer list {:?}", list);
|
gst_log!(self.cat, obj: pad, "Handling buffer list {:?}", list);
|
||||||
self.enqueue_item(pad, element, DataQueueItem::BufferList(list))
|
self.enqueue_item(pad, element, DataQueueItem::BufferList(list))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink_event(&self, pad: &gst::Pad, element: &Element, event: gst::Event) -> bool {
|
fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool {
|
||||||
use gst::EventView;
|
use gst::EventView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
||||||
|
@ -612,13 +557,18 @@ impl ProxySink {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink_query(&self, pad: &gst::Pad, element: &Element, query: &mut gst::QueryRef) -> bool {
|
fn sink_query(
|
||||||
|
&self,
|
||||||
|
pad: &gst::Pad,
|
||||||
|
element: &gst::Element,
|
||||||
|
query: &mut gst::QueryRef,
|
||||||
|
) -> bool {
|
||||||
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
||||||
|
|
||||||
pad.query_default(element, query)
|
pad.query_default(element, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&self, element: &Element) -> Result<(), gst::ErrorMessage> {
|
fn prepare(&self, element: &gst::Element) -> Result<(), gst::ErrorMessage> {
|
||||||
gst_debug!(self.cat, obj: element, "Preparing");
|
gst_debug!(self.cat, obj: element, "Preparing");
|
||||||
|
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
let settings = self.settings.lock().unwrap().clone();
|
||||||
|
@ -640,7 +590,7 @@ impl ProxySink {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unprepare(&self, element: &Element) -> Result<(), ()> {
|
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Unpreparing");
|
gst_debug!(self.cat, obj: element, "Unpreparing");
|
||||||
|
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
@ -650,7 +600,7 @@ impl ProxySink {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&self, element: &Element) -> Result<(), ()> {
|
fn start(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Starting");
|
gst_debug!(self.cat, obj: element, "Starting");
|
||||||
let state = self.state.lock().unwrap();
|
let state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -662,7 +612,7 @@ impl ProxySink {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self, element: &Element) -> Result<(), ()> {
|
fn stop(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Stopping");
|
gst_debug!(self.cat, obj: element, "Stopping");
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -682,12 +632,93 @@ impl ProxySink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl<Element> for ProxySink {
|
impl ObjectSubclass for ProxySink {
|
||||||
fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
|
const NAME: &'static str = "RsTsProxySink";
|
||||||
let prop = &PROPERTIES_SINK[id as usize];
|
type ParentType = gst::Element;
|
||||||
|
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
|
||||||
|
klass.set_metadata(
|
||||||
|
"Thread-sharing proxy sink",
|
||||||
|
"Sink/Generic",
|
||||||
|
"Thread-sharing proxy sink",
|
||||||
|
"Sebastian Dröge <sebastian@centricular.com>",
|
||||||
|
);
|
||||||
|
|
||||||
|
let caps = gst::Caps::new_any();
|
||||||
|
|
||||||
|
let sink_pad_template = gst::PadTemplate::new(
|
||||||
|
"sink",
|
||||||
|
gst::PadDirection::Sink,
|
||||||
|
gst::PadPresence::Always,
|
||||||
|
&caps,
|
||||||
|
);
|
||||||
|
klass.add_pad_template(sink_pad_template);
|
||||||
|
|
||||||
|
klass.install_properties(&PROPERTIES_SINK);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
|
||||||
|
let templ = klass.get_pad_template("sink").unwrap();
|
||||||
|
let sink_pad = gst::Pad::new_from_template(&templ, "sink");
|
||||||
|
|
||||||
|
sink_pad.set_chain_function(|pad, parent, buffer| {
|
||||||
|
ProxySink::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| gst::FlowReturn::Error,
|
||||||
|
|queue, element| queue.sink_chain(pad, element, buffer),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
sink_pad.set_chain_list_function(|pad, parent, list| {
|
||||||
|
ProxySink::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| gst::FlowReturn::Error,
|
||||||
|
|queue, element| queue.sink_chain_list(pad, element, list),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
sink_pad.set_event_function(|pad, parent, event| {
|
||||||
|
ProxySink::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.sink_event(pad, element, event),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
sink_pad.set_query_function(|pad, parent, query| {
|
||||||
|
ProxySink::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.sink_query(pad, element, query),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cat: gst::DebugCategory::new(
|
||||||
|
"ts-proxysink",
|
||||||
|
gst::DebugColorFlags::empty(),
|
||||||
|
"Thread-sharing proxy sink",
|
||||||
|
),
|
||||||
|
sink_pad: sink_pad,
|
||||||
|
state: Mutex::new(StateSink::default()),
|
||||||
|
settings: Mutex::new(SettingsSink::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for ProxySink {
|
||||||
|
glib_object_impl!();
|
||||||
|
|
||||||
|
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES_SINK[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("proxy-context", ..) => {
|
subclass::Property("proxy-context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.proxy_context = value.get().unwrap_or_else(|| "".into());
|
settings.proxy_context = value.get().unwrap_or_else(|| "".into());
|
||||||
}
|
}
|
||||||
|
@ -695,23 +726,32 @@ impl ObjectImpl<Element> for ProxySink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||||
let prop = &PROPERTIES_SINK[id as usize];
|
let prop = &PROPERTIES_SINK[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("proxy-context", ..) => {
|
subclass::Property("proxy-context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.proxy_context.to_value())
|
Ok(settings.proxy_context.to_value())
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &glib::Object) {
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
|
||||||
|
let element = obj.downcast_ref::<gst::Element>().unwrap();
|
||||||
|
element.add_pad(&self.sink_pad).unwrap();
|
||||||
|
|
||||||
|
::set_element_flags(element, gst::ElementFlags::SINK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementImpl<Element> for ProxySink {
|
impl ElementImpl for ProxySink {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
||||||
|
@ -735,7 +775,7 @@ impl ElementImpl<Element> for ProxySink {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = element.parent_change_state(transition);
|
let ret = self.parent_change_state(element, transition);
|
||||||
if ret == gst::StateChangeReturn::Failure {
|
if ret == gst::StateChangeReturn::Failure {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -760,71 +800,6 @@ struct ProxySrc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProxySrc {
|
impl ProxySrc {
|
||||||
fn class_init(klass: &mut ElementClass) {
|
|
||||||
klass.set_metadata(
|
|
||||||
"Thread-sharing proxy source",
|
|
||||||
"Source/Generic",
|
|
||||||
"Thread-sharing proxy source",
|
|
||||||
"Sebastian Dröge <sebastian@centricular.com>",
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
|
|
||||||
let src_pad_template = gst::PadTemplate::new(
|
|
||||||
"src",
|
|
||||||
gst::PadDirection::Src,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(src_pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES_SRC);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
let templ = element.get_pad_template("src").unwrap();
|
|
||||||
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
|
||||||
|
|
||||||
src_pad.set_event_function(|pad, parent, event| {
|
|
||||||
ProxySrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.src_event(pad, element, event),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
src_pad.set_query_function(|pad, parent, query| {
|
|
||||||
ProxySrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.src_query(pad, element, query),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
element.add_pad(&src_pad).unwrap();
|
|
||||||
|
|
||||||
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
|
||||||
|
|
||||||
Box::new(Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"ts-proxysrc",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Thread-sharing proxy source",
|
|
||||||
),
|
|
||||||
src_pad: src_pad,
|
|
||||||
state: Mutex::new(StateSrc::default()),
|
|
||||||
settings: Mutex::new(SettingsSrc::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn catch_panic_pad_function<T, F: FnOnce(&Self, &Element) -> T, G: FnOnce() -> T>(
|
|
||||||
parent: &Option<gst::Object>,
|
|
||||||
fallback: G,
|
|
||||||
f: F,
|
|
||||||
) -> T {
|
|
||||||
let element = parent.as_ref().unwrap().downcast_ref::<Element>().unwrap();
|
|
||||||
let src = element.get_impl().downcast_ref::<ProxySrc>().unwrap();
|
|
||||||
element.catch_panic(fallback, |element| f(src, element))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_io_context_event(state: &StateSrc) -> Option<gst::Event> {
|
fn create_io_context_event(state: &StateSrc) -> Option<gst::Event> {
|
||||||
if let (&Some(ref pending_future_id), &Some(ref io_context)) =
|
if let (&Some(ref pending_future_id), &Some(ref io_context)) =
|
||||||
(&state.pending_future_id, &state.io_context)
|
(&state.pending_future_id, &state.io_context)
|
||||||
|
@ -842,7 +817,7 @@ impl ProxySrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_event(&self, pad: &gst::Pad, element: &Element, event: gst::Event) -> bool {
|
fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool {
|
||||||
use gst::EventView;
|
use gst::EventView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
||||||
|
@ -875,7 +850,12 @@ impl ProxySrc {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_query(&self, pad: &gst::Pad, _element: &Element, query: &mut gst::QueryRef) -> bool {
|
fn src_query(
|
||||||
|
&self,
|
||||||
|
pad: &gst::Pad,
|
||||||
|
_element: &gst::Element,
|
||||||
|
query: &mut gst::QueryRef,
|
||||||
|
) -> bool {
|
||||||
use gst::QueryView;
|
use gst::QueryView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
||||||
|
@ -917,7 +897,7 @@ impl ProxySrc {
|
||||||
|
|
||||||
fn push_item(
|
fn push_item(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
item: DataQueueItem,
|
item: DataQueueItem,
|
||||||
) -> future::Either<
|
) -> future::Either<
|
||||||
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
||||||
|
@ -1045,7 +1025,7 @@ impl ProxySrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&self, element: &Element) -> Result<(), gst::ErrorMessage> {
|
fn prepare(&self, element: &gst::Element) -> Result<(), gst::ErrorMessage> {
|
||||||
gst_debug!(self.cat, obj: element, "Preparing");
|
gst_debug!(self.cat, obj: element, "Preparing");
|
||||||
|
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
let settings = self.settings.lock().unwrap().clone();
|
||||||
|
@ -1095,14 +1075,11 @@ impl ProxySrc {
|
||||||
.schedule(
|
.schedule(
|
||||||
&io_context,
|
&io_context,
|
||||||
move |item| {
|
move |item| {
|
||||||
let src = element_clone.get_impl().downcast_ref::<ProxySrc>().unwrap();
|
let src = Self::from_instance(&element_clone);
|
||||||
src.push_item(&element_clone, item)
|
src.push_item(&element_clone, item)
|
||||||
},
|
},
|
||||||
move |err| {
|
move |err| {
|
||||||
let src = element_clone2
|
let src = Self::from_instance(&element_clone2);
|
||||||
.get_impl()
|
|
||||||
.downcast_ref::<ProxySrc>()
|
|
||||||
.unwrap();
|
|
||||||
gst_error!(src.cat, obj: &element_clone2, "Got error {}", err);
|
gst_error!(src.cat, obj: &element_clone2, "Got error {}", err);
|
||||||
match err {
|
match err {
|
||||||
gst::FlowError::CustomError => (),
|
gst::FlowError::CustomError => (),
|
||||||
|
@ -1143,7 +1120,7 @@ impl ProxySrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unprepare(&self, element: &Element) -> Result<(), ()> {
|
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Unpreparing");
|
gst_debug!(self.cat, obj: element, "Unpreparing");
|
||||||
|
|
||||||
// FIXME: The IO Context has to be alive longer than the queue,
|
// FIXME: The IO Context has to be alive longer than the queue,
|
||||||
|
@ -1181,7 +1158,7 @@ impl ProxySrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&self, element: &Element) -> Result<(), ()> {
|
fn start(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Starting");
|
gst_debug!(self.cat, obj: element, "Starting");
|
||||||
let state = self.state.lock().unwrap();
|
let state = self.state.lock().unwrap();
|
||||||
let queue = state.queue.as_ref().unwrap().0.lock().unwrap();
|
let queue = state.queue.as_ref().unwrap().0.lock().unwrap();
|
||||||
|
@ -1195,7 +1172,7 @@ impl ProxySrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self, element: &Element) -> Result<(), ()> {
|
fn stop(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Stopping");
|
gst_debug!(self.cat, obj: element, "Stopping");
|
||||||
let state = self.state.lock().unwrap();
|
let state = self.state.lock().unwrap();
|
||||||
let mut queue = state.queue.as_ref().unwrap().0.lock().unwrap();
|
let mut queue = state.queue.as_ref().unwrap().0.lock().unwrap();
|
||||||
|
@ -1212,32 +1189,99 @@ impl ProxySrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl<Element> for ProxySrc {
|
impl ObjectSubclass for ProxySrc {
|
||||||
fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
|
const NAME: &'static str = "RsTsProxySrc";
|
||||||
let prop = &PROPERTIES_SRC[id as usize];
|
type ParentType = gst::Element;
|
||||||
|
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
|
||||||
|
klass.set_metadata(
|
||||||
|
"Thread-sharing proxy source",
|
||||||
|
"Source/Generic",
|
||||||
|
"Thread-sharing proxy source",
|
||||||
|
"Sebastian Dröge <sebastian@centricular.com>",
|
||||||
|
);
|
||||||
|
|
||||||
|
let caps = gst::Caps::new_any();
|
||||||
|
|
||||||
|
let src_pad_template = gst::PadTemplate::new(
|
||||||
|
"src",
|
||||||
|
gst::PadDirection::Src,
|
||||||
|
gst::PadPresence::Always,
|
||||||
|
&caps,
|
||||||
|
);
|
||||||
|
klass.add_pad_template(src_pad_template);
|
||||||
|
|
||||||
|
klass.install_properties(&PROPERTIES_SRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
|
||||||
|
let templ = klass.get_pad_template("src").unwrap();
|
||||||
|
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
||||||
|
|
||||||
|
src_pad.set_event_function(|pad, parent, event| {
|
||||||
|
ProxySrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.src_event(pad, element, event),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
src_pad.set_query_function(|pad, parent, query| {
|
||||||
|
ProxySrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.src_query(pad, element, query),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cat: gst::DebugCategory::new(
|
||||||
|
"ts-proxysrc",
|
||||||
|
gst::DebugColorFlags::empty(),
|
||||||
|
"Thread-sharing proxy source",
|
||||||
|
),
|
||||||
|
src_pad: src_pad,
|
||||||
|
state: Mutex::new(StateSrc::default()),
|
||||||
|
settings: Mutex::new(SettingsSrc::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for ProxySrc {
|
||||||
|
glib_object_impl!();
|
||||||
|
|
||||||
|
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES_SRC[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::UInt("max-size-buffers", ..) => {
|
subclass::Property("max-size-buffers", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.max_size_buffers = value.get().unwrap();
|
settings.max_size_buffers = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::UInt("max-size-bytes", ..) => {
|
subclass::Property("max-size-bytes", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.max_size_bytes = value.get().unwrap();
|
settings.max_size_bytes = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::UInt64("max-size-time", ..) => {
|
subclass::Property("max-size-time", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.max_size_time = value.get().unwrap();
|
settings.max_size_time = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context = value.get().unwrap_or_else(|| "".into());
|
settings.context = value.get().unwrap_or_else(|| "".into());
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context_wait = value.get().unwrap();
|
settings.context_wait = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::String("proxy-context", ..) => {
|
subclass::Property("proxy-context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.proxy_context = value.get().unwrap_or_else(|| "".into());
|
settings.proxy_context = value.get().unwrap_or_else(|| "".into());
|
||||||
}
|
}
|
||||||
|
@ -1245,43 +1289,52 @@ impl ObjectImpl<Element> for ProxySrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||||
let prop = &PROPERTIES_SRC[id as usize];
|
let prop = &PROPERTIES_SRC[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::UInt("max-size-buffers", ..) => {
|
subclass::Property("max-size-buffers", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.max_size_buffers.to_value())
|
Ok(settings.max_size_buffers.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("max-size-bytes", ..) => {
|
subclass::Property("max-size-bytes", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.max_size_bytes.to_value())
|
Ok(settings.max_size_bytes.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt64("max-size-time", ..) => {
|
subclass::Property("max-size-time", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.max_size_time.to_value())
|
Ok(settings.max_size_time.to_value())
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context.to_value())
|
Ok(settings.context.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context_wait.to_value())
|
Ok(settings.context_wait.to_value())
|
||||||
}
|
}
|
||||||
Property::String("proxy-context", ..) => {
|
subclass::Property("proxy-context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.proxy_context.to_value())
|
Ok(settings.proxy_context.to_value())
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &glib::Object) {
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
|
||||||
|
let element = obj.downcast_ref::<gst::Element>().unwrap();
|
||||||
|
element.add_pad(&self.src_pad).unwrap();
|
||||||
|
|
||||||
|
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementImpl<Element> for ProxySrc {
|
impl ElementImpl for ProxySrc {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
||||||
|
@ -1305,7 +1358,7 @@ impl ElementImpl<Element> for ProxySrc {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret = element.parent_change_state(transition);
|
let mut ret = self.parent_change_state(element, transition);
|
||||||
if ret == gst::StateChangeReturn::Failure {
|
if ret == gst::StateChangeReturn::Failure {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1325,42 +1378,7 @@ impl ElementImpl<Element> for ProxySrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProxySinkStatic;
|
|
||||||
|
|
||||||
impl ImplTypeStatic<Element> for ProxySinkStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
"ProxySink"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
ProxySink::init(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut ElementClass) {
|
|
||||||
ProxySink::class_init(klass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ProxySrcStatic;
|
|
||||||
|
|
||||||
impl ImplTypeStatic<Element> for ProxySrcStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
"ProxySrc"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
ProxySrc::init(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut ElementClass) {
|
|
||||||
ProxySrc::class_init(klass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
let type_ = register_type(ProxySinkStatic);
|
gst::Element::register(plugin, "ts-proxysink", 0, ProxySink::get_type())?;
|
||||||
gst::Element::register(plugin, "ts-proxysink", 0, type_)?;
|
gst::Element::register(plugin, "ts-proxysrc", 0, ProxySrc::get_type())
|
||||||
|
|
||||||
let type_ = register_type(ProxySrcStatic);
|
|
||||||
gst::Element::register(plugin, "ts-proxysrc", 0, type_)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
|
|
||||||
use glib;
|
use glib;
|
||||||
use glib::prelude::*;
|
use glib::prelude::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use glib::subclass::prelude::*;
|
||||||
use gst;
|
use gst;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
use gst::subclass::prelude::*;
|
||||||
use gobject_subclass::object::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
@ -64,46 +64,60 @@ impl Default for Settings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PROPERTIES: [Property; 5] = [
|
static PROPERTIES: [subclass::Property; 5] = [
|
||||||
Property::UInt(
|
subclass::Property("max-size-buffers", || {
|
||||||
"max-size-buffers",
|
glib::ParamSpec::uint(
|
||||||
"Max Size Buffers",
|
"max-size-buffers",
|
||||||
"Maximum number of buffers to queue (0=unlimited)",
|
"Max Size Buffers",
|
||||||
(0, u32::MAX),
|
"Maximum number of buffers to queue (0=unlimited)",
|
||||||
DEFAULT_MAX_SIZE_BUFFERS,
|
0,
|
||||||
PropertyMutability::ReadWrite,
|
u32::MAX,
|
||||||
),
|
DEFAULT_MAX_SIZE_BUFFERS,
|
||||||
Property::UInt(
|
glib::ParamFlags::READWRITE,
|
||||||
"max-size-bytes",
|
)
|
||||||
"Max Size Bytes",
|
}),
|
||||||
"Maximum number of bytes to queue (0=unlimited)",
|
subclass::Property("max-size-bytes", || {
|
||||||
(0, u32::MAX),
|
glib::ParamSpec::uint(
|
||||||
DEFAULT_MAX_SIZE_BYTES,
|
"max-size-bytes",
|
||||||
PropertyMutability::ReadWrite,
|
"Max Size Bytes",
|
||||||
),
|
"Maximum number of bytes to queue (0=unlimited)",
|
||||||
Property::UInt64(
|
0,
|
||||||
"max-size-time",
|
u32::MAX,
|
||||||
"Max Size Time",
|
DEFAULT_MAX_SIZE_BYTES,
|
||||||
"Maximum number of nanoseconds to queue (0=unlimited)",
|
glib::ParamFlags::READWRITE,
|
||||||
(0, u64::MAX - 1),
|
)
|
||||||
DEFAULT_MAX_SIZE_TIME,
|
}),
|
||||||
PropertyMutability::ReadWrite,
|
subclass::Property("max-size-time", || {
|
||||||
),
|
glib::ParamSpec::uint64(
|
||||||
Property::String(
|
"max-size-time",
|
||||||
"context",
|
"Max Size Time",
|
||||||
"Context",
|
"Maximum number of nanoseconds to queue (0=unlimited)",
|
||||||
"Context name to share threads with",
|
0,
|
||||||
Some(DEFAULT_CONTEXT),
|
u64::MAX - 1,
|
||||||
PropertyMutability::ReadWrite,
|
DEFAULT_MAX_SIZE_TIME,
|
||||||
),
|
glib::ParamFlags::READWRITE,
|
||||||
Property::UInt(
|
)
|
||||||
"context-wait",
|
}),
|
||||||
"Context Wait",
|
subclass::Property("context", || {
|
||||||
"Throttle poll loop to run at most once every this many ms",
|
glib::ParamSpec::string(
|
||||||
(0, 1000),
|
"context",
|
||||||
DEFAULT_CONTEXT_WAIT,
|
"Context",
|
||||||
PropertyMutability::ReadWrite,
|
"Context name to share threads with",
|
||||||
),
|
Some(DEFAULT_CONTEXT),
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
subclass::Property("context-wait", || {
|
||||||
|
glib::ParamSpec::uint(
|
||||||
|
"context-wait",
|
||||||
|
"Context Wait",
|
||||||
|
"Throttle poll loop to run at most once every this many ms",
|
||||||
|
0,
|
||||||
|
1000,
|
||||||
|
DEFAULT_CONTEXT_WAIT,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
|
@ -141,100 +155,6 @@ struct Queue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Queue {
|
impl Queue {
|
||||||
fn class_init(klass: &mut ElementClass) {
|
|
||||||
klass.set_metadata(
|
|
||||||
"Thread-sharing queue",
|
|
||||||
"Generic",
|
|
||||||
"Simple data queue",
|
|
||||||
"Sebastian Dröge <sebastian@centricular.com>",
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
|
|
||||||
let sink_pad_template = gst::PadTemplate::new(
|
|
||||||
"sink",
|
|
||||||
gst::PadDirection::Sink,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(sink_pad_template);
|
|
||||||
|
|
||||||
let src_pad_template = gst::PadTemplate::new(
|
|
||||||
"src",
|
|
||||||
gst::PadDirection::Src,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(src_pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
let templ = element.get_pad_template("sink").unwrap();
|
|
||||||
let sink_pad = gst::Pad::new_from_template(&templ, "sink");
|
|
||||||
let templ = element.get_pad_template("src").unwrap();
|
|
||||||
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
|
||||||
|
|
||||||
sink_pad.set_chain_function(|pad, parent, buffer| {
|
|
||||||
Queue::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| gst::FlowReturn::Error,
|
|
||||||
|queue, element| queue.sink_chain(pad, element, buffer),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
sink_pad.set_chain_list_function(|pad, parent, list| {
|
|
||||||
Queue::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| gst::FlowReturn::Error,
|
|
||||||
|queue, element| queue.sink_chain_list(pad, element, list),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
sink_pad.set_event_function(|pad, parent, event| {
|
|
||||||
Queue::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.sink_event(pad, element, event),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
sink_pad.set_query_function(|pad, parent, query| {
|
|
||||||
Queue::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.sink_query(pad, element, query),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
src_pad.set_event_function(|pad, parent, event| {
|
|
||||||
Queue::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.src_event(pad, element, event),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
src_pad.set_query_function(|pad, parent, query| {
|
|
||||||
Queue::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|queue, element| queue.src_query(pad, element, query),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
element.add_pad(&sink_pad).unwrap();
|
|
||||||
element.add_pad(&src_pad).unwrap();
|
|
||||||
|
|
||||||
Box::new(Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"ts-queue",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Thread-sharing queue",
|
|
||||||
),
|
|
||||||
sink_pad: sink_pad,
|
|
||||||
src_pad: src_pad,
|
|
||||||
state: Mutex::new(State::default()),
|
|
||||||
settings: Mutex::new(Settings::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_io_context_event(state: &State) -> Option<gst::Event> {
|
fn create_io_context_event(state: &State) -> Option<gst::Event> {
|
||||||
if let (&Some(ref pending_future_id), &Some(ref io_context)) =
|
if let (&Some(ref pending_future_id), &Some(ref io_context)) =
|
||||||
(&state.pending_future_id, &state.io_context)
|
(&state.pending_future_id, &state.io_context)
|
||||||
|
@ -255,7 +175,7 @@ impl Queue {
|
||||||
fn enqueue_item(
|
fn enqueue_item(
|
||||||
&self,
|
&self,
|
||||||
_pad: &gst::Pad,
|
_pad: &gst::Pad,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
item: DataQueueItem,
|
item: DataQueueItem,
|
||||||
) -> gst::FlowReturn {
|
) -> gst::FlowReturn {
|
||||||
let wait_future = {
|
let wait_future = {
|
||||||
|
@ -325,7 +245,7 @@ impl Queue {
|
||||||
|
|
||||||
let element_clone = element.clone();
|
let element_clone = element.clone();
|
||||||
let future = future::poll_fn(move || {
|
let future = future::poll_fn(move || {
|
||||||
let queue = element_clone.get_impl().downcast_ref::<Queue>().unwrap();
|
let queue = Self::from_instance(&element_clone);
|
||||||
let mut state = queue.state.lock().unwrap();
|
let mut state = queue.state.lock().unwrap();
|
||||||
|
|
||||||
let State {
|
let State {
|
||||||
|
@ -430,7 +350,7 @@ impl Queue {
|
||||||
fn sink_chain(
|
fn sink_chain(
|
||||||
&self,
|
&self,
|
||||||
pad: &gst::Pad,
|
pad: &gst::Pad,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
buffer: gst::Buffer,
|
buffer: gst::Buffer,
|
||||||
) -> gst::FlowReturn {
|
) -> gst::FlowReturn {
|
||||||
gst_log!(self.cat, obj: pad, "Handling buffer {:?}", buffer);
|
gst_log!(self.cat, obj: pad, "Handling buffer {:?}", buffer);
|
||||||
|
@ -440,14 +360,14 @@ impl Queue {
|
||||||
fn sink_chain_list(
|
fn sink_chain_list(
|
||||||
&self,
|
&self,
|
||||||
pad: &gst::Pad,
|
pad: &gst::Pad,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
list: gst::BufferList,
|
list: gst::BufferList,
|
||||||
) -> gst::FlowReturn {
|
) -> gst::FlowReturn {
|
||||||
gst_log!(self.cat, obj: pad, "Handling buffer list {:?}", list);
|
gst_log!(self.cat, obj: pad, "Handling buffer list {:?}", list);
|
||||||
self.enqueue_item(pad, element, DataQueueItem::BufferList(list))
|
self.enqueue_item(pad, element, DataQueueItem::BufferList(list))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink_event(&self, pad: &gst::Pad, element: &Element, mut event: gst::Event) -> bool {
|
fn sink_event(&self, pad: &gst::Pad, element: &gst::Element, mut event: gst::Event) -> bool {
|
||||||
use gst::EventView;
|
use gst::EventView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
||||||
|
@ -505,7 +425,12 @@ impl Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink_query(&self, pad: &gst::Pad, _element: &Element, query: &mut gst::QueryRef) -> bool {
|
fn sink_query(
|
||||||
|
&self,
|
||||||
|
pad: &gst::Pad,
|
||||||
|
_element: &gst::Element,
|
||||||
|
query: &mut gst::QueryRef,
|
||||||
|
) -> bool {
|
||||||
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
||||||
|
|
||||||
if query.is_serialized() {
|
if query.is_serialized() {
|
||||||
|
@ -518,7 +443,7 @@ impl Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_event(&self, pad: &gst::Pad, element: &Element, event: gst::Event) -> bool {
|
fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool {
|
||||||
use gst::EventView;
|
use gst::EventView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
||||||
|
@ -542,7 +467,12 @@ impl Queue {
|
||||||
self.sink_pad.push_event(event)
|
self.sink_pad.push_event(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_query(&self, pad: &gst::Pad, _element: &Element, query: &mut gst::QueryRef) -> bool {
|
fn src_query(
|
||||||
|
&self,
|
||||||
|
pad: &gst::Pad,
|
||||||
|
_element: &gst::Element,
|
||||||
|
query: &mut gst::QueryRef,
|
||||||
|
) -> bool {
|
||||||
use gst::QueryView;
|
use gst::QueryView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
||||||
|
@ -578,7 +508,7 @@ impl Queue {
|
||||||
|
|
||||||
fn push_item(
|
fn push_item(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
item: DataQueueItem,
|
item: DataQueueItem,
|
||||||
) -> future::Either<
|
) -> future::Either<
|
||||||
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
||||||
|
@ -679,7 +609,7 @@ impl Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&self, element: &Element) -> Result<(), gst::ErrorMessage> {
|
fn prepare(&self, element: &gst::Element) -> Result<(), gst::ErrorMessage> {
|
||||||
gst_debug!(self.cat, obj: element, "Preparing");
|
gst_debug!(self.cat, obj: element, "Preparing");
|
||||||
|
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
let settings = self.settings.lock().unwrap().clone();
|
||||||
|
@ -719,11 +649,11 @@ impl Queue {
|
||||||
.schedule(
|
.schedule(
|
||||||
&io_context,
|
&io_context,
|
||||||
move |item| {
|
move |item| {
|
||||||
let queue = element_clone.get_impl().downcast_ref::<Queue>().unwrap();
|
let queue = Self::from_instance(&element_clone);
|
||||||
queue.push_item(&element_clone, item)
|
queue.push_item(&element_clone, item)
|
||||||
},
|
},
|
||||||
move |err| {
|
move |err| {
|
||||||
let queue = element_clone2.get_impl().downcast_ref::<Queue>().unwrap();
|
let queue = Self::from_instance(&element_clone2);
|
||||||
gst_error!(queue.cat, obj: &element_clone2, "Got error {}", err);
|
gst_error!(queue.cat, obj: &element_clone2, "Got error {}", err);
|
||||||
match err {
|
match err {
|
||||||
gst::FlowError::CustomError => (),
|
gst::FlowError::CustomError => (),
|
||||||
|
@ -762,7 +692,7 @@ impl Queue {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unprepare(&self, element: &Element) -> Result<(), ()> {
|
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Unpreparing");
|
gst_debug!(self.cat, obj: element, "Unpreparing");
|
||||||
|
|
||||||
// FIXME: The IO Context has to be alive longer than the queue,
|
// FIXME: The IO Context has to be alive longer than the queue,
|
||||||
|
@ -792,7 +722,7 @@ impl Queue {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&self, element: &Element) -> Result<(), ()> {
|
fn start(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Starting");
|
gst_debug!(self.cat, obj: element, "Starting");
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -806,7 +736,7 @@ impl Queue {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self, element: &Element) -> Result<(), ()> {
|
fn stop(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Stopping");
|
gst_debug!(self.cat, obj: element, "Stopping");
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -826,28 +756,135 @@ impl Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl<Element> for Queue {
|
impl ObjectSubclass for Queue {
|
||||||
fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
|
const NAME: &'static str = "RsTsQueue";
|
||||||
let prop = &PROPERTIES[id as usize];
|
type ParentType = gst::Element;
|
||||||
|
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
|
||||||
|
klass.set_metadata(
|
||||||
|
"Thread-sharing queue",
|
||||||
|
"Generic",
|
||||||
|
"Simple data queue",
|
||||||
|
"Sebastian Dröge <sebastian@centricular.com>",
|
||||||
|
);
|
||||||
|
|
||||||
|
let caps = gst::Caps::new_any();
|
||||||
|
|
||||||
|
let sink_pad_template = gst::PadTemplate::new(
|
||||||
|
"sink",
|
||||||
|
gst::PadDirection::Sink,
|
||||||
|
gst::PadPresence::Always,
|
||||||
|
&caps,
|
||||||
|
);
|
||||||
|
klass.add_pad_template(sink_pad_template);
|
||||||
|
|
||||||
|
let src_pad_template = gst::PadTemplate::new(
|
||||||
|
"src",
|
||||||
|
gst::PadDirection::Src,
|
||||||
|
gst::PadPresence::Always,
|
||||||
|
&caps,
|
||||||
|
);
|
||||||
|
klass.add_pad_template(src_pad_template);
|
||||||
|
|
||||||
|
klass.install_properties(&PROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
|
||||||
|
let templ = klass.get_pad_template("sink").unwrap();
|
||||||
|
let sink_pad = gst::Pad::new_from_template(&templ, "sink");
|
||||||
|
let templ = klass.get_pad_template("src").unwrap();
|
||||||
|
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
||||||
|
|
||||||
|
sink_pad.set_chain_function(|pad, parent, buffer| {
|
||||||
|
Queue::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| gst::FlowReturn::Error,
|
||||||
|
|queue, element| queue.sink_chain(pad, element, buffer),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
sink_pad.set_chain_list_function(|pad, parent, list| {
|
||||||
|
Queue::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| gst::FlowReturn::Error,
|
||||||
|
|queue, element| queue.sink_chain_list(pad, element, list),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
sink_pad.set_event_function(|pad, parent, event| {
|
||||||
|
Queue::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.sink_event(pad, element, event),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
sink_pad.set_query_function(|pad, parent, query| {
|
||||||
|
Queue::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.sink_query(pad, element, query),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
src_pad.set_event_function(|pad, parent, event| {
|
||||||
|
Queue::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.src_event(pad, element, event),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
src_pad.set_query_function(|pad, parent, query| {
|
||||||
|
Queue::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|queue, element| queue.src_query(pad, element, query),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cat: gst::DebugCategory::new(
|
||||||
|
"ts-queue",
|
||||||
|
gst::DebugColorFlags::empty(),
|
||||||
|
"Thread-sharing queue",
|
||||||
|
),
|
||||||
|
sink_pad: sink_pad,
|
||||||
|
src_pad: src_pad,
|
||||||
|
state: Mutex::new(State::default()),
|
||||||
|
settings: Mutex::new(Settings::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for Queue {
|
||||||
|
glib_object_impl!();
|
||||||
|
|
||||||
|
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::UInt("max-size-buffers", ..) => {
|
subclass::Property("max-size-buffers", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.max_size_buffers = value.get().unwrap();
|
settings.max_size_buffers = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::UInt("max-size-bytes", ..) => {
|
subclass::Property("max-size-bytes", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.max_size_bytes = value.get().unwrap();
|
settings.max_size_bytes = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::UInt64("max-size-time", ..) => {
|
subclass::Property("max-size-time", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.max_size_time = value.get().unwrap();
|
settings.max_size_time = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context = value.get().unwrap_or_else(|| "".into());
|
settings.context = value.get().unwrap_or_else(|| "".into());
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context_wait = value.get().unwrap();
|
settings.context_wait = value.get().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -855,39 +892,47 @@ impl ObjectImpl<Element> for Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||||
let prop = &PROPERTIES[id as usize];
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::UInt("max-size-buffers", ..) => {
|
subclass::Property("max-size-buffers", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.max_size_buffers.to_value())
|
Ok(settings.max_size_buffers.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("max-size-bytes", ..) => {
|
subclass::Property("max-size-bytes", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.max_size_bytes.to_value())
|
Ok(settings.max_size_bytes.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt64("max-size-time", ..) => {
|
subclass::Property("max-size-time", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.max_size_time.to_value())
|
Ok(settings.max_size_time.to_value())
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context.to_value())
|
Ok(settings.context.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context_wait.to_value())
|
Ok(settings.context_wait.to_value())
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &glib::Object) {
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
|
||||||
|
let element = obj.downcast_ref::<gst::Element>().unwrap();
|
||||||
|
element.add_pad(&self.sink_pad).unwrap();
|
||||||
|
element.add_pad(&self.src_pad).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementImpl<Element> for Queue {
|
impl ElementImpl for Queue {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
||||||
|
@ -911,7 +956,7 @@ impl ElementImpl<Element> for Queue {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = element.parent_change_state(transition);
|
let ret = self.parent_change_state(element, transition);
|
||||||
if ret == gst::StateChangeReturn::Failure {
|
if ret == gst::StateChangeReturn::Failure {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -928,24 +973,6 @@ impl ElementImpl<Element> for Queue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QueueStatic;
|
|
||||||
|
|
||||||
impl ImplTypeStatic<Element> for QueueStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
"Queue"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
Queue::init(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut ElementClass) {
|
|
||||||
Queue::class_init(klass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
let queue_static = QueueStatic;
|
gst::Element::register(plugin, "ts-queue", 0, Queue::get_type())
|
||||||
let type_ = register_type(queue_static);
|
|
||||||
gst::Element::register(plugin, "ts-queue", 0, type_)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
|
|
||||||
use glib;
|
use glib;
|
||||||
use glib::prelude::*;
|
use glib::prelude::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use glib::subclass::prelude::*;
|
||||||
use gst;
|
use gst;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
use gst::subclass::prelude::*;
|
||||||
use gobject_subclass::object::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
@ -71,52 +71,67 @@ impl Default for Settings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PROPERTIES: [Property; 6] = [
|
static PROPERTIES: [subclass::Property; 6] = [
|
||||||
Property::String(
|
subclass::Property("address", || {
|
||||||
"address",
|
glib::ParamSpec::string(
|
||||||
"Address",
|
"address",
|
||||||
"Address to receive packets from",
|
"Address",
|
||||||
DEFAULT_ADDRESS,
|
"Address to receive packets from",
|
||||||
PropertyMutability::ReadWrite,
|
DEFAULT_ADDRESS,
|
||||||
),
|
glib::ParamFlags::READWRITE,
|
||||||
Property::UInt(
|
)
|
||||||
"port",
|
}),
|
||||||
"Port",
|
subclass::Property("port", || {
|
||||||
"Port to receive packets from",
|
glib::ParamSpec::uint(
|
||||||
(0, u16::MAX as u32),
|
"port",
|
||||||
DEFAULT_PORT,
|
"Port",
|
||||||
PropertyMutability::ReadWrite,
|
"Port to receive packets from",
|
||||||
),
|
0,
|
||||||
Property::Boxed(
|
u16::MAX as u32,
|
||||||
"caps",
|
DEFAULT_PORT,
|
||||||
"Caps",
|
glib::ParamFlags::READWRITE,
|
||||||
"Caps to use",
|
)
|
||||||
gst::Caps::static_type,
|
}),
|
||||||
PropertyMutability::ReadWrite,
|
subclass::Property("caps", || {
|
||||||
),
|
glib::ParamSpec::boxed(
|
||||||
Property::UInt(
|
"caps",
|
||||||
"chunk-size",
|
"Caps",
|
||||||
"Chunk Size",
|
"Caps to use",
|
||||||
"Chunk Size",
|
gst::Caps::static_type(),
|
||||||
(0, u16::MAX as u32),
|
glib::ParamFlags::READWRITE,
|
||||||
DEFAULT_CHUNK_SIZE,
|
)
|
||||||
PropertyMutability::ReadWrite,
|
}),
|
||||||
),
|
subclass::Property("chunk-size", || {
|
||||||
Property::String(
|
glib::ParamSpec::uint(
|
||||||
"context",
|
"chunk-size",
|
||||||
"Context",
|
"Chunk Size",
|
||||||
"Context name to share threads with",
|
"Chunk Size",
|
||||||
Some(DEFAULT_CONTEXT),
|
0,
|
||||||
PropertyMutability::ReadWrite,
|
u16::MAX as u32,
|
||||||
),
|
DEFAULT_CHUNK_SIZE,
|
||||||
Property::UInt(
|
glib::ParamFlags::READWRITE,
|
||||||
"context-wait",
|
)
|
||||||
"Context Wait",
|
}),
|
||||||
"Throttle poll loop to run at most once every this many ms",
|
subclass::Property("context", || {
|
||||||
(0, 1000),
|
glib::ParamSpec::string(
|
||||||
DEFAULT_CONTEXT_WAIT,
|
"context",
|
||||||
PropertyMutability::ReadWrite,
|
"Context",
|
||||||
),
|
"Context name to share threads with",
|
||||||
|
Some(DEFAULT_CONTEXT),
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
subclass::Property("context-wait", || {
|
||||||
|
glib::ParamSpec::uint(
|
||||||
|
"context-wait",
|
||||||
|
"Context Wait",
|
||||||
|
"Throttle poll loop to run at most once every this many ms",
|
||||||
|
0,
|
||||||
|
1000,
|
||||||
|
DEFAULT_CONTEXT_WAIT,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub struct TcpClientReader {
|
pub struct TcpClientReader {
|
||||||
|
@ -185,61 +200,7 @@ struct TcpClientSrc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TcpClientSrc {
|
impl TcpClientSrc {
|
||||||
fn class_init(klass: &mut ElementClass) {
|
fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool {
|
||||||
klass.set_metadata(
|
|
||||||
"Thread-sharing TCP client source",
|
|
||||||
"Source/Network",
|
|
||||||
"Receives data over the network via TCP",
|
|
||||||
"Sebastian Dröge <sebastian@centricular.com>, LEE Dongjun <redongjun@gmail.com>",
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
let src_pad_template = gst::PadTemplate::new(
|
|
||||||
"src",
|
|
||||||
gst::PadDirection::Src,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(src_pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
let templ = element.get_pad_template("src").unwrap();
|
|
||||||
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
|
||||||
|
|
||||||
src_pad.set_event_function(|pad, parent, event| {
|
|
||||||
TcpClientSrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|tcpclientsrc, element| tcpclientsrc.src_event(pad, element, event),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
src_pad.set_query_function(|pad, parent, query| {
|
|
||||||
TcpClientSrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|tcpclientsrc, element| tcpclientsrc.src_query(pad, element, query),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
element.add_pad(&src_pad).unwrap();
|
|
||||||
|
|
||||||
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
|
||||||
|
|
||||||
Box::new(Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"ts-tcpclientsrc",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Thread-sharing TCP Client source",
|
|
||||||
),
|
|
||||||
src_pad: src_pad,
|
|
||||||
state: Mutex::new(State::default()),
|
|
||||||
settings: Mutex::new(Settings::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn src_event(&self, pad: &gst::Pad, element: &Element, event: gst::Event) -> bool {
|
|
||||||
use gst::EventView;
|
use gst::EventView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
||||||
|
@ -271,7 +232,12 @@ impl TcpClientSrc {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_query(&self, pad: &gst::Pad, _element: &Element, query: &mut gst::QueryRef) -> bool {
|
fn src_query(
|
||||||
|
&self,
|
||||||
|
pad: &gst::Pad,
|
||||||
|
_element: &gst::Element,
|
||||||
|
query: &mut gst::QueryRef,
|
||||||
|
) -> bool {
|
||||||
use gst::QueryView;
|
use gst::QueryView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
||||||
|
@ -331,7 +297,7 @@ impl TcpClientSrc {
|
||||||
|
|
||||||
fn push_buffer(
|
fn push_buffer(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
buffer: gst::Buffer,
|
buffer: gst::Buffer,
|
||||||
) -> future::Either<
|
) -> future::Either<
|
||||||
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
||||||
|
@ -431,7 +397,7 @@ impl TcpClientSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&self, element: &Element) -> Result<(), gst::ErrorMessage> {
|
fn prepare(&self, element: &gst::Element) -> Result<(), gst::ErrorMessage> {
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: element, "Preparing");
|
gst_debug!(self.cat, obj: element, "Preparing");
|
||||||
|
@ -493,17 +459,11 @@ impl TcpClientSrc {
|
||||||
.schedule(
|
.schedule(
|
||||||
&io_context,
|
&io_context,
|
||||||
move |buffer| {
|
move |buffer| {
|
||||||
let tcpclientsrc = element_clone
|
let tcpclientsrc = Self::from_instance(&element_clone);
|
||||||
.get_impl()
|
|
||||||
.downcast_ref::<TcpClientSrc>()
|
|
||||||
.unwrap();
|
|
||||||
tcpclientsrc.push_buffer(&element_clone, buffer)
|
tcpclientsrc.push_buffer(&element_clone, buffer)
|
||||||
},
|
},
|
||||||
move |err| {
|
move |err| {
|
||||||
let tcpclientsrc = element_clone2
|
let tcpclientsrc = Self::from_instance(&element_clone2);
|
||||||
.get_impl()
|
|
||||||
.downcast_ref::<TcpClientSrc>()
|
|
||||||
.unwrap();
|
|
||||||
gst_error!(tcpclientsrc.cat, obj: &element_clone2, "Got error {}", err);
|
gst_error!(tcpclientsrc.cat, obj: &element_clone2, "Got error {}", err);
|
||||||
match err {
|
match err {
|
||||||
Either::Left(gst::FlowError::CustomError) => (),
|
Either::Left(gst::FlowError::CustomError) => (),
|
||||||
|
@ -547,7 +507,7 @@ impl TcpClientSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unprepare(&self, element: &Element) -> Result<(), ()> {
|
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Unpreparing");
|
gst_debug!(self.cat, obj: element, "Unpreparing");
|
||||||
|
|
||||||
// FIXME: The IO Context has to be alive longer than the queue,
|
// FIXME: The IO Context has to be alive longer than the queue,
|
||||||
|
@ -576,7 +536,7 @@ impl TcpClientSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&self, element: &Element) -> Result<(), ()> {
|
fn start(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Starting");
|
gst_debug!(self.cat, obj: element, "Starting");
|
||||||
let state = self.state.lock().unwrap();
|
let state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -589,7 +549,7 @@ impl TcpClientSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self, element: &Element) -> Result<(), ()> {
|
fn stop(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Stopping");
|
gst_debug!(self.cat, obj: element, "Stopping");
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -604,32 +564,98 @@ impl TcpClientSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl<Element> for TcpClientSrc {
|
impl ObjectSubclass for TcpClientSrc {
|
||||||
fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
|
const NAME: &'static str = "RsTsTcpClientSrc";
|
||||||
let prop = &PROPERTIES[id as usize];
|
type ParentType = gst::Element;
|
||||||
|
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
|
||||||
|
klass.set_metadata(
|
||||||
|
"Thread-sharing TCP client source",
|
||||||
|
"Source/Network",
|
||||||
|
"Receives data over the network via TCP",
|
||||||
|
"Sebastian Dröge <sebastian@centricular.com>, LEE Dongjun <redongjun@gmail.com>",
|
||||||
|
);
|
||||||
|
|
||||||
|
let caps = gst::Caps::new_any();
|
||||||
|
let src_pad_template = gst::PadTemplate::new(
|
||||||
|
"src",
|
||||||
|
gst::PadDirection::Src,
|
||||||
|
gst::PadPresence::Always,
|
||||||
|
&caps,
|
||||||
|
);
|
||||||
|
klass.add_pad_template(src_pad_template);
|
||||||
|
|
||||||
|
klass.install_properties(&PROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
|
||||||
|
let templ = klass.get_pad_template("src").unwrap();
|
||||||
|
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
||||||
|
|
||||||
|
src_pad.set_event_function(|pad, parent, event| {
|
||||||
|
TcpClientSrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|tcpclientsrc, element| tcpclientsrc.src_event(pad, element, event),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
src_pad.set_query_function(|pad, parent, query| {
|
||||||
|
TcpClientSrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|tcpclientsrc, element| tcpclientsrc.src_query(pad, element, query),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cat: gst::DebugCategory::new(
|
||||||
|
"ts-tcpclientsrc",
|
||||||
|
gst::DebugColorFlags::empty(),
|
||||||
|
"Thread-sharing TCP Client source",
|
||||||
|
),
|
||||||
|
src_pad: src_pad,
|
||||||
|
state: Mutex::new(State::default()),
|
||||||
|
settings: Mutex::new(Settings::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for TcpClientSrc {
|
||||||
|
glib_object_impl!();
|
||||||
|
|
||||||
|
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("address", ..) => {
|
subclass::Property("address", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.address = value.get();
|
settings.address = value.get();
|
||||||
}
|
}
|
||||||
Property::UInt("port", ..) => {
|
subclass::Property("port", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.port = value.get().unwrap();
|
settings.port = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::Boxed("caps", ..) => {
|
subclass::Property("caps", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.caps = value.get();
|
settings.caps = value.get();
|
||||||
}
|
}
|
||||||
Property::UInt("chunk-size", ..) => {
|
subclass::Property("chunk-size", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.chunk_size = value.get().unwrap();
|
settings.chunk_size = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context = value.get().unwrap_or_else(|| "".into());
|
settings.context = value.get().unwrap_or_else(|| "".into());
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context_wait = value.get().unwrap();
|
settings.context_wait = value.get().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -637,43 +663,52 @@ impl ObjectImpl<Element> for TcpClientSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||||
let prop = &PROPERTIES[id as usize];
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("address", ..) => {
|
subclass::Property("address", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.address.to_value())
|
Ok(settings.address.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("port", ..) => {
|
subclass::Property("port", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.port.to_value())
|
Ok(settings.port.to_value())
|
||||||
}
|
}
|
||||||
Property::Boxed("caps", ..) => {
|
subclass::Property("caps", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.caps.to_value())
|
Ok(settings.caps.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("chunk-size", ..) => {
|
subclass::Property("chunk-size", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.chunk_size.to_value())
|
Ok(settings.chunk_size.to_value())
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context.to_value())
|
Ok(settings.context.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context_wait.to_value())
|
Ok(settings.context_wait.to_value())
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &glib::Object) {
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
|
||||||
|
let element = obj.downcast_ref::<gst::Element>().unwrap();
|
||||||
|
element.add_pad(&self.src_pad).unwrap();
|
||||||
|
|
||||||
|
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementImpl<Element> for TcpClientSrc {
|
impl ElementImpl for TcpClientSrc {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
||||||
|
@ -699,7 +734,7 @@ impl ElementImpl<Element> for TcpClientSrc {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret = element.parent_change_state(transition);
|
let mut ret = self.parent_change_state(element, transition);
|
||||||
if ret == gst::StateChangeReturn::Failure {
|
if ret == gst::StateChangeReturn::Failure {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -719,24 +754,6 @@ impl ElementImpl<Element> for TcpClientSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TcpClientSrcStatic;
|
|
||||||
|
|
||||||
impl ImplTypeStatic<Element> for TcpClientSrcStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
"TcpClientSrc"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
TcpClientSrc::init(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut ElementClass) {
|
|
||||||
TcpClientSrc::class_init(klass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
let tcpclientsrc_static = TcpClientSrcStatic;
|
gst::Element::register(plugin, "ts-tcpclientsrc", 0, TcpClientSrc::get_type())
|
||||||
let type_ = register_type(tcpclientsrc_static);
|
|
||||||
gst::Element::register(plugin, "ts-tcpclientsrc", 0, type_)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,17 +17,17 @@
|
||||||
|
|
||||||
use glib;
|
use glib;
|
||||||
use glib::prelude::*;
|
use glib::prelude::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use glib::subclass::prelude::*;
|
||||||
use gst;
|
use gst;
|
||||||
use gst::prelude::*;
|
use gst::prelude::*;
|
||||||
|
use gst::subclass::prelude::*;
|
||||||
|
|
||||||
use gio;
|
use gio;
|
||||||
|
|
||||||
use gio_ffi;
|
use gio_ffi;
|
||||||
use gobject_ffi;
|
use gobject_ffi;
|
||||||
|
|
||||||
use gobject_subclass::object::*;
|
|
||||||
use gst_plugin::element::*;
|
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
@ -179,73 +179,94 @@ impl Default for Settings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PROPERTIES: [Property; 9] = [
|
static PROPERTIES: [subclass::Property; 9] = [
|
||||||
Property::String(
|
subclass::Property("address", || {
|
||||||
"address",
|
glib::ParamSpec::string(
|
||||||
"Address",
|
"address",
|
||||||
"Address/multicast group to listen on",
|
"Address",
|
||||||
DEFAULT_ADDRESS,
|
"Address/multicast group to listen on",
|
||||||
PropertyMutability::ReadWrite,
|
DEFAULT_ADDRESS,
|
||||||
),
|
glib::ParamFlags::READWRITE,
|
||||||
Property::UInt(
|
)
|
||||||
"port",
|
}),
|
||||||
"Port",
|
subclass::Property("port", || {
|
||||||
"Port to listen on",
|
glib::ParamSpec::uint(
|
||||||
(0, u16::MAX as u32),
|
"port",
|
||||||
DEFAULT_PORT,
|
"Port",
|
||||||
PropertyMutability::ReadWrite,
|
"Port to listen on",
|
||||||
),
|
0,
|
||||||
Property::Boolean(
|
u16::MAX as u32,
|
||||||
"reuse",
|
DEFAULT_PORT,
|
||||||
"Reuse",
|
glib::ParamFlags::READWRITE,
|
||||||
"Allow reuse of the port",
|
)
|
||||||
DEFAULT_REUSE,
|
}),
|
||||||
PropertyMutability::ReadWrite,
|
subclass::Property("reuse", || {
|
||||||
),
|
glib::ParamSpec::boolean(
|
||||||
Property::Boxed(
|
"reuse",
|
||||||
"caps",
|
"Reuse",
|
||||||
"Caps",
|
"Allow reuse of the port",
|
||||||
"Caps to use",
|
DEFAULT_REUSE,
|
||||||
gst::Caps::static_type,
|
glib::ParamFlags::READWRITE,
|
||||||
PropertyMutability::ReadWrite,
|
)
|
||||||
),
|
}),
|
||||||
Property::UInt(
|
subclass::Property("caps", || {
|
||||||
"mtu",
|
glib::ParamSpec::boxed(
|
||||||
"MTU",
|
"caps",
|
||||||
"MTU",
|
"Caps",
|
||||||
(0, u16::MAX as u32),
|
"Caps to use",
|
||||||
DEFAULT_MTU,
|
gst::Caps::static_type(),
|
||||||
PropertyMutability::ReadWrite,
|
glib::ParamFlags::READWRITE,
|
||||||
),
|
)
|
||||||
Property::Object(
|
}),
|
||||||
"socket",
|
subclass::Property("mtu", || {
|
||||||
"Socket",
|
glib::ParamSpec::uint(
|
||||||
"Socket to use for UDP reception. (None == allocate)",
|
"mtu",
|
||||||
gio::Socket::static_type,
|
"MTU",
|
||||||
PropertyMutability::ReadWrite,
|
"MTU",
|
||||||
),
|
0,
|
||||||
Property::Object(
|
u16::MAX as u32,
|
||||||
"used-socket",
|
DEFAULT_MTU,
|
||||||
"Used Socket",
|
glib::ParamFlags::READWRITE,
|
||||||
"Socket currently in use for UDP reception. (None = no socket)",
|
)
|
||||||
gio::Socket::static_type,
|
}),
|
||||||
PropertyMutability::Readable,
|
subclass::Property("socket", || {
|
||||||
),
|
glib::ParamSpec::object(
|
||||||
Property::String(
|
"socket",
|
||||||
"context",
|
"Socket",
|
||||||
"Context",
|
"Socket to use for UDP reception. (None == allocate)",
|
||||||
"Context name to share threads with",
|
gio::Socket::static_type(),
|
||||||
Some(DEFAULT_CONTEXT),
|
glib::ParamFlags::READWRITE,
|
||||||
PropertyMutability::ReadWrite,
|
)
|
||||||
),
|
}),
|
||||||
Property::UInt(
|
subclass::Property("used-socket", || {
|
||||||
"context-wait",
|
glib::ParamSpec::object(
|
||||||
"Context Wait",
|
"used-socket",
|
||||||
"Throttle poll loop to run at most once every this many ms",
|
"Used Socket",
|
||||||
(0, 1000),
|
"Socket currently in use for UDP reception. (None = no socket)",
|
||||||
DEFAULT_CONTEXT_WAIT,
|
gio::Socket::static_type(),
|
||||||
PropertyMutability::ReadWrite,
|
glib::ParamFlags::READABLE,
|
||||||
),
|
)
|
||||||
|
}),
|
||||||
|
subclass::Property("context", || {
|
||||||
|
glib::ParamSpec::string(
|
||||||
|
"context",
|
||||||
|
"Context",
|
||||||
|
"Context name to share threads with",
|
||||||
|
Some(DEFAULT_CONTEXT),
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
subclass::Property("context-wait", || {
|
||||||
|
glib::ParamSpec::uint(
|
||||||
|
"context-wait",
|
||||||
|
"Context Wait",
|
||||||
|
"Throttle poll loop to run at most once every this many ms",
|
||||||
|
0,
|
||||||
|
1000,
|
||||||
|
DEFAULT_CONTEXT_WAIT,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub struct UdpReader {
|
pub struct UdpReader {
|
||||||
|
@ -296,61 +317,7 @@ struct UdpSrc {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UdpSrc {
|
impl UdpSrc {
|
||||||
fn class_init(klass: &mut ElementClass) {
|
fn src_event(&self, pad: &gst::Pad, element: &gst::Element, event: gst::Event) -> bool {
|
||||||
klass.set_metadata(
|
|
||||||
"Thread-sharing UDP source",
|
|
||||||
"Source/Network",
|
|
||||||
"Receives data over the network via UDP",
|
|
||||||
"Sebastian Dröge <sebastian@centricular.com>",
|
|
||||||
);
|
|
||||||
|
|
||||||
let caps = gst::Caps::new_any();
|
|
||||||
let src_pad_template = gst::PadTemplate::new(
|
|
||||||
"src",
|
|
||||||
gst::PadDirection::Src,
|
|
||||||
gst::PadPresence::Always,
|
|
||||||
&caps,
|
|
||||||
);
|
|
||||||
klass.add_pad_template(src_pad_template);
|
|
||||||
|
|
||||||
klass.install_properties(&PROPERTIES);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
let templ = element.get_pad_template("src").unwrap();
|
|
||||||
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
|
||||||
|
|
||||||
src_pad.set_event_function(|pad, parent, event| {
|
|
||||||
UdpSrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|udpsrc, element| udpsrc.src_event(pad, element, event),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
src_pad.set_query_function(|pad, parent, query| {
|
|
||||||
UdpSrc::catch_panic_pad_function(
|
|
||||||
parent,
|
|
||||||
|| false,
|
|
||||||
|udpsrc, element| udpsrc.src_query(pad, element, query),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
element.add_pad(&src_pad).unwrap();
|
|
||||||
|
|
||||||
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
|
||||||
|
|
||||||
Box::new(Self {
|
|
||||||
cat: gst::DebugCategory::new(
|
|
||||||
"ts-udpsrc",
|
|
||||||
gst::DebugColorFlags::empty(),
|
|
||||||
"Thread-sharing UDP source",
|
|
||||||
),
|
|
||||||
src_pad: src_pad,
|
|
||||||
state: Mutex::new(State::default()),
|
|
||||||
settings: Mutex::new(Settings::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn src_event(&self, pad: &gst::Pad, element: &Element, event: gst::Event) -> bool {
|
|
||||||
use gst::EventView;
|
use gst::EventView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
gst_log!(self.cat, obj: pad, "Handling event {:?}", event);
|
||||||
|
@ -382,7 +349,12 @@ impl UdpSrc {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src_query(&self, pad: &gst::Pad, _element: &Element, query: &mut gst::QueryRef) -> bool {
|
fn src_query(
|
||||||
|
&self,
|
||||||
|
pad: &gst::Pad,
|
||||||
|
_element: &gst::Element,
|
||||||
|
query: &mut gst::QueryRef,
|
||||||
|
) -> bool {
|
||||||
use gst::QueryView;
|
use gst::QueryView;
|
||||||
|
|
||||||
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
gst_log!(self.cat, obj: pad, "Handling query {:?}", query);
|
||||||
|
@ -442,7 +414,7 @@ impl UdpSrc {
|
||||||
|
|
||||||
fn push_buffer(
|
fn push_buffer(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
buffer: gst::Buffer,
|
buffer: gst::Buffer,
|
||||||
) -> future::Either<
|
) -> future::Either<
|
||||||
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
Box<Future<Item = (), Error = gst::FlowError> + Send + 'static>,
|
||||||
|
@ -537,7 +509,7 @@ impl UdpSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&self, element: &Element) -> Result<(), gst::ErrorMessage> {
|
fn prepare(&self, element: &gst::Element) -> Result<(), gst::ErrorMessage> {
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||||
|
|
||||||
gst_debug!(self.cat, obj: element, "Preparing");
|
gst_debug!(self.cat, obj: element, "Preparing");
|
||||||
|
@ -768,11 +740,11 @@ impl UdpSrc {
|
||||||
.schedule(
|
.schedule(
|
||||||
&io_context,
|
&io_context,
|
||||||
move |buffer| {
|
move |buffer| {
|
||||||
let udpsrc = element_clone.get_impl().downcast_ref::<UdpSrc>().unwrap();
|
let udpsrc = Self::from_instance(&element_clone);
|
||||||
udpsrc.push_buffer(&element_clone, buffer)
|
udpsrc.push_buffer(&element_clone, buffer)
|
||||||
},
|
},
|
||||||
move |err| {
|
move |err| {
|
||||||
let udpsrc = element_clone2.get_impl().downcast_ref::<UdpSrc>().unwrap();
|
let udpsrc = Self::from_instance(&element_clone2);
|
||||||
gst_error!(udpsrc.cat, obj: &element_clone2, "Got error {}", err);
|
gst_error!(udpsrc.cat, obj: &element_clone2, "Got error {}", err);
|
||||||
match err {
|
match err {
|
||||||
Either::Left(gst::FlowError::CustomError) => (),
|
Either::Left(gst::FlowError::CustomError) => (),
|
||||||
|
@ -819,7 +791,7 @@ impl UdpSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unprepare(&self, element: &Element) -> Result<(), ()> {
|
fn unprepare(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Unpreparing");
|
gst_debug!(self.cat, obj: element, "Unpreparing");
|
||||||
|
|
||||||
self.settings.lock().unwrap().used_socket = None;
|
self.settings.lock().unwrap().used_socket = None;
|
||||||
|
@ -850,7 +822,7 @@ impl UdpSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(&self, element: &Element) -> Result<(), ()> {
|
fn start(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Starting");
|
gst_debug!(self.cat, obj: element, "Starting");
|
||||||
let state = self.state.lock().unwrap();
|
let state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -863,7 +835,7 @@ impl UdpSrc {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self, element: &Element) -> Result<(), ()> {
|
fn stop(&self, element: &gst::Element) -> Result<(), ()> {
|
||||||
gst_debug!(self.cat, obj: element, "Stopping");
|
gst_debug!(self.cat, obj: element, "Stopping");
|
||||||
let mut state = self.state.lock().unwrap();
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
@ -878,45 +850,111 @@ impl UdpSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl<Element> for UdpSrc {
|
impl ObjectSubclass for UdpSrc {
|
||||||
fn set_property(&self, _obj: &glib::Object, id: u32, value: &glib::Value) {
|
const NAME: &'static str = "RsTsUdpSrc";
|
||||||
let prop = &PROPERTIES[id as usize];
|
type ParentType = gst::Element;
|
||||||
|
type Instance = gst::subclass::ElementInstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn class_init(klass: &mut subclass::simple::ClassStruct<Self>) {
|
||||||
|
klass.set_metadata(
|
||||||
|
"Thread-sharing UDP source",
|
||||||
|
"Source/Network",
|
||||||
|
"Receives data over the network via UDP",
|
||||||
|
"Sebastian Dröge <sebastian@centricular.com>",
|
||||||
|
);
|
||||||
|
|
||||||
|
let caps = gst::Caps::new_any();
|
||||||
|
let src_pad_template = gst::PadTemplate::new(
|
||||||
|
"src",
|
||||||
|
gst::PadDirection::Src,
|
||||||
|
gst::PadPresence::Always,
|
||||||
|
&caps,
|
||||||
|
);
|
||||||
|
klass.add_pad_template(src_pad_template);
|
||||||
|
|
||||||
|
klass.install_properties(&PROPERTIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_with_class(klass: &subclass::simple::ClassStruct<Self>) -> Self {
|
||||||
|
let templ = klass.get_pad_template("src").unwrap();
|
||||||
|
let src_pad = gst::Pad::new_from_template(&templ, "src");
|
||||||
|
|
||||||
|
src_pad.set_event_function(|pad, parent, event| {
|
||||||
|
UdpSrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|udpsrc, element| udpsrc.src_event(pad, element, event),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
src_pad.set_query_function(|pad, parent, query| {
|
||||||
|
UdpSrc::catch_panic_pad_function(
|
||||||
|
parent,
|
||||||
|
|| false,
|
||||||
|
|udpsrc, element| udpsrc.src_query(pad, element, query),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
cat: gst::DebugCategory::new(
|
||||||
|
"ts-udpsrc",
|
||||||
|
gst::DebugColorFlags::empty(),
|
||||||
|
"Thread-sharing UDP source",
|
||||||
|
),
|
||||||
|
src_pad: src_pad,
|
||||||
|
state: Mutex::new(State::default()),
|
||||||
|
settings: Mutex::new(Settings::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for UdpSrc {
|
||||||
|
glib_object_impl!();
|
||||||
|
|
||||||
|
fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("address", ..) => {
|
subclass::Property("address", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.address = value.get();
|
settings.address = value.get();
|
||||||
}
|
}
|
||||||
Property::UInt("port", ..) => {
|
subclass::Property("port", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.port = value.get().unwrap();
|
settings.port = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::Boolean("reuse", ..) => {
|
subclass::Property("reuse", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.reuse = value.get().unwrap();
|
settings.reuse = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::Boxed("caps", ..) => {
|
subclass::Property("caps", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.caps = value.get();
|
settings.caps = value.get();
|
||||||
}
|
}
|
||||||
Property::UInt("mtu", ..) => {
|
subclass::Property("mtu", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.mtu = value.get().unwrap();
|
settings.mtu = value.get().unwrap();
|
||||||
}
|
}
|
||||||
Property::Object("socket", ..) => {
|
subclass::Property("socket", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.socket = value
|
settings.socket = value
|
||||||
.get::<gio::Socket>()
|
.get::<gio::Socket>()
|
||||||
.map(|socket| GioSocketWrapper::new(&socket));
|
.map(|socket| GioSocketWrapper::new(&socket));
|
||||||
}
|
}
|
||||||
Property::Object("used-socket", ..) => {
|
subclass::Property("used-socket", ..) => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context = value.get().unwrap_or_else(|| "".into());
|
settings.context = value.get().unwrap_or_else(|| "".into());
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
settings.context_wait = value.get().unwrap();
|
settings.context_wait = value.get().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -924,31 +962,31 @@ impl ObjectImpl<Element> for UdpSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_property(&self, _obj: &glib::Object, id: u32) -> Result<glib::Value, ()> {
|
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
|
||||||
let prop = &PROPERTIES[id as usize];
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
match *prop {
|
match *prop {
|
||||||
Property::String("address", ..) => {
|
subclass::Property("address", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.address.to_value())
|
Ok(settings.address.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("port", ..) => {
|
subclass::Property("port", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.port.to_value())
|
Ok(settings.port.to_value())
|
||||||
}
|
}
|
||||||
Property::Boolean("reuse", ..) => {
|
subclass::Property("reuse", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.reuse.to_value())
|
Ok(settings.reuse.to_value())
|
||||||
}
|
}
|
||||||
Property::Boxed("caps", ..) => {
|
subclass::Property("caps", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.caps.to_value())
|
Ok(settings.caps.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("mtu", ..) => {
|
subclass::Property("mtu", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.mtu.to_value())
|
Ok(settings.mtu.to_value())
|
||||||
}
|
}
|
||||||
Property::Object("socket", ..) => {
|
subclass::Property("socket", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings
|
Ok(settings
|
||||||
.socket
|
.socket
|
||||||
|
@ -956,7 +994,7 @@ impl ObjectImpl<Element> for UdpSrc {
|
||||||
.map(GioSocketWrapper::as_socket)
|
.map(GioSocketWrapper::as_socket)
|
||||||
.to_value())
|
.to_value())
|
||||||
}
|
}
|
||||||
Property::Object("used-socket", ..) => {
|
subclass::Property("used-socket", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings
|
Ok(settings
|
||||||
.used_socket
|
.used_socket
|
||||||
|
@ -964,23 +1002,31 @@ impl ObjectImpl<Element> for UdpSrc {
|
||||||
.map(GioSocketWrapper::as_socket)
|
.map(GioSocketWrapper::as_socket)
|
||||||
.to_value())
|
.to_value())
|
||||||
}
|
}
|
||||||
Property::String("context", ..) => {
|
subclass::Property("context", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context.to_value())
|
Ok(settings.context.to_value())
|
||||||
}
|
}
|
||||||
Property::UInt("context-wait", ..) => {
|
subclass::Property("context-wait", ..) => {
|
||||||
let mut settings = self.settings.lock().unwrap();
|
let mut settings = self.settings.lock().unwrap();
|
||||||
Ok(settings.context_wait.to_value())
|
Ok(settings.context_wait.to_value())
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &glib::Object) {
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
|
||||||
|
let element = obj.downcast_ref::<gst::Element>().unwrap();
|
||||||
|
element.add_pad(&self.src_pad).unwrap();
|
||||||
|
::set_element_flags(element, gst::ElementFlags::SOURCE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementImpl<Element> for UdpSrc {
|
impl ElementImpl for UdpSrc {
|
||||||
fn change_state(
|
fn change_state(
|
||||||
&self,
|
&self,
|
||||||
element: &Element,
|
element: &gst::Element,
|
||||||
transition: gst::StateChange,
|
transition: gst::StateChange,
|
||||||
) -> gst::StateChangeReturn {
|
) -> gst::StateChangeReturn {
|
||||||
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
gst_trace!(self.cat, obj: element, "Changing state {:?}", transition);
|
||||||
|
@ -1004,7 +1050,7 @@ impl ElementImpl<Element> for UdpSrc {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret = element.parent_change_state(transition);
|
let mut ret = self.parent_change_state(element, transition);
|
||||||
if ret == gst::StateChangeReturn::Failure {
|
if ret == gst::StateChangeReturn::Failure {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1028,24 +1074,6 @@ impl ElementImpl<Element> for UdpSrc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UdpSrcStatic;
|
|
||||||
|
|
||||||
impl ImplTypeStatic<Element> for UdpSrcStatic {
|
|
||||||
fn get_name(&self) -> &str {
|
|
||||||
"UdpSrc"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(&self, element: &Element) -> Box<ElementImpl<Element>> {
|
|
||||||
UdpSrc::init(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class_init(&self, klass: &mut ElementClass) {
|
|
||||||
UdpSrc::class_init(klass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> {
|
||||||
let udpsrc_static = UdpSrcStatic;
|
gst::Element::register(plugin, "ts-udpsrc", 0, UdpSrc::get_type())
|
||||||
let type_ = register_type(udpsrc_static);
|
|
||||||
gst::Element::register(plugin, "ts-udpsrc", 0, type_)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue