mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-10-31 22:59:14 +00:00
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"
|
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 = [
|
||||||
"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>"]
|
||||||
[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"
|
||||||
|
|
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"
|
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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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;
|
||||||
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;
|
||||||
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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 {
|
||||||
|
|
||||||
//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 {
|
||||||
// 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() }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue