Commit e3902bbb authored by Sebastian Dröge's avatar Sebastian Dröge 🍵

Add decodebin example and add some missing API for it

parent 9b910242
...@@ -20,7 +20,10 @@ name = "examples" ...@@ -20,7 +20,10 @@ name = "examples"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"glib 0.1.3 (git+https://github.com/gtk-rs/glib)", "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 0.1.0",
"gstreamer-sys 0.1.1 (git+https://github.com/sdroege/gstreamer-sys)",
] ]
[[package]] [[package]]
......
...@@ -45,6 +45,7 @@ generate = [ ...@@ -45,6 +45,7 @@ generate = [
"Gst.StreamCollection", "Gst.StreamCollection",
"Gst.StreamType", "Gst.StreamType",
"Gst.StreamFlags", "Gst.StreamFlags",
"Gst.PadLinkReturn",
] ]
manual = [ manual = [
......
...@@ -6,6 +6,12 @@ authors = ["Sebastian Dröge <sebastian@centricular.com>"] ...@@ -6,6 +6,12 @@ authors = ["Sebastian Dröge <sebastian@centricular.com>"]
[dependencies] [dependencies]
glib = { version = "0.1.3", git = "https://github.com/gtk-rs/glib" } glib = { version = "0.1.3", git = "https://github.com/gtk-rs/glib" }
gstreamer = { path = "../gstreamer" } 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]] [[bin]]
name = "launch" name = "launch"
[[bin]]
name = "decodebin"
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);
}
...@@ -28,4 +28,7 @@ fn main() { ...@@ -28,4 +28,7 @@ fn main() {
_ => (), _ => (),
} }
} }
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
} }
...@@ -8,5 +8,5 @@ bitflags = "0.9" ...@@ -8,5 +8,5 @@ bitflags = "0.9"
libc = "0.2" libc = "0.2"
glib-sys = { version = "0.3.4", git = "https://github.com/gtk-rs/sys" } 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" } 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" } glib = { version = "0.1.3", git = "https://github.com/gtk-rs/glib" }
...@@ -361,6 +361,53 @@ impl FromGlib<ffi::GstPadDirection> for PadDirection { ...@@ -361,6 +361,53 @@ impl FromGlib<ffi::GstPadDirection> 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<ffi::GstPadLinkReturn> 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)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum ParseError { pub enum ParseError {
Syntax, Syntax,
......
...@@ -79,6 +79,7 @@ pub use self::enums::FlowReturn; ...@@ -79,6 +79,7 @@ pub use self::enums::FlowReturn;
pub use self::enums::Format; pub use self::enums::Format;
pub use self::enums::LibraryError; pub use self::enums::LibraryError;
pub use self::enums::PadDirection; pub use self::enums::PadDirection;
pub use self::enums::PadLinkReturn;
pub use self::enums::ParseError; pub use self::enums::ParseError;
pub use self::enums::PluginError; pub use self::enums::PluginError;
pub use self::enums::ResourceError; pub use self::enums::ResourceError;
......
...@@ -6,6 +6,7 @@ use FlowReturn; ...@@ -6,6 +6,7 @@ use FlowReturn;
use Format; use Format;
use Object; use Object;
use PadDirection; use PadDirection;
use PadLinkReturn;
use PadTemplate; use PadTemplate;
#[cfg(feature = "v1_10")] #[cfg(feature = "v1_10")]
use Stream; use Stream;
...@@ -52,9 +53,11 @@ impl Pad { ...@@ -52,9 +53,11 @@ impl Pad {
} }
} }
//pub fn link_get_name(ret: /*Ignored*/PadLinkReturn) -> Option<String> { pub fn link_get_name(ret: PadLinkReturn) -> Option<String> {
// unsafe { TODO: call ffi::gst_pad_link_get_name() } unsafe {
//} from_glib_none(ffi::gst_pad_link_get_name(ret.to_glib()))
}
}
} }
unsafe impl Send for Pad {} unsafe impl Send for Pad {}
...@@ -129,9 +132,9 @@ pub trait PadExt { ...@@ -129,9 +132,9 @@ pub trait PadExt {
//fn iterate_internal_links_default<'a, P: IsA<Object> + 'a, Q: Into<Option<&'a P>>>(&self, parent: Q) -> /*Ignored*/Option<Iterator>; //fn iterate_internal_links_default<'a, P: IsA<Object> + 'a, Q: Into<Option<&'a P>>>(&self, parent: Q) -> /*Ignored*/Option<Iterator>;
//fn link<P: IsA<Pad>>(&self, sinkpad: &P) -> /*Ignored*/PadLinkReturn; fn link<P: IsA<Pad>>(&self, sinkpad: &P) -> PadLinkReturn;
//fn link_full<P: IsA<Pad>>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> /*Ignored*/PadLinkReturn; //fn link_full<P: IsA<Pad>>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> PadLinkReturn;
#[cfg(feature = "v1_10")] #[cfg(feature = "v1_10")]
fn link_maybe_ghosting<P: IsA<Pad>>(&self, sink: &P) -> Result<(), glib::error::BoolError>; fn link_maybe_ghosting<P: IsA<Pad>>(&self, sink: &P) -> Result<(), glib::error::BoolError>;
...@@ -407,11 +410,13 @@ impl<O: IsA<Pad> + IsA<glib::object::Object>> PadExt for O { ...@@ -407,11 +410,13 @@ impl<O: IsA<Pad> + IsA<glib::object::Object>> PadExt for O {
// unsafe { TODO: call ffi::gst_pad_iterate_internal_links_default() } // unsafe { TODO: call ffi::gst_pad_iterate_internal_links_default() }
//} //}
//fn link<P: IsA<Pad>>(&self, sinkpad: &P) -> /*Ignored*/PadLinkReturn { fn link<P: IsA<Pad>>(&self, sinkpad: &P) -> PadLinkReturn {
// unsafe { TODO: call ffi::gst_pad_link() } unsafe {
//} from_glib(ffi::gst_pad_link(self.to_glib_none().0, sinkpad.to_glib_none().0))
}
}
//fn link_full<P: IsA<Pad>>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> /*Ignored*/PadLinkReturn { //fn link_full<P: IsA<Pad>>(&self, sinkpad: &P, flags: /*Ignored*/PadLinkCheck) -> PadLinkReturn {
// unsafe { TODO: call ffi::gst_pad_link_full() } // unsafe { TODO: call ffi::gst_pad_link_full() }
//} //}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment