From e3902bbbf6af47bb1d595406d96c302880285612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 5 Jul 2017 10:40:02 +0300 Subject: [PATCH] Add decodebin example and add some missing API for it --- Cargo.lock | 3 + Gir_Gst.toml | 1 + examples/Cargo.toml | 6 ++ examples/src/decodebin.rs | 124 ++++++++++++++++++++++++++++++++++++ examples/src/launch.rs | 3 + gstreamer/Cargo.toml | 2 +- gstreamer/src/auto/enums.rs | 47 ++++++++++++++ gstreamer/src/auto/mod.rs | 1 + gstreamer/src/auto/pad.rs | 23 ++++--- 9 files changed, 200 insertions(+), 10 deletions(-) create mode 100644 examples/src/decodebin.rs diff --git a/Cargo.lock b/Cargo.lock index 7b3b73b08..94a432df4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,7 +20,10 @@ name = "examples" version = "0.1.0" dependencies = [ "glib 0.1.3 (git+https://github.com/gtk-rs/glib)", + "glib-sys 0.3.4 (git+https://github.com/gtk-rs/sys)", + "gobject-sys 0.3.4 (git+https://github.com/gtk-rs/sys)", "gstreamer 0.1.0", + "gstreamer-sys 0.1.1 (git+https://github.com/sdroege/gstreamer-sys)", ] [[package]] diff --git a/Gir_Gst.toml b/Gir_Gst.toml index 99005efe2..9a1fa7f53 100644 --- a/Gir_Gst.toml +++ b/Gir_Gst.toml @@ -45,6 +45,7 @@ generate = [ "Gst.StreamCollection", "Gst.StreamType", "Gst.StreamFlags", + "Gst.PadLinkReturn", ] manual = [ diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8f64d184d..f92d3204f 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -6,6 +6,12 @@ authors = ["Sebastian Dröge "] [dependencies] glib = { version = "0.1.3", git = "https://github.com/gtk-rs/glib" } gstreamer = { path = "../gstreamer" } +glib-sys = { version = "0.3.4", git = "https://github.com/gtk-rs/sys" } +gobject-sys = { version = "0.3.4", git = "https://github.com/gtk-rs/sys" } +gstreamer-sys = { version = "0.1.1", git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] } [[bin]] name = "launch" + +[[bin]] +name = "decodebin" diff --git a/examples/src/decodebin.rs b/examples/src/decodebin.rs new file mode 100644 index 000000000..a1a43cd02 --- /dev/null +++ b/examples/src/decodebin.rs @@ -0,0 +1,124 @@ +extern crate gstreamer as gst; +use gst::*; + +extern crate glib; +use glib::translate::{from_glib_none, ToGlibPtr}; + +extern crate gstreamer_sys as gst_ffi; +extern crate gobject_sys as gobject_ffi; + +use std::env; +use std::u64; + +fn main() { + gst::init().unwrap(); + + let args: Vec<_> = env::args().collect(); + let uri: &str = if args.len() == 2 { + args[1].as_ref() + } else { + panic!("Usage: decodebin file_path"); + }; + + let pipeline = gst::Pipeline::new(None); + let src = gst::ElementFactory::make("filesrc", None).unwrap(); + let decodebin = gst::ElementFactory::make("decodebin", None).unwrap(); + + // FIXME: https://github.com/gtk-rs/glib/pull/189 + unsafe { + let uri = Value::from(uri); + gobject_ffi::g_object_set_property(src.to_glib_none().0, "location".to_glib_none().0, uri.to_glib_none().0); + } + + // TODO: Add Bin::add_many(), Element::link_many() + pipeline.add(&src).unwrap(); + pipeline.add(&decodebin).unwrap(); + src.link(&decodebin).unwrap(); + + // Need to move a new reference into the closure + let pipeline_clone = pipeline.clone(); + decodebin.connect_pad_added(move |_, src_pad| { + let ref pipeline = pipeline_clone; + + // FIXME: Needs caps/structure bindings + let (is_audio, is_video) = unsafe { + let caps = gst_ffi::gst_pad_get_current_caps(src_pad.to_glib_none().0); + let structure = gst_ffi::gst_caps_get_structure(caps, 0); + + let name: String = from_glib_none(gst_ffi::gst_structure_get_name(structure)); + + (name.starts_with("audio/"), name.starts_with("video/")) + }; + + if is_audio { + let queue = gst::ElementFactory::make("queue", None).unwrap(); + let convert = gst::ElementFactory::make("audioconvert", None).unwrap(); + let resample = gst::ElementFactory::make("audioresample", None).unwrap(); + let sink = gst::ElementFactory::make("autoaudiosink", None).unwrap(); + pipeline.add(&queue).unwrap(); + pipeline.add(&convert).unwrap(); + pipeline.add(&resample).unwrap(); + pipeline.add(&sink).unwrap(); + + queue.link(&convert).unwrap(); + convert.link(&resample).unwrap(); + resample.link(&sink).unwrap(); + + queue.sync_state_with_parent().unwrap(); + convert.sync_state_with_parent().unwrap(); + resample.sync_state_with_parent().unwrap(); + sink.sync_state_with_parent().unwrap(); + + let sink_pad = queue.get_static_pad("sink").unwrap(); + assert_eq!(src_pad.link(&sink_pad), gst::PadLinkReturn::Ok); + } else if is_video { + let queue = gst::ElementFactory::make("queue", None).unwrap(); + let convert = gst::ElementFactory::make("videoconvert", None).unwrap(); + let scale = gst::ElementFactory::make("videoscale", None).unwrap(); + let sink = gst::ElementFactory::make("autovideosink", None).unwrap(); + pipeline.add(&queue).unwrap(); + pipeline.add(&convert).unwrap(); + pipeline.add(&scale).unwrap(); + pipeline.add(&sink).unwrap(); + + queue.link(&convert).unwrap(); + convert.link(&scale).unwrap(); + scale.link(&sink).unwrap(); + + queue.sync_state_with_parent().unwrap(); + convert.sync_state_with_parent().unwrap(); + scale.sync_state_with_parent().unwrap(); + sink.sync_state_with_parent().unwrap(); + + let sink_pad = queue.get_static_pad("sink").unwrap(); + assert_eq!(src_pad.link(&sink_pad), gst::PadLinkReturn::Ok); + } + }); + + assert_ne!(pipeline.set_state(gst::State::Playing), gst::StateChangeReturn::Failure); + + let bus = pipeline.get_bus().unwrap(); + + loop { + let msg = match bus.timed_pop(u64::MAX) { + None => break, + Some(msg) => msg, + }; + + match msg.view() { + MessageView::Eos => break, + MessageView::Error(err) => { + println!("Error from {}: {} ({:?})", msg.get_src().get_path_string(), + err.get_error(), err.get_debug()); + break; + }, + MessageView::StateChanged(s) => { + println!("State changed from {}: {:?} -> {:?} ({:?})", msg.get_src().get_path_string(), + s.get_old(), s.get_current(), s.get_pending()); + }, + _ => (), + } + } + + assert_ne!(pipeline.set_state(gst::State::Null), gst::StateChangeReturn::Failure); +} diff --git a/examples/src/launch.rs b/examples/src/launch.rs index 59bb0a9cc..56bb92e3f 100644 --- a/examples/src/launch.rs +++ b/examples/src/launch.rs @@ -28,4 +28,7 @@ fn main() { _ => (), } } + + let ret = pipeline.set_state(gst::State::Null); + assert_ne!(ret, gst::StateChangeReturn::Failure); } diff --git a/gstreamer/Cargo.toml b/gstreamer/Cargo.toml index ff31139da..6b96ed520 100644 --- a/gstreamer/Cargo.toml +++ b/gstreamer/Cargo.toml @@ -8,5 +8,5 @@ bitflags = "0.9" libc = "0.2" glib-sys = { version = "0.3.4", git = "https://github.com/gtk-rs/sys" } gobject-sys = { version = "0.3.4", git = "https://github.com/gtk-rs/sys" } -gstreamer-sys = { version = "0.1.1", git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_12"] } +gstreamer-sys = { version = "0.1.1", git = "https://github.com/sdroege/gstreamer-sys", features = ["v1_8"] } glib = { version = "0.1.3", git = "https://github.com/gtk-rs/glib" } diff --git a/gstreamer/src/auto/enums.rs b/gstreamer/src/auto/enums.rs index 0c537acfb..709016270 100644 --- a/gstreamer/src/auto/enums.rs +++ b/gstreamer/src/auto/enums.rs @@ -361,6 +361,53 @@ impl FromGlib for PadDirection { } } +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum PadLinkReturn { + Ok, + WrongHierarchy, + WasLinked, + WrongDirection, + Noformat, + Nosched, + Refused, + #[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl ToGlib for PadLinkReturn { + type GlibType = ffi::GstPadLinkReturn; + + fn to_glib(&self) -> ffi::GstPadLinkReturn { + match *self { + PadLinkReturn::Ok => ffi::GST_PAD_LINK_OK, + PadLinkReturn::WrongHierarchy => ffi::GST_PAD_LINK_WRONG_HIERARCHY, + PadLinkReturn::WasLinked => ffi::GST_PAD_LINK_WAS_LINKED, + PadLinkReturn::WrongDirection => ffi::GST_PAD_LINK_WRONG_DIRECTION, + PadLinkReturn::Noformat => ffi::GST_PAD_LINK_NOFORMAT, + PadLinkReturn::Nosched => ffi::GST_PAD_LINK_NOSCHED, + PadLinkReturn::Refused => ffi::GST_PAD_LINK_REFUSED, + PadLinkReturn::__Unknown(value) => unsafe{std::mem::transmute(value)} + } + } +} + +#[doc(hidden)] +impl FromGlib for PadLinkReturn { + fn from_glib(value: ffi::GstPadLinkReturn) -> Self { + match value as i32 { + 0 => PadLinkReturn::Ok, + -1 => PadLinkReturn::WrongHierarchy, + -2 => PadLinkReturn::WasLinked, + -3 => PadLinkReturn::WrongDirection, + -4 => PadLinkReturn::Noformat, + -5 => PadLinkReturn::Nosched, + -6 => PadLinkReturn::Refused, + value => PadLinkReturn::__Unknown(value), + } + } +} + #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum ParseError { Syntax, diff --git a/gstreamer/src/auto/mod.rs b/gstreamer/src/auto/mod.rs index c637c9a4b..913951ba8 100644 --- a/gstreamer/src/auto/mod.rs +++ b/gstreamer/src/auto/mod.rs @@ -79,6 +79,7 @@ pub use self::enums::FlowReturn; pub use self::enums::Format; pub use self::enums::LibraryError; pub use self::enums::PadDirection; +pub use self::enums::PadLinkReturn; pub use self::enums::ParseError; pub use self::enums::PluginError; pub use self::enums::ResourceError; diff --git a/gstreamer/src/auto/pad.rs b/gstreamer/src/auto/pad.rs index 0298b82ac..bad553a50 100644 --- a/gstreamer/src/auto/pad.rs +++ b/gstreamer/src/auto/pad.rs @@ -6,6 +6,7 @@ use FlowReturn; use Format; use Object; use PadDirection; +use PadLinkReturn; use PadTemplate; #[cfg(feature = "v1_10")] use Stream; @@ -52,9 +53,11 @@ impl Pad { } } - //pub fn link_get_name(ret: /*Ignored*/PadLinkReturn) -> Option { - // unsafe { TODO: call ffi::gst_pad_link_get_name() } - //} + pub fn link_get_name(ret: PadLinkReturn) -> Option { + unsafe { + from_glib_none(ffi::gst_pad_link_get_name(ret.to_glib())) + } + } } unsafe impl Send for Pad {} @@ -129,9 +132,9 @@ pub trait PadExt { //fn iterate_internal_links_default<'a, P: IsA + 'a, Q: Into>>(&self, parent: Q) -> /*Ignored*/Option; - //fn link>(&self, sinkpad: &P) -> /*Ignored*/PadLinkReturn; + fn link>(&self, sinkpad: &P) -> PadLinkReturn; - //fn link_full>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> /*Ignored*/PadLinkReturn; + //fn link_full>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> PadLinkReturn; #[cfg(feature = "v1_10")] fn link_maybe_ghosting>(&self, sink: &P) -> Result<(), glib::error::BoolError>; @@ -407,11 +410,13 @@ impl + IsA> PadExt for O { // unsafe { TODO: call ffi::gst_pad_iterate_internal_links_default() } //} - //fn link>(&self, sinkpad: &P) -> /*Ignored*/PadLinkReturn { - // unsafe { TODO: call ffi::gst_pad_link() } - //} + fn link>(&self, sinkpad: &P) -> PadLinkReturn { + unsafe { + from_glib(ffi::gst_pad_link(self.to_glib_none().0, sinkpad.to_glib_none().0)) + } + } - //fn link_full>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> /*Ignored*/PadLinkReturn { + //fn link_full>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> PadLinkReturn { // unsafe { TODO: call ffi::gst_pad_link_full() } //}