forked from mirrors/gstreamer-rs
Add decodebin example and add some missing API for it
This commit is contained in:
parent
9b91024221
commit
e3902bbbf6
9 changed files with 200 additions and 10 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -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]]
|
||||
|
|
|
@ -45,6 +45,7 @@ generate = [
|
|||
"Gst.StreamCollection",
|
||||
"Gst.StreamType",
|
||||
"Gst.StreamFlags",
|
||||
"Gst.PadLinkReturn",
|
||||
]
|
||||
|
||||
manual = [
|
||||
|
|
|
@ -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
124
examples/src/decodebin.rs
Normal 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);
|
||||
}
|
|
@ -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"
|
|||
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" }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() }
|
||||
//}
|
||||
|
||||
|
|
Loading…
Reference in a new issue