Add decodebin example and add some missing API for it

This commit is contained in:
Sebastian Dröge 2017-07-05 10:40:02 +03:00
parent 9b91024221
commit e3902bbbf6
9 changed files with 200 additions and 10 deletions

3
Cargo.lock generated
View file

@ -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]]

View file

@ -45,6 +45,7 @@ generate = [
"Gst.StreamCollection",
"Gst.StreamType",
"Gst.StreamFlags",
"Gst.PadLinkReturn",
]
manual = [

View file

@ -6,6 +6,12 @@ authors = ["Sebastian Dröge <sebastian@centricular.com>"]
[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"

124
examples/src/decodebin.rs Normal file
View file

@ -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);
}

View file

@ -28,4 +28,7 @@ fn main() {
_ => (),
}
}
let ret = pipeline.set_state(gst::State::Null);
assert_ne!(ret, gst::StateChangeReturn::Failure);
}

View file

@ -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" }

View file

@ -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)]
pub enum ParseError {
Syntax,

View file

@ -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;

View file

@ -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<String> {
// unsafe { TODO: call ffi::gst_pad_link_get_name() }
//}
pub fn link_get_name(ret: PadLinkReturn) -> Option<String> {
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<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")]
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 {
// unsafe { TODO: call ffi::gst_pad_iterate_internal_links_default() }
//}
//fn link<P: IsA<Pad>>(&self, sinkpad: &P) -> /*Ignored*/PadLinkReturn {
// unsafe { TODO: call ffi::gst_pad_link() }
//}
fn link<P: IsA<Pad>>(&self, sinkpad: &P) -> PadLinkReturn {
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() }
//}