forked from mirrors/gstreamer-rs
elementfactory: Change make()
/ create()
to builders and keep the old variants as create_with_name()
/ make_with_name()
As a side-effect, this also now includes the element factory name in the error messages instead of giving the same error string for every factory. Partially fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/318 Also let them all go through the same, single object construction code.
This commit is contained in:
parent
7ad75d4b1f
commit
7423b1dea6
46 changed files with 723 additions and 518 deletions
|
@ -23,10 +23,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -40,9 +36,8 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
gst::init()?;
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("audiotestsrc", None)
|
||||
.map_err(|_| MissingElement("audiotestsrc"))?;
|
||||
let sink = gst::ElementFactory::make("appsink", None).map_err(|_| MissingElement("appsink"))?;
|
||||
let src = gst::ElementFactory::make("audiotestsrc").build()?;
|
||||
let sink = gst::ElementFactory::make("appsink").build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &sink])?;
|
||||
src.link(&sink)?;
|
||||
|
|
|
@ -18,10 +18,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -38,11 +34,9 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
gst::init()?;
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("appsrc", None).map_err(|_| MissingElement("appsrc"))?;
|
||||
let videoconvert = gst::ElementFactory::make("videoconvert", None)
|
||||
.map_err(|_| MissingElement("videoconvert"))?;
|
||||
let sink = gst::ElementFactory::make("autovideosink", None)
|
||||
.map_err(|_| MissingElement("autovideosink"))?;
|
||||
let src = gst::ElementFactory::make("appsrc").build()?;
|
||||
let videoconvert = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let sink = gst::ElementFactory::make("autovideosink").build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &videoconvert, &sink])?;
|
||||
gst::Element::link_many(&[&src, &videoconvert, &sink])?;
|
||||
|
|
|
@ -567,12 +567,17 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
|
||||
// Create our pipeline with the compositor and two input streams.
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src1 = gst::ElementFactory::make("videotestsrc", None).context("Creating videotestsrc")?;
|
||||
let src2 = gst::ElementFactory::make("videotestsrc", None).context("Creating videotestsrc")?;
|
||||
let src1 = gst::ElementFactory::make("videotestsrc")
|
||||
.property_from_str("pattern", "ball")
|
||||
.build()?;
|
||||
let src2 = gst::ElementFactory::make("videotestsrc")
|
||||
.property_from_str("pattern", "smpte")
|
||||
.build()?;
|
||||
let comp = cairo_compositor::CairoCompositor::new(None);
|
||||
let conv = gst::ElementFactory::make("videoconvert", None).context("Creating videoconvert")?;
|
||||
let sink =
|
||||
gst::ElementFactory::make("autovideosink", None).context("Creating autovideosink")?;
|
||||
let conv = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let sink = gst::ElementFactory::make("autovideosink").build()?;
|
||||
|
||||
comp.set_property("background-color", 0xff_33_33_33u32);
|
||||
|
||||
pipeline.add_many(&[&src1, &src2, comp.upcast_ref(), &conv, &sink])?;
|
||||
|
||||
|
@ -603,11 +608,6 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
.context("Linking converter")?;
|
||||
conv.link(&sink).context("Linking sink")?;
|
||||
|
||||
src1.set_property_from_str("pattern", "ball");
|
||||
src2.set_property_from_str("pattern", "smpte");
|
||||
|
||||
comp.set_property("background-color", 0xff_33_33_33u32);
|
||||
|
||||
// Change positions etc of both inputs based on a timer
|
||||
let xmax = 1280.0 - 320.0f64;
|
||||
let ymax = 720.0 - 240.0f64;
|
||||
|
|
|
@ -46,7 +46,6 @@ mod custom_meta {
|
|||
}
|
||||
|
||||
// Retrieve the stored label.
|
||||
#[doc(alias = "get_label")]
|
||||
pub fn label(&self) -> &str {
|
||||
self.0.label.as_str()
|
||||
}
|
||||
|
@ -183,11 +182,13 @@ fn example_main() {
|
|||
|
||||
// This creates a pipeline with appsrc and appsink.
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let appsrc = gst::ElementFactory::make("appsrc", None)
|
||||
let appsrc = gst::ElementFactory::make("appsrc")
|
||||
.build()
|
||||
.unwrap()
|
||||
.downcast::<gst_app::AppSrc>()
|
||||
.unwrap();
|
||||
let appsink = gst::ElementFactory::make("appsink", None)
|
||||
let appsink = gst::ElementFactory::make("appsink")
|
||||
.build()
|
||||
.unwrap()
|
||||
.downcast::<gst_app::AppSink>()
|
||||
.unwrap();
|
||||
|
|
|
@ -42,10 +42,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -71,12 +67,10 @@ fn example_main() -> Result<(), Error> {
|
|||
};
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("filesrc", None).map_err(|_| MissingElement("filesrc"))?;
|
||||
let decodebin =
|
||||
gst::ElementFactory::make("decodebin", None).map_err(|_| MissingElement("decodebin"))?;
|
||||
|
||||
// Tell the filesrc what file to load
|
||||
src.set_property("location", uri);
|
||||
let src = gst::ElementFactory::make("filesrc")
|
||||
.property("location", uri)
|
||||
.build()?;
|
||||
let decodebin = gst::ElementFactory::make("decodebin").build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &decodebin])?;
|
||||
gst::Element::link_many(&[&src, &decodebin])?;
|
||||
|
@ -135,14 +129,10 @@ fn example_main() -> Result<(), Error> {
|
|||
if is_audio {
|
||||
// decodebin found a raw audiostream, so we build the follow-up pipeline to
|
||||
// play it on the default audio playback device (using autoaudiosink).
|
||||
let queue = gst::ElementFactory::make("queue", None)
|
||||
.map_err(|_| MissingElement("queue"))?;
|
||||
let convert = gst::ElementFactory::make("audioconvert", None)
|
||||
.map_err(|_| MissingElement("audioconvert"))?;
|
||||
let resample = gst::ElementFactory::make("audioresample", None)
|
||||
.map_err(|_| MissingElement("audioresample"))?;
|
||||
let sink = gst::ElementFactory::make("autoaudiosink", None)
|
||||
.map_err(|_| MissingElement("autoaudiosink"))?;
|
||||
let queue = gst::ElementFactory::make("queue").build()?;
|
||||
let convert = gst::ElementFactory::make("audioconvert").build()?;
|
||||
let resample = gst::ElementFactory::make("audioresample").build()?;
|
||||
let sink = gst::ElementFactory::make("autoaudiosink").build()?;
|
||||
|
||||
let elements = &[&queue, &convert, &resample, &sink];
|
||||
pipeline.add_many(elements)?;
|
||||
|
@ -163,14 +153,10 @@ fn example_main() -> Result<(), Error> {
|
|||
} else if is_video {
|
||||
// decodebin found a raw videostream, so we build the follow-up pipeline to
|
||||
// display it using the autovideosink.
|
||||
let queue = gst::ElementFactory::make("queue", None)
|
||||
.map_err(|_| MissingElement("queue"))?;
|
||||
let convert = gst::ElementFactory::make("videoconvert", None)
|
||||
.map_err(|_| MissingElement("videoconvert"))?;
|
||||
let scale = gst::ElementFactory::make("videoscale", None)
|
||||
.map_err(|_| MissingElement("videoscale"))?;
|
||||
let sink = gst::ElementFactory::make("autovideosink", None)
|
||||
.map_err(|_| MissingElement("autovideosink"))?;
|
||||
let queue = gst::ElementFactory::make("queue").build()?;
|
||||
let convert = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let scale = gst::ElementFactory::make("videoscale").build()?;
|
||||
let sink = gst::ElementFactory::make("autovideosink").build()?;
|
||||
|
||||
let elements = &[&queue, &convert, &scale, &sink];
|
||||
pipeline.add_many(elements)?;
|
||||
|
|
|
@ -26,10 +26,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -90,15 +86,13 @@ fn example_main() -> Result<(), Error> {
|
|||
};
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("uridecodebin", None)
|
||||
.map_err(|_| MissingElement("uridecodebin"))?;
|
||||
let encodebin =
|
||||
gst::ElementFactory::make("encodebin", None).map_err(|_| MissingElement("encodebin"))?;
|
||||
let sink =
|
||||
gst::ElementFactory::make("filesink", None).map_err(|_| MissingElement("filesink"))?;
|
||||
|
||||
src.set_property("uri", uri);
|
||||
sink.set_property("location", output_file);
|
||||
let src = gst::ElementFactory::make("uridecodebin")
|
||||
.property("uri", uri)
|
||||
.build()?;
|
||||
let encodebin = gst::ElementFactory::make("encodebin").build()?;
|
||||
let sink = gst::ElementFactory::make("filesink")
|
||||
.property("location", output_file)
|
||||
.build()?;
|
||||
|
||||
// Configure the encodebin.
|
||||
// Here we tell the bin what format we expect it to create at its output.
|
||||
|
@ -157,12 +151,9 @@ fn example_main() -> Result<(), Error> {
|
|||
|
||||
let link_to_encodebin = |is_audio, is_video| -> Result<(), Error> {
|
||||
if is_audio {
|
||||
let queue = gst::ElementFactory::make("queue", None)
|
||||
.map_err(|_| MissingElement("queue"))?;
|
||||
let convert = gst::ElementFactory::make("audioconvert", None)
|
||||
.map_err(|_| MissingElement("audioconvert"))?;
|
||||
let resample = gst::ElementFactory::make("audioresample", None)
|
||||
.map_err(|_| MissingElement("audioresample"))?;
|
||||
let queue = gst::ElementFactory::make("queue").build()?;
|
||||
let convert = gst::ElementFactory::make("audioconvert").build()?;
|
||||
let resample = gst::ElementFactory::make("audioresample").build()?;
|
||||
|
||||
let elements = &[&queue, &convert, &resample];
|
||||
pipeline
|
||||
|
@ -188,12 +179,9 @@ fn example_main() -> Result<(), Error> {
|
|||
let sink_pad = queue.static_pad("sink").expect("queue has no sinkpad");
|
||||
dbin_src_pad.link(&sink_pad)?;
|
||||
} else if is_video {
|
||||
let queue = gst::ElementFactory::make("queue", None)
|
||||
.map_err(|_| MissingElement("queue"))?;
|
||||
let convert = gst::ElementFactory::make("videoconvert", None)
|
||||
.map_err(|_| MissingElement("videoconvert"))?;
|
||||
let scale = gst::ElementFactory::make("videoscale", None)
|
||||
.map_err(|_| MissingElement("videoscale"))?;
|
||||
let queue = gst::ElementFactory::make("queue").build()?;
|
||||
let convert = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let scale = gst::ElementFactory::make("videoscale").build()?;
|
||||
|
||||
let elements = &[&queue, &convert, &scale];
|
||||
pipeline
|
||||
|
|
|
@ -31,10 +31,6 @@ use std::{
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -51,13 +47,11 @@ fn create_receiver_pipeline(
|
|||
let caps = video_info.to_caps()?;
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("appsrc", None).map_err(|_| MissingElement("appsrc"))?;
|
||||
let src = gst::ElementFactory::make("appsrc").build()?;
|
||||
let filter = video_filter::FdMemoryFadeInVideoFilter::default().upcast::<gst::Element>();
|
||||
let convert = gst::ElementFactory::make("videoconvert", None)
|
||||
.map_err(|_| MissingElement("videoconvert"))?;
|
||||
let queue = gst::ElementFactory::make("queue", None).map_err(|_| MissingElement("queue"))?;
|
||||
let sink = gst::ElementFactory::make("autovideosink", None)
|
||||
.map_err(|_| MissingElement("autovideosink"))?;
|
||||
let convert = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let queue = gst::ElementFactory::make("queue").build()?;
|
||||
let sink = gst::ElementFactory::make("autovideosink").build()?;
|
||||
|
||||
src.downcast_ref::<gst_app::AppSrc>()
|
||||
.ok_or_else(|| anyhow::anyhow!("is not a appsrc"))?
|
||||
|
@ -131,11 +125,10 @@ fn create_sender_pipeline(
|
|||
let caps = video_info.to_caps()?;
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None)
|
||||
.map_err(|_| MissingElement("videotestsrc"))?;
|
||||
let sink = gst::ElementFactory::make("appsink", None).map_err(|_| MissingElement("appsink"))?;
|
||||
|
||||
src.set_property("num-buffers", 250i32);
|
||||
let src = gst::ElementFactory::make("videotestsrc")
|
||||
.property("num-buffers", 250i32)
|
||||
.build()?;
|
||||
let sink = gst::ElementFactory::make("appsink").build()?;
|
||||
|
||||
sink.downcast_ref::<gst_app::AppSink>()
|
||||
.ok_or_else(|| anyhow::anyhow!("is not a appsink"))?
|
||||
|
|
|
@ -20,20 +20,22 @@ use std::cell::RefCell;
|
|||
|
||||
fn create_ui(app: >k::Application) {
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None).unwrap();
|
||||
let src = gst::ElementFactory::make("videotestsrc").build().unwrap();
|
||||
// Create the gtk sink and retrieve the widget from it. The sink element will be used
|
||||
// in the pipeline, and the widget will be embedded in our gui.
|
||||
// Gstreamer then displays frames in the gtk widget.
|
||||
// First, we try to use the OpenGL version - and if that fails, we fall back to non-OpenGL.
|
||||
let (sink, widget) = if let Ok(gtkglsink) = gst::ElementFactory::make("gtkglsink", None) {
|
||||
let (sink, widget) = if let Ok(gtkglsink) = gst::ElementFactory::make("gtkglsink").build() {
|
||||
// Using the OpenGL widget succeeded, so we are in for a nice playback experience with
|
||||
// low cpu usage. :)
|
||||
// The gtkglsink essentially allocates an OpenGL texture on the GPU, that it will display.
|
||||
// Now we create the glsinkbin element, which is responsible for conversions and for uploading
|
||||
// video frames to our texture (if they are not already in the GPU). Now we tell the OpenGL-sink
|
||||
// about our gtkglsink element, form where it will retrieve the OpenGL texture to fill.
|
||||
let glsinkbin = gst::ElementFactory::make("glsinkbin", None).unwrap();
|
||||
glsinkbin.set_property("sink", >kglsink);
|
||||
let glsinkbin = gst::ElementFactory::make("glsinkbin")
|
||||
.property("sink", >kglsink)
|
||||
.build()
|
||||
.unwrap();
|
||||
// The gtkglsink creates the gtk widget for us. This is accessible through a property.
|
||||
// So we get it and use it later to add it to our gui.
|
||||
let widget = gtkglsink.property::<gtk::Widget>("widget");
|
||||
|
@ -42,7 +44,7 @@ fn create_ui(app: >k::Application) {
|
|||
// Unfortunately, using the OpenGL widget didn't work out, so we will have to render
|
||||
// our frames manually, using the CPU. An example why this may fail is, when
|
||||
// the PC doesn't have proper graphics drivers installed.
|
||||
let sink = gst::ElementFactory::make("gtksink", None).unwrap();
|
||||
let sink = gst::ElementFactory::make("gtksink").build().unwrap();
|
||||
// The gtksink creates the gtk widget for us. This is accessible through a property.
|
||||
// So we get it and use it later to add it to our gui.
|
||||
let widget = sink.property::<gtk::Widget>("widget");
|
||||
|
|
|
@ -34,7 +34,7 @@ fn create_video_sink() -> gst::Element {
|
|||
// When we are on linux with the Xorg display server, we use the
|
||||
// X11 protocol's XV extension, which allows to overlay regions
|
||||
// with video streams. For this, we use the xvimagesink element.
|
||||
gst::ElementFactory::make("xvimagesink", None).unwrap()
|
||||
gst::ElementFactory::make("xvimagesink").build().unwrap()
|
||||
}
|
||||
#[cfg(all(target_os = "linux", feature = "gtkvideooverlay-x11"))]
|
||||
fn set_window_handle(video_overlay: &gst_video::VideoOverlay, gdk_window: &gdk::Window) {
|
||||
|
@ -68,7 +68,7 @@ fn set_window_handle(video_overlay: &gst_video::VideoOverlay, gdk_window: &gdk::
|
|||
fn create_video_sink() -> gst::Element {
|
||||
// On Mac, this is done by overlaying a window region with an
|
||||
// OpenGL-texture, using the glimagesink element.
|
||||
gst::ElementFactory::make("glimagesink", None).unwrap()
|
||||
gst::ElementFactory::make("glimagesink").build().unwrap()
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "macos", feature = "gtkvideooverlay-quartz"))]
|
||||
|
@ -102,7 +102,7 @@ fn set_window_handle(video_overlay: &gst_video::VideoOverlay, gdk_window: &gdk::
|
|||
|
||||
fn create_ui(app: >k::Application) {
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None).unwrap();
|
||||
let src = gst::ElementFactory::make("videotestsrc").build().unwrap();
|
||||
|
||||
// Since using the window system to overlay our gui window is making
|
||||
// direct contact with the windowing system, this is highly platform-
|
||||
|
|
|
@ -13,7 +13,7 @@ fn example_main() {
|
|||
// Create and use an identity element here.
|
||||
// This element does nothing, really. We also never add it to a pipeline.
|
||||
// We just want to iterate the identity element's pads.
|
||||
let identity = gst::ElementFactory::make("identity", None).unwrap();
|
||||
let identity = gst::ElementFactory::make("identity").build().unwrap();
|
||||
// Get an iterator over all pads of the identity-element.
|
||||
let mut iter = identity.iterate_pads();
|
||||
loop {
|
||||
|
|
|
@ -21,10 +21,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -58,19 +54,14 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
gst::init()?;
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None)
|
||||
.map_err(|_| MissingElement("videotestsrc"))?;
|
||||
let overlay = gst::ElementFactory::make("overlaycomposition", None)
|
||||
.map_err(|_| MissingElement("overlaycomposition"))?;
|
||||
let capsfilter =
|
||||
gst::ElementFactory::make("capsfilter", None).map_err(|_| MissingElement("capsfilter"))?;
|
||||
let videoconvert = gst::ElementFactory::make("videoconvert", None)
|
||||
.map_err(|_| MissingElement("videoconvert"))?;
|
||||
let sink = gst::ElementFactory::make("autovideosink", None)
|
||||
.map_err(|_| MissingElement("autovideosink"))?;
|
||||
|
||||
pipeline.add_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
gst::Element::link_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
// The videotestsrc supports multiple test patterns. In this example, we will use the
|
||||
// pattern with a white ball moving around the video's center point.
|
||||
let src = gst::ElementFactory::make("videotestsrc")
|
||||
.property_from_str("pattern", "ball")
|
||||
.build()?;
|
||||
|
||||
let overlay = gst::ElementFactory::make("overlaycomposition").build()?;
|
||||
|
||||
// Plug in a capsfilter element that will force the videotestsrc and the overlay to work
|
||||
// with images of the size 800x800, and framerate of 15 fps, since my laptop struggles
|
||||
|
@ -80,11 +71,15 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
.height(800)
|
||||
.framerate((15, 1).into())
|
||||
.build();
|
||||
capsfilter.set_property("caps", &caps);
|
||||
let capsfilter = gst::ElementFactory::make("capsfilter")
|
||||
.property("caps", &caps)
|
||||
.build()?;
|
||||
|
||||
// The videotestsrc supports multiple test patterns. In this example, we will use the
|
||||
// pattern with a white ball moving around the video's center point.
|
||||
src.set_property_from_str("pattern", "ball");
|
||||
let videoconvert = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let sink = gst::ElementFactory::make("autovideosink").build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
gst::Element::link_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
|
||||
// The PangoFontMap represents the set of fonts available for a particular rendering system.
|
||||
let fontmap = pangocairo::FontMap::new();
|
||||
|
|
|
@ -24,10 +24,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -61,19 +57,12 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
gst::init()?;
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None)
|
||||
.map_err(|_| MissingElement("videotestsrc"))?;
|
||||
let overlay = gst::ElementFactory::make("cairooverlay", None)
|
||||
.map_err(|_| MissingElement("cairooverlay"))?;
|
||||
let capsfilter =
|
||||
gst::ElementFactory::make("capsfilter", None).map_err(|_| MissingElement("capsfilter"))?;
|
||||
let videoconvert = gst::ElementFactory::make("videoconvert", None)
|
||||
.map_err(|_| MissingElement("videoconvert"))?;
|
||||
let sink = gst::ElementFactory::make("autovideosink", None)
|
||||
.map_err(|_| MissingElement("autovideosink"))?;
|
||||
|
||||
pipeline.add_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
gst::Element::link_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
let src = gst::ElementFactory::make("videotestsrc")
|
||||
// The videotestsrc supports multiple test patterns. In this example, we will use the
|
||||
// pattern with a white ball moving around the video's center point.
|
||||
.property_from_str("pattern", "ball")
|
||||
.build()?;
|
||||
let overlay = gst::ElementFactory::make("cairooverlay").build()?;
|
||||
|
||||
// Plug in a capsfilter element that will force the videotestsrc and the cairooverlay to work
|
||||
// with images of the size 800x800.
|
||||
|
@ -81,11 +70,15 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
.width(800)
|
||||
.height(800)
|
||||
.build();
|
||||
capsfilter.set_property("caps", &caps);
|
||||
let capsfilter = gst::ElementFactory::make("capsfilter")
|
||||
.property("caps", &caps)
|
||||
.build()?;
|
||||
|
||||
// The videotestsrc supports multiple test patterns. In this example, we will use the
|
||||
// pattern with a white ball moving around the video's center point.
|
||||
src.set_property_from_str("pattern", "ball");
|
||||
let videoconvert = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let sink = gst::ElementFactory::make("autovideosink").build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
gst::Element::link_many(&[&src, &overlay, &capsfilter, &videoconvert, &sink])?;
|
||||
|
||||
// The PangoFontMap represents the set of fonts available for a particular rendering system.
|
||||
let fontmap = pangocairo::FontMap::new();
|
||||
|
|
|
@ -28,8 +28,10 @@ fn example_main() {
|
|||
};
|
||||
|
||||
// Create a new playbin element, and tell it what uri to play back.
|
||||
let playbin = gst::ElementFactory::make("playbin", None).unwrap();
|
||||
playbin.set_property("uri", uri);
|
||||
let playbin = gst::ElementFactory::make("playbin")
|
||||
.property("uri", uri)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// For flags handling
|
||||
// With flags, one can configure playbin's behavior such as whether it
|
||||
|
|
|
@ -9,10 +9,6 @@ mod examples_common;
|
|||
use anyhow::Error;
|
||||
use derive_more::{Display, Error};
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "No such pad {} in {}", _0, _1)]
|
||||
struct NoSuchPad(#[error(not(source))] &'static str, String);
|
||||
|
@ -34,17 +30,6 @@ struct ErrorMessage {
|
|||
source: glib::Error,
|
||||
}
|
||||
|
||||
fn make_element(
|
||||
factory_name: &'static str,
|
||||
element_name: Option<&str>,
|
||||
) -> Result<gst::Element, Error> {
|
||||
match gst::ElementFactory::make(factory_name, element_name) {
|
||||
Ok(elem) => Ok(elem),
|
||||
Err(_) => Err(Error::from(MissingElement(factory_name))),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "get_static_pad")]
|
||||
fn static_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad, Error> {
|
||||
match element.static_pad(pad_name) {
|
||||
Some(pad) => Ok(pad),
|
||||
|
@ -55,7 +40,6 @@ fn static_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "get_request_pad")]
|
||||
fn request_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad, Error> {
|
||||
match element.request_pad_simple(pad_name) {
|
||||
Some(pad) => Ok(pad),
|
||||
|
@ -83,11 +67,11 @@ fn connect_rtpbin_srcpad(src_pad: &gst::Pad, sink: &gst::Element) -> Result<(),
|
|||
}
|
||||
|
||||
fn make_fec_decoder(rtpbin: &gst::Element, sess_id: u32) -> Result<gst::Element, Error> {
|
||||
let fecdec = make_element("rtpulpfecdec", None)?;
|
||||
let internal_storage = rtpbin.emit_by_name::<glib::Object>("get-internal-storage", &[&sess_id]);
|
||||
|
||||
fecdec.set_property("storage", &internal_storage);
|
||||
fecdec.set_property("pt", 100u32);
|
||||
let fecdec = gst::ElementFactory::make("rtpulpfecdec")
|
||||
.property("storage", &internal_storage)
|
||||
.property("pt", 100u32)
|
||||
.build()?;
|
||||
|
||||
Ok(fecdec)
|
||||
}
|
||||
|
@ -104,33 +88,54 @@ fn example_main() -> Result<(), Error> {
|
|||
let drop_probability = args[2].parse::<f32>()?;
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = make_element("udpsrc", None)?;
|
||||
let netsim = make_element("netsim", None)?;
|
||||
let rtpbin = make_element("rtpbin", None)?;
|
||||
let depay = make_element("rtpvp8depay", None)?;
|
||||
let dec = make_element("vp8dec", None)?;
|
||||
let conv = make_element("videoconvert", None)?;
|
||||
let scale = make_element("videoscale", None)?;
|
||||
let filter = make_element("capsfilter", None)?;
|
||||
|
||||
let rtp_caps = gst::Caps::builder("application/x-rtp")
|
||||
.field("clock-rate", 90000i32)
|
||||
.build();
|
||||
|
||||
let video_caps = gst_video::VideoCapsBuilder::new()
|
||||
.width(1920)
|
||||
.height(1080)
|
||||
.build();
|
||||
|
||||
let src = gst::ElementFactory::make("udpsrc")
|
||||
.property("address", "127.0.0.1")
|
||||
.property("caps", &rtp_caps)
|
||||
.build()?;
|
||||
let netsim = gst::ElementFactory::make("netsim")
|
||||
.property("drop-probability", drop_probability)
|
||||
.build()?;
|
||||
let rtpbin = gst::ElementFactory::make("rtpbin")
|
||||
.property("do-lost", true)
|
||||
.build()?;
|
||||
let depay = gst::ElementFactory::make("rtpvp8depay").build()?;
|
||||
let dec = gst::ElementFactory::make("vp8dec").build()?;
|
||||
let conv = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let scale = gst::ElementFactory::make("videoscale").build()?;
|
||||
let filter = gst::ElementFactory::make("capsfilter")
|
||||
.property("caps", &video_caps)
|
||||
.build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &netsim, &rtpbin, &depay, &dec, &conv, &scale, &filter])?;
|
||||
gst::Element::link_many(&[&depay, &dec, &conv, &scale, &filter])?;
|
||||
|
||||
match args[1].as_str() {
|
||||
"play" => {
|
||||
let sink = make_element("autovideosink", None)?;
|
||||
let sink = gst::ElementFactory::make("autovideosink").build()?;
|
||||
pipeline.add(&sink)?;
|
||||
filter.link(&sink)?;
|
||||
}
|
||||
"record" => {
|
||||
let enc = make_element("x264enc", None)?;
|
||||
let mux = make_element("matroskamux", None)?;
|
||||
let sink = make_element("filesink", None)?;
|
||||
let enc = gst::ElementFactory::make("x264enc")
|
||||
.property_from_str("tune", "zerolatency")
|
||||
.build()?;
|
||||
let mux = gst::ElementFactory::make("matroskamux").build()?;
|
||||
let sink = gst::ElementFactory::make("filesink")
|
||||
.property("location", "out.mkv")
|
||||
.build()?;
|
||||
|
||||
pipeline.add_many(&[&enc, &mux, &sink])?;
|
||||
gst::Element::link_many(&[&filter, &enc, &mux, &sink])?;
|
||||
sink.set_property("location", "out.mkv");
|
||||
enc.set_property_from_str("tune", "zerolatency");
|
||||
eprintln!("Recording to out.mkv");
|
||||
}
|
||||
_ => return Err(Error::from(UsageError(args[0].clone()))),
|
||||
|
@ -218,21 +223,6 @@ fn example_main() -> Result<(), Error> {
|
|||
}
|
||||
});
|
||||
|
||||
let rtp_caps = gst::Caps::builder("application/x-rtp")
|
||||
.field("clock-rate", 90000i32)
|
||||
.build();
|
||||
|
||||
let video_caps = gst_video::VideoCapsBuilder::new()
|
||||
.width(1920)
|
||||
.height(1080)
|
||||
.build();
|
||||
|
||||
src.set_property("address", "127.0.0.1");
|
||||
src.set_property("caps", &rtp_caps);
|
||||
netsim.set_property("drop-probability", drop_probability);
|
||||
rtpbin.set_property("do-lost", true);
|
||||
filter.set_property("caps", &video_caps);
|
||||
|
||||
let bus = pipeline
|
||||
.bus()
|
||||
.expect("Pipeline without bus. Shouldn't happen!");
|
||||
|
|
|
@ -9,10 +9,6 @@ use std::env;
|
|||
use anyhow::Error;
|
||||
use derive_more::{Display, Error};
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "No such pad {} in {}", _0, _1)]
|
||||
struct NoSuchPad(&'static str, String);
|
||||
|
@ -30,17 +26,6 @@ struct ErrorMessage {
|
|||
source: glib::Error,
|
||||
}
|
||||
|
||||
fn make_element(
|
||||
factory_name: &'static str,
|
||||
element_name: Option<&str>,
|
||||
) -> Result<gst::Element, Error> {
|
||||
match gst::ElementFactory::make(factory_name, element_name) {
|
||||
Ok(elem) => Ok(elem),
|
||||
Err(_) => Err(Error::from(MissingElement(factory_name))),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "get_static_pad")]
|
||||
fn static_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad, Error> {
|
||||
match element.static_pad(pad_name) {
|
||||
Some(pad) => Ok(pad),
|
||||
|
@ -51,7 +36,6 @@ fn static_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "get_request_pad")]
|
||||
fn request_pad(element: &gst::Element, pad_name: &'static str) -> Result<gst::Pad, Error> {
|
||||
match element.request_pad_simple(pad_name) {
|
||||
Some(pad) => Ok(pad),
|
||||
|
@ -70,11 +54,11 @@ fn connect_decodebin_pad(src_pad: &gst::Pad, sink: &gst::Element) -> Result<(),
|
|||
}
|
||||
|
||||
fn make_fec_encoder(fec_percentage: u32) -> Result<gst::Element, Error> {
|
||||
let fecenc = make_element("rtpulpfecenc", None)?;
|
||||
|
||||
fecenc.set_property("pt", 100u32);
|
||||
fecenc.set_property("multipacket", true);
|
||||
fecenc.set_property("percentage", fec_percentage);
|
||||
let fecenc = gst::ElementFactory::make("rtpulpfecenc")
|
||||
.property("pt", 100u32)
|
||||
.property("multipacket", true)
|
||||
.property("percentage", fec_percentage)
|
||||
.build()?;
|
||||
|
||||
Ok(fecenc)
|
||||
}
|
||||
|
@ -91,15 +75,31 @@ fn example_main() -> Result<(), Error> {
|
|||
let uri = &args[1];
|
||||
let fec_percentage = args[2].parse::<u32>()?;
|
||||
|
||||
let video_caps = gst::Caps::builder("video/x-raw").build();
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = make_element("uridecodebin", None)?;
|
||||
let conv = make_element("videoconvert", None)?;
|
||||
let q1 = make_element("queue", None)?;
|
||||
let enc = make_element("vp8enc", None)?;
|
||||
let q2 = make_element("queue", None)?;
|
||||
let pay = make_element("rtpvp8pay", None)?;
|
||||
let rtpbin = make_element("rtpbin", None)?;
|
||||
let sink = make_element("udpsink", None)?;
|
||||
let src = gst::ElementFactory::make("uridecodebin")
|
||||
.property_from_str("pattern", "ball")
|
||||
.property("expose-all-streams", false)
|
||||
.property("caps", video_caps)
|
||||
.property("uri", uri)
|
||||
.build()?;
|
||||
let conv = gst::ElementFactory::make("videoconvert").build()?;
|
||||
let q1 = gst::ElementFactory::make("queue").build()?;
|
||||
let enc = gst::ElementFactory::make("vp8enc")
|
||||
.property("keyframe-max-dist", 30i32)
|
||||
.property("threads", 12i32)
|
||||
.property("cpu-used", -16i32)
|
||||
.property("deadline", 1i64)
|
||||
.property_from_str("error-resilient", "default")
|
||||
.build()?;
|
||||
let q2 = gst::ElementFactory::make("queue").build()?;
|
||||
let pay = gst::ElementFactory::make("rtpvp8pay").build()?;
|
||||
let rtpbin = gst::ElementFactory::make("rtpbin").build()?;
|
||||
let sink = gst::ElementFactory::make("udpsink")
|
||||
.property("host", "127.0.0.1")
|
||||
.property("sync", true)
|
||||
.build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &conv, &q1, &enc, &q2, &pay, &rtpbin, &sink])?;
|
||||
|
||||
|
@ -149,20 +149,6 @@ fn example_main() -> Result<(), Error> {
|
|||
},
|
||||
);
|
||||
|
||||
let video_caps = gst::Caps::builder("video/x-raw").build();
|
||||
|
||||
src.set_property_from_str("pattern", "ball");
|
||||
sink.set_property("host", "127.0.0.1");
|
||||
sink.set_property("sync", true);
|
||||
enc.set_property("keyframe-max-dist", 30i32);
|
||||
enc.set_property("threads", 12i32);
|
||||
enc.set_property("cpu-used", -16i32);
|
||||
enc.set_property("deadline", 1i64);
|
||||
enc.set_property_from_str("error-resilient", "default");
|
||||
src.set_property("expose-all-streams", false);
|
||||
src.set_property("caps", video_caps);
|
||||
src.set_property("uri", uri);
|
||||
|
||||
let bus = pipeline
|
||||
.bus()
|
||||
.expect("Pipeline without bus. Shouldn't happen!");
|
||||
|
|
|
@ -121,17 +121,22 @@ mod media_factory {
|
|||
fn create_element(&self, _url: &gst_rtsp::RTSPUrl) -> Option<gst::Element> {
|
||||
// Create a simple VP8 videotestsrc input
|
||||
let bin = gst::Bin::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None).unwrap();
|
||||
let enc = gst::ElementFactory::make("vp8enc", None).unwrap();
|
||||
let src = gst::ElementFactory::make("videotestsrc")
|
||||
// Configure the videotestsrc live
|
||||
.property("is-live", true)
|
||||
.build()
|
||||
.unwrap();
|
||||
let enc = gst::ElementFactory::make("vp8enc")
|
||||
// Produce encoded data as fast as possible
|
||||
.property("deadline", 1i64)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
// The names of the payloaders must be payX
|
||||
let pay = gst::ElementFactory::make("rtpvp8pay", Some("pay0")).unwrap();
|
||||
|
||||
// Configure the videotestsrc live
|
||||
src.set_property("is-live", true);
|
||||
|
||||
// Produce encoded data as fast as possible
|
||||
enc.set_property("deadline", 1i64);
|
||||
let pay = gst::ElementFactory::make("rtpvp8pay")
|
||||
.name("pay0")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
bin.add_many(&[&src, &enc, &pay]).unwrap();
|
||||
gst::Element::link_many(&[&src, &enc, &pay]).unwrap();
|
||||
|
|
|
@ -231,10 +231,6 @@ mod fir_filter {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -249,21 +245,18 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
|
|||
|
||||
// Create our pipeline with the custom element
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("audiotestsrc", None)
|
||||
.map_err(|_| MissingElement("audiotestsrc"))?;
|
||||
let src = gst::ElementFactory::make("audiotestsrc")
|
||||
.property_from_str("wave", "white-noise")
|
||||
.build()?;
|
||||
let filter = fir_filter::FirFilter::new(None);
|
||||
let conv = gst::ElementFactory::make("audioconvert", None)
|
||||
.map_err(|_| MissingElement("audioconvert"))?;
|
||||
let sink = gst::ElementFactory::make("autoaudiosink", None)
|
||||
.map_err(|_| MissingElement("autoaudiosink"))?;
|
||||
let conv = gst::ElementFactory::make("audioconvert").build()?;
|
||||
let sink = gst::ElementFactory::make("autoaudiosink").build()?;
|
||||
|
||||
pipeline.add_many(&[&src, filter.upcast_ref(), &conv, &sink])?;
|
||||
src.link(&filter)?;
|
||||
filter.link(&conv)?;
|
||||
conv.link(&sink)?;
|
||||
|
||||
src.set_property_from_str("wave", "white-noise");
|
||||
|
||||
// Create a windowed sinc lowpass filter at 1/64 sample rate,
|
||||
// i.e. 689Hz for 44.1kHz sample rate
|
||||
let w = 2.0 * std::f32::consts::PI / 64.0;
|
||||
|
|
|
@ -16,10 +16,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
|
|
@ -28,10 +28,11 @@ fn example_main() {
|
|||
};
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("filesrc", None).unwrap();
|
||||
let decodebin = gst::ElementFactory::make("decodebin", None).unwrap();
|
||||
|
||||
src.set_property("location", uri);
|
||||
let src = gst::ElementFactory::make("filesrc")
|
||||
.property("location", uri)
|
||||
.build()
|
||||
.unwrap();
|
||||
let decodebin = gst::ElementFactory::make("decodebin").build().unwrap();
|
||||
|
||||
pipeline.add_many(&[&src, &decodebin]).unwrap();
|
||||
gst::Element::link_many(&[&src, &decodebin]).unwrap();
|
||||
|
@ -59,8 +60,8 @@ fn example_main() {
|
|||
// In this example, we are only interested about parsing the ToC, so
|
||||
// we simply pipe every encountered stream into a fakesink, essentially
|
||||
// throwing away the data.
|
||||
let queue = gst::ElementFactory::make("queue", None).unwrap();
|
||||
let sink = gst::ElementFactory::make("fakesink", None).unwrap();
|
||||
let queue = gst::ElementFactory::make("queue").build().unwrap();
|
||||
let sink = gst::ElementFactory::make("fakesink").build().unwrap();
|
||||
|
||||
let elements = &[&queue, &sink];
|
||||
pipeline.add_many(elements).unwrap();
|
||||
|
|
|
@ -28,10 +28,6 @@ use derive_more::{Display, Error};
|
|||
#[path = "../examples-common.rs"]
|
||||
mod examples_common;
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -59,20 +55,18 @@ fn example_main() -> Result<(), Error> {
|
|||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::Element::make_from_uri(gst::URIType::Src, uri, None)
|
||||
.expect("We do not seem to support this uri");
|
||||
let typefinder =
|
||||
gst::ElementFactory::make("typefind", None).map_err(|_| MissingElement("typefind"))?;
|
||||
let queue =
|
||||
gst::ElementFactory::make("multiqueue", None).map_err(|_| MissingElement("multiqueue"))?;
|
||||
let muxer = gst::ElementFactory::make("matroskamux", None)
|
||||
.map_err(|_| MissingElement("matroskamux"))?;
|
||||
let sink =
|
||||
gst::ElementFactory::make("filesink", None).map_err(|_| MissingElement("filesink"))?;
|
||||
let typefinder = gst::ElementFactory::make("typefind").build()?;
|
||||
let queue = gst::ElementFactory::make("multiqueue")
|
||||
.property("max-size-buffers", 0u32)
|
||||
.property("max-size-time", 0u64)
|
||||
.property("max-size-bytes", 1024u32 * 1024 * 100)
|
||||
.build()?;
|
||||
let muxer = gst::ElementFactory::make("matroskamux").build()?;
|
||||
let sink = gst::ElementFactory::make("filesink")
|
||||
.property("location", output_file)
|
||||
.build()?;
|
||||
|
||||
sink.set_property("location", output_file);
|
||||
// Increase the queue capacity to 100MB to avoid a stalling pipeline
|
||||
queue.set_property("max-size-buffers", 0u32);
|
||||
queue.set_property("max-size-time", 0u64);
|
||||
queue.set_property("max-size-bytes", 1024u32 * 1024 * 100);
|
||||
|
||||
pipeline
|
||||
.add_many(&[&src, &typefinder, &queue, &muxer, &sink])
|
||||
|
@ -96,12 +90,12 @@ fn example_main() -> Result<(), Error> {
|
|||
let format_name = caps.structure(0).expect("Failed to get format name").name();
|
||||
|
||||
let demuxer = match format_name {
|
||||
"video/x-matroska" | "video/webm" => {
|
||||
gst::ElementFactory::make("matroskademux", None).expect("matroskademux missing")
|
||||
}
|
||||
"video/quicktime" => {
|
||||
gst::ElementFactory::make("qtdemux", None).expect("qtdemux missing")
|
||||
}
|
||||
"video/x-matroska" | "video/webm" => gst::ElementFactory::make("matroskademux")
|
||||
.build()
|
||||
.expect("matroskademux missing"),
|
||||
"video/quicktime" => gst::ElementFactory::make("qtdemux")
|
||||
.build()
|
||||
.expect("qtdemux missing"),
|
||||
_ => {
|
||||
eprintln!("Sorry, this format is not supported by this example.");
|
||||
std::process::exit(-1);
|
||||
|
|
|
@ -16,10 +16,6 @@ use std::sync;
|
|||
use anyhow::Error;
|
||||
use derive_more::{Display, Error};
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Missing element {}", _0)]
|
||||
struct MissingElement(#[error(not(source))] &'static str);
|
||||
|
||||
#[derive(Debug, Display, Error)]
|
||||
#[display(fmt = "Received error from {}: {} (debug: {:?})", src, error, debug)]
|
||||
struct ErrorMessage {
|
||||
|
@ -535,18 +531,15 @@ impl App {
|
|||
gl_element: Option<&gst::Element>,
|
||||
) -> Result<(gst::Pipeline, gst_app::AppSink, gst::Element), Error> {
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
let src = gst::ElementFactory::make("videotestsrc", None)
|
||||
.map_err(|_| MissingElement("videotestsrc"))?;
|
||||
let src = gst::ElementFactory::make("videotestsrc").build()?;
|
||||
|
||||
let appsink = gst::ElementFactory::make("appsink", None)
|
||||
.map_err(|_| MissingElement("appsink"))?
|
||||
let appsink = gst::ElementFactory::make("appsink")
|
||||
.build()?
|
||||
.dynamic_cast::<gst_app::AppSink>()
|
||||
.expect("Sink element is expected to be an appsink!");
|
||||
|
||||
appsink.set_property("enable-last-sample", false);
|
||||
appsink.set_property("emit-signals", false);
|
||||
appsink.set_property("max-buffers", 1u32);
|
||||
|
||||
appsink.set_enable_last_sample(true);
|
||||
appsink.set_max_buffers(1);
|
||||
let caps = gst_video::VideoCapsBuilder::new()
|
||||
.features(&[&gst_gl::CAPS_FEATURE_MEMORY_GL_MEMORY])
|
||||
.format(gst_video::VideoFormat::Rgba)
|
||||
|
@ -555,8 +548,7 @@ impl App {
|
|||
appsink.set_caps(Some(&caps));
|
||||
|
||||
if let Some(gl_element) = gl_element {
|
||||
let glupload = gst::ElementFactory::make("glupload", None)
|
||||
.map_err(|_| MissingElement("glupload"))?;
|
||||
let glupload = gst::ElementFactory::make("glupload").build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &glupload])?;
|
||||
pipeline.add(gl_element)?;
|
||||
|
@ -568,10 +560,9 @@ impl App {
|
|||
|
||||
Ok((pipeline, appsink, glupload))
|
||||
} else {
|
||||
let sink = gst::ElementFactory::make("glsinkbin", None)
|
||||
.map_err(|_| MissingElement("glsinkbin"))?;
|
||||
|
||||
sink.set_property("sink", &appsink);
|
||||
let sink = gst::ElementFactory::make("glsinkbin")
|
||||
.property("sink", &appsink)
|
||||
.build()?;
|
||||
|
||||
pipeline.add_many(&[&src, &sink])?;
|
||||
src.link(&sink)?;
|
||||
|
|
|
@ -1006,10 +1006,11 @@ mod tests {
|
|||
fn test_app_sink_stream() {
|
||||
gst::init().unwrap();
|
||||
|
||||
let videotestsrc = gst::ElementFactory::make("videotestsrc", None).unwrap();
|
||||
let appsink = gst::ElementFactory::make("appsink", None).unwrap();
|
||||
|
||||
videotestsrc.set_property("num-buffers", 5);
|
||||
let videotestsrc = gst::ElementFactory::make("videotestsrc")
|
||||
.property("num-buffers", 5)
|
||||
.build()
|
||||
.unwrap();
|
||||
let appsink = gst::ElementFactory::make("appsink").build().unwrap();
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
pipeline.add(&videotestsrc).unwrap();
|
||||
|
|
|
@ -458,10 +458,11 @@ mod tests {
|
|||
fn test_app_src_sink() {
|
||||
gst::init().unwrap();
|
||||
|
||||
let appsrc = gst::ElementFactory::make("appsrc", None).unwrap();
|
||||
let fakesink = gst::ElementFactory::make("fakesink", None).unwrap();
|
||||
|
||||
fakesink.set_property("signal-handoffs", true);
|
||||
let appsrc = gst::ElementFactory::make("appsrc").build().unwrap();
|
||||
let fakesink = gst::ElementFactory::make("fakesink")
|
||||
.property("signal-handoffs", true)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let pipeline = gst::Pipeline::new(None);
|
||||
pipeline.add(&appsrc).unwrap();
|
||||
|
|
|
@ -1248,13 +1248,13 @@ status = "generate"
|
|||
final_type = true
|
||||
[[object.function]]
|
||||
name = "create"
|
||||
[object.function.return]
|
||||
nullable_return_is_error = "Failed to create element from factory"
|
||||
rename = "create_with_name"
|
||||
manual = true
|
||||
|
||||
[[object.function]]
|
||||
name = "make"
|
||||
[object.function.return]
|
||||
nullable_return_is_error = "Failed to create element from factory name"
|
||||
rename = "make_with_name"
|
||||
manual = true
|
||||
|
||||
[[object.function]]
|
||||
name = "create_full"
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
// DO NOT EDIT
|
||||
|
||||
use crate::Caps;
|
||||
use crate::Element;
|
||||
use crate::Object;
|
||||
use crate::PluginFeature;
|
||||
use crate::URIType;
|
||||
|
@ -60,17 +59,6 @@ impl ElementFactory {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_element_factory_create")]
|
||||
pub fn create(&self, name: Option<&str>) -> Result<Element, glib::BoolError> {
|
||||
unsafe {
|
||||
Option::<_>::from_glib_none(ffi::gst_element_factory_create(
|
||||
self.to_glib_none().0,
|
||||
name.to_glib_none().0,
|
||||
))
|
||||
.ok_or_else(|| glib::bool_error!("Failed to create element from factory"))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_element_factory_get_element_type")]
|
||||
#[doc(alias = "get_element_type")]
|
||||
pub fn element_type(&self) -> glib::types::Type {
|
||||
|
@ -140,18 +128,6 @@ impl ElementFactory {
|
|||
assert_initialized_main_thread!();
|
||||
unsafe { from_glib_full(ffi::gst_element_factory_find(name.to_glib_none().0)) }
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_element_factory_make")]
|
||||
pub fn make(factoryname: &str, name: Option<&str>) -> Result<Element, glib::BoolError> {
|
||||
assert_initialized_main_thread!();
|
||||
unsafe {
|
||||
Option::<_>::from_glib_none(ffi::gst_element_factory_make(
|
||||
factoryname.to_glib_none().0,
|
||||
name.to_glib_none().0,
|
||||
))
|
||||
.ok_or_else(|| glib::bool_error!("Failed to create element from factory name"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ElementFactory {}
|
||||
|
|
|
@ -246,10 +246,20 @@ mod tests {
|
|||
crate::init().unwrap();
|
||||
|
||||
let bin = crate::Bin::new(None);
|
||||
bin.add(&crate::ElementFactory::make("identity", Some("identity0")).unwrap())
|
||||
.unwrap();
|
||||
bin.add(&crate::ElementFactory::make("identity", Some("identity1")).unwrap())
|
||||
.unwrap();
|
||||
bin.add(
|
||||
&crate::ElementFactory::make("identity")
|
||||
.name("identity0")
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
bin.add(
|
||||
&crate::ElementFactory::make("identity")
|
||||
.name("identity1")
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut child_names = bin
|
||||
.children()
|
||||
|
|
|
@ -1595,7 +1595,7 @@ mod tests {
|
|||
fn test_get_pads() {
|
||||
crate::init().unwrap();
|
||||
|
||||
let identity = crate::ElementFactory::make("identity", None).unwrap();
|
||||
let identity = crate::ElementFactory::make("identity").build().unwrap();
|
||||
|
||||
let mut pad_names = identity
|
||||
.pads()
|
||||
|
@ -1626,7 +1626,7 @@ mod tests {
|
|||
fn test_foreach_pad() {
|
||||
crate::init().unwrap();
|
||||
|
||||
let identity = crate::ElementFactory::make("identity", None).unwrap();
|
||||
let identity = crate::ElementFactory::make("identity").build().unwrap();
|
||||
|
||||
let mut pad_names = Vec::new();
|
||||
identity.foreach_pad(|_element, pad| {
|
||||
|
@ -1642,7 +1642,7 @@ mod tests {
|
|||
fn test_call_async() {
|
||||
crate::init().unwrap();
|
||||
|
||||
let identity = crate::ElementFactory::make("identity", None).unwrap();
|
||||
let identity = crate::ElementFactory::make("identity").build().unwrap();
|
||||
let (sender, receiver) = channel();
|
||||
|
||||
identity.call_async(move |_| {
|
||||
|
|
|
@ -25,64 +25,12 @@ impl ElementFactory {
|
|||
) -> Result<Element, glib::BoolError> {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
// The below is basically a reimplementation of the C function. We want to call
|
||||
// glib::Object::with_type() ourselves here for checking properties and their values
|
||||
// correctly and to provide consistent behaviour.
|
||||
use crate::prelude::{
|
||||
ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual,
|
||||
};
|
||||
|
||||
let factory = self.load().map_err(|_| {
|
||||
crate::warning!(crate::CAT_RUST, obj: self, "loading plugin returned None");
|
||||
glib::bool_error!("Failed to create element from factory")
|
||||
})?;
|
||||
|
||||
let element_type = factory.element_type();
|
||||
if !element_type.is_valid() {
|
||||
crate::warning!(crate::CAT_RUST, obj: self, "factory has no type");
|
||||
return Err(glib::bool_error!("Failed to create element from factory"));
|
||||
}
|
||||
|
||||
let element = glib::Object::with_type(element_type, properties)
|
||||
.downcast::<crate::Element>()
|
||||
.unwrap();
|
||||
unsafe {
|
||||
use std::sync::atomic;
|
||||
|
||||
let klass = element.element_class();
|
||||
let factory_ptr: &atomic::AtomicPtr<ffi::GstElementFactory> =
|
||||
&*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory
|
||||
as *const atomic::AtomicPtr<ffi::GstElementFactory>);
|
||||
if factory_ptr
|
||||
.compare_exchange(
|
||||
std::ptr::null_mut(),
|
||||
factory.as_ptr(),
|
||||
atomic::Ordering::SeqCst,
|
||||
atomic::Ordering::SeqCst,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED);
|
||||
}
|
||||
|
||||
if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _)
|
||||
!= glib::ffi::GFALSE
|
||||
{
|
||||
glib::g_critical!(
|
||||
"GStreamer",
|
||||
"The created element should be floating, this is probably caused by faulty bindings",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
crate::log!(
|
||||
crate::CAT_RUST,
|
||||
obj: self,
|
||||
"created element \"{}\"",
|
||||
factory.name()
|
||||
);
|
||||
|
||||
Ok(element)
|
||||
let mut builder = self.create();
|
||||
builder.properties = properties
|
||||
.iter()
|
||||
.map(|(name, value)| (*name, ValueOrStr::Value(value.to_value())))
|
||||
.collect();
|
||||
builder.build()
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_element_factory_make_with_properties")]
|
||||
|
@ -93,22 +41,59 @@ impl ElementFactory {
|
|||
) -> Result<Element, glib::BoolError> {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
crate::log!(
|
||||
crate::CAT_RUST,
|
||||
"gstelementfactory: make \"{}\"",
|
||||
factoryname
|
||||
);
|
||||
let mut builder = Self::make(factoryname);
|
||||
builder.properties = properties
|
||||
.iter()
|
||||
.map(|(name, value)| (*name, ValueOrStr::Value(value.to_value())))
|
||||
.collect();
|
||||
builder.build()
|
||||
}
|
||||
|
||||
let factory = Self::find(factoryname).ok_or_else(|| {
|
||||
crate::warning!(
|
||||
crate::CAT_RUST,
|
||||
"gstelementfactory: make \"{}\"",
|
||||
factoryname
|
||||
);
|
||||
glib::bool_error!("Failed to create element from factory name")
|
||||
})?;
|
||||
#[doc(alias = "gst_element_factory_create")]
|
||||
#[doc(alias = "gst_element_factory_create_with_properties")]
|
||||
#[track_caller]
|
||||
pub fn create(&self) -> ElementBuilder {
|
||||
ElementBuilder {
|
||||
name_or_factory: NameOrFactory::Factory(self),
|
||||
properties: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
factory.create_with_properties(properties)
|
||||
#[doc(alias = "gst_element_factory_make")]
|
||||
#[doc(alias = "gst_element_factory_make_with_properties")]
|
||||
#[track_caller]
|
||||
pub fn make(factoryname: &str) -> ElementBuilder {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
ElementBuilder {
|
||||
name_or_factory: NameOrFactory::Name(factoryname),
|
||||
properties: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_element_factory_create")]
|
||||
#[track_caller]
|
||||
pub fn create_with_name(&self, name: Option<&str>) -> Result<Element, glib::BoolError> {
|
||||
let mut builder = self.create();
|
||||
if let Some(name) = name {
|
||||
builder = builder.name(name);
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_element_factory_make")]
|
||||
#[track_caller]
|
||||
pub fn make_with_name(
|
||||
factoryname: &str,
|
||||
name: Option<&str>,
|
||||
) -> Result<Element, glib::BoolError> {
|
||||
assert_initialized_main_thread!();
|
||||
|
||||
let mut builder = Self::make(factoryname);
|
||||
if let Some(name) = name {
|
||||
builder = builder.name(name);
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
|
||||
#[doc(alias = "gst_element_factory_get_static_pad_templates")]
|
||||
|
@ -196,3 +181,219 @@ impl ElementFactory {
|
|||
self.metadata(&ELEMENT_METADATA_ICON_NAME)
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Builder for `Element`s.
|
||||
#[must_use = "The builder must be built to be used"]
|
||||
pub struct ElementBuilder<'a> {
|
||||
name_or_factory: NameOrFactory<'a>,
|
||||
properties: Vec<(&'a str, ValueOrStr<'a>)>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum NameOrFactory<'a> {
|
||||
Name(&'a str),
|
||||
Factory(&'a ElementFactory),
|
||||
}
|
||||
|
||||
enum ValueOrStr<'a> {
|
||||
Value(glib::Value),
|
||||
Str(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> ElementBuilder<'a> {
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Sets the name property to the given `name`.
|
||||
pub fn name(self, name: &'a str) -> Self {
|
||||
self.property("name", name)
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Set property `name` to the given value `value`.
|
||||
pub fn property<T: glib::ToValue + 'a>(self, name: &'a str, value: T) -> Self {
|
||||
Self {
|
||||
name_or_factory: self.name_or_factory,
|
||||
properties: {
|
||||
let mut properties = self.properties;
|
||||
properties.push((name, ValueOrStr::Value(value.to_value())));
|
||||
properties
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Set property `name` to the given string value `value`.
|
||||
pub fn property_from_str(self, name: &'a str, value: &'a str) -> Self {
|
||||
Self {
|
||||
name_or_factory: self.name_or_factory,
|
||||
properties: {
|
||||
let mut properties = self.properties;
|
||||
properties.push((name, ValueOrStr::Str(value)));
|
||||
properties
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// rustdoc-stripper-ignore-next
|
||||
/// Build the element with the provided properties.
|
||||
///
|
||||
/// This fails if there is no such element factory or the element factory can't be loaded.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This panics if the element is not instantiable, doesn't have all the given properties or
|
||||
/// property values of the wrong type are provided.
|
||||
#[track_caller]
|
||||
#[must_use = "Building the element without using it has no effect"]
|
||||
pub fn build(self) -> Result<Element, glib::BoolError> {
|
||||
let mut _factory_found = None;
|
||||
let factory = match self.name_or_factory {
|
||||
NameOrFactory::Name(name) => {
|
||||
let factory = ElementFactory::find(name).ok_or_else(|| {
|
||||
crate::warning!(crate::CAT_RUST, "element factory '{}' not found", name);
|
||||
glib::bool_error!(
|
||||
"Failed to find element factory with name '{}' for creating element",
|
||||
name
|
||||
)
|
||||
})?;
|
||||
_factory_found = Some(factory);
|
||||
_factory_found.as_ref().unwrap()
|
||||
}
|
||||
NameOrFactory::Factory(factory) => factory,
|
||||
};
|
||||
|
||||
// The below is basically a reimplementation of the C function. We want to call
|
||||
// glib::Object::with_type() ourselves here for checking properties and their values
|
||||
// correctly and to provide consistent behaviour.
|
||||
use crate::prelude::{
|
||||
ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual,
|
||||
};
|
||||
|
||||
let factory = factory.load().map_err(|_| {
|
||||
crate::warning!(
|
||||
crate::CAT_RUST,
|
||||
obj: factory,
|
||||
"loading element factory '{}' failed",
|
||||
factory.name(),
|
||||
);
|
||||
glib::bool_error!(
|
||||
"Failed to load element factory '{}' for creating element",
|
||||
factory.name()
|
||||
)
|
||||
})?;
|
||||
|
||||
let element_type = factory.element_type();
|
||||
if !element_type.is_valid() {
|
||||
crate::warning!(
|
||||
crate::CAT_RUST,
|
||||
obj: &factory,
|
||||
"element factory '{}' has no type",
|
||||
factory.name()
|
||||
);
|
||||
return Err(glib::bool_error!(
|
||||
"Failed to create element from factory '{}'",
|
||||
factory.name()
|
||||
));
|
||||
}
|
||||
|
||||
let mut properties = Vec::with_capacity(self.properties.len());
|
||||
let klass = glib::Class::<Element>::from_type(element_type).unwrap();
|
||||
for (name, value) in self.properties {
|
||||
match value {
|
||||
ValueOrStr::Value(value) => {
|
||||
properties.push((name, value));
|
||||
}
|
||||
ValueOrStr::Str(value) => {
|
||||
use crate::value::GstValueExt;
|
||||
|
||||
let pspec = match klass.find_property(name) {
|
||||
Some(pspec) => pspec,
|
||||
None => {
|
||||
panic!(
|
||||
"property '{}' of element factory '{}' not found",
|
||||
name,
|
||||
factory.name()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let value = {
|
||||
if pspec.value_type() == crate::Structure::static_type() && value == "NULL"
|
||||
{
|
||||
None::<crate::Structure>.to_value()
|
||||
} else {
|
||||
#[cfg(feature = "v1_20")]
|
||||
{
|
||||
glib::Value::deserialize_with_pspec(value, &pspec)
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"property '{}' of element factory '{}' can't be set from string '{}'",
|
||||
name,
|
||||
factory.name(),
|
||||
value,
|
||||
)
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "v1_20"))]
|
||||
{
|
||||
glib::Value::deserialize(value, pspec.value_type())
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"property '{}' of element factory '{}' can't be set from string '{}'",
|
||||
name,
|
||||
factory.name(),
|
||||
value,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
properties.push((name, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let element = glib::Object::with_values(element_type, &properties)
|
||||
.downcast::<crate::Element>()
|
||||
.unwrap();
|
||||
|
||||
unsafe {
|
||||
use std::sync::atomic;
|
||||
|
||||
let klass = element.element_class();
|
||||
let factory_ptr: &atomic::AtomicPtr<ffi::GstElementFactory> =
|
||||
&*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory
|
||||
as *const atomic::AtomicPtr<ffi::GstElementFactory>);
|
||||
if factory_ptr
|
||||
.compare_exchange(
|
||||
std::ptr::null_mut(),
|
||||
factory.as_ptr(),
|
||||
atomic::Ordering::SeqCst,
|
||||
atomic::Ordering::SeqCst,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED);
|
||||
}
|
||||
|
||||
if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _)
|
||||
!= glib::ffi::GFALSE
|
||||
{
|
||||
glib::g_critical!(
|
||||
"GStreamer",
|
||||
"The created element should be floating, this is probably caused by faulty bindings",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
crate::log!(
|
||||
crate::CAT_RUST,
|
||||
obj: &factory,
|
||||
"created element \"{}\"",
|
||||
factory.name()
|
||||
);
|
||||
|
||||
Ok(element)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,11 +21,25 @@ impl<O: IsA<glib::Object>> GObjectExtManualGst for O {
|
|||
} else {
|
||||
#[cfg(feature = "v1_20")]
|
||||
{
|
||||
glib::Value::deserialize_with_pspec(value, &pspec).unwrap()
|
||||
glib::Value::deserialize_with_pspec(value, &pspec).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"property '{}' of type '{}' can't be set from string '{}'",
|
||||
name,
|
||||
self.type_(),
|
||||
value,
|
||||
)
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "v1_20"))]
|
||||
{
|
||||
glib::Value::deserialize(value, pspec.value_type()).unwrap()
|
||||
glib::Value::deserialize(value, pspec.value_type()).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"property '{}' of type '{}' can't be set from string '{}'",
|
||||
name,
|
||||
self.type_(),
|
||||
value,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -42,7 +56,7 @@ mod tests {
|
|||
fn test_set_property_from_str() {
|
||||
crate::init().unwrap();
|
||||
|
||||
let fakesink = crate::ElementFactory::make("fakesink", None).unwrap();
|
||||
let fakesink = crate::ElementFactory::make("fakesink").build().unwrap();
|
||||
fakesink.set_property_from_str("state-error", "ready-to-paused");
|
||||
let v = fakesink.property_value("state-error");
|
||||
let (_klass, e) = glib::EnumValue::from_value(&v).unwrap();
|
||||
|
|
|
@ -798,8 +798,8 @@ mod tests {
|
|||
crate::init().unwrap();
|
||||
|
||||
let bin = crate::Bin::new(None);
|
||||
let id1 = crate::ElementFactory::make("identity", None).unwrap();
|
||||
let id2 = crate::ElementFactory::make("identity", None).unwrap();
|
||||
let id1 = crate::ElementFactory::make("identity").build().unwrap();
|
||||
let id2 = crate::ElementFactory::make("identity").build().unwrap();
|
||||
|
||||
bin.add(&id1).unwrap();
|
||||
|
||||
|
@ -829,8 +829,8 @@ mod tests {
|
|||
crate::init().unwrap();
|
||||
|
||||
let bin = crate::Bin::new(None);
|
||||
let id1 = crate::ElementFactory::make("identity", None).unwrap();
|
||||
let id2 = crate::ElementFactory::make("identity", None).unwrap();
|
||||
let id1 = crate::ElementFactory::make("identity").build().unwrap();
|
||||
let id2 = crate::ElementFactory::make("identity").build().unwrap();
|
||||
|
||||
bin.add(&id1).unwrap();
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ pub use promise::{Promise, PromiseError};
|
|||
|
||||
pub mod bus;
|
||||
mod element;
|
||||
mod element_factory;
|
||||
pub mod element_factory;
|
||||
|
||||
mod bin;
|
||||
|
||||
|
|
|
@ -136,7 +136,10 @@ mod tests {
|
|||
crate::init().unwrap();
|
||||
|
||||
let bin = crate::Bin::new(None);
|
||||
let identity = crate::ElementFactory::make("identity", Some("id")).unwrap();
|
||||
let identity = crate::ElementFactory::make("identity")
|
||||
.name("id")
|
||||
.build()
|
||||
.unwrap();
|
||||
bin.add(&identity).unwrap();
|
||||
|
||||
let notify = Arc::new(Mutex::new(None));
|
||||
|
|
|
@ -55,6 +55,6 @@ mod tests {
|
|||
let factory = crate::ElementFactory::find("identity").unwrap();
|
||||
let loaded = factory.load().unwrap();
|
||||
assert_eq!(factory.type_(), loaded.type_());
|
||||
let _element = loaded.create(None).unwrap();
|
||||
let _element = loaded.create().build().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -781,10 +781,11 @@ mod tests {
|
|||
);
|
||||
|
||||
let pipeline = crate::Pipeline::new(None);
|
||||
let src = ElementFactory::make("fakesrc", None).unwrap();
|
||||
let sink = ElementFactory::make("fakesink", None).unwrap();
|
||||
|
||||
src.set_property("num-buffers", 100i32);
|
||||
let src = ElementFactory::make("fakesrc")
|
||||
.property("num-buffers", 100i32)
|
||||
.build()
|
||||
.unwrap();
|
||||
let sink = ElementFactory::make("fakesink").build().unwrap();
|
||||
|
||||
pipeline
|
||||
.add_many(&[&src, element.upcast_ref(), &sink])
|
||||
|
|
|
@ -8,9 +8,14 @@ fn tutorial_main() {
|
|||
gst::init().unwrap();
|
||||
|
||||
// Create the elements
|
||||
let source = gst::ElementFactory::make("videotestsrc", Some("source"))
|
||||
let source = gst::ElementFactory::make("videotestsrc")
|
||||
.name("source")
|
||||
.property_from_str("pattern", "smpte")
|
||||
.build()
|
||||
.expect("Could not create source element.");
|
||||
let sink = gst::ElementFactory::make("autovideosink", Some("sink"))
|
||||
let sink = gst::ElementFactory::make("autovideosink")
|
||||
.name("sink")
|
||||
.build()
|
||||
.expect("Could not create sink element");
|
||||
|
||||
// Create the empty pipeline
|
||||
|
@ -20,9 +25,6 @@ fn tutorial_main() {
|
|||
pipeline.add_many(&[&source, &sink]).unwrap();
|
||||
source.link(&sink).expect("Elements could not be linked.");
|
||||
|
||||
// Modify the source's properties
|
||||
source.set_property_from_str("pattern", "smpte");
|
||||
|
||||
// Start playing
|
||||
pipeline
|
||||
.set_state(gst::State::Playing)
|
||||
|
|
|
@ -7,14 +7,27 @@ fn tutorial_main() {
|
|||
// Initialize GStreamer
|
||||
gst::init().unwrap();
|
||||
|
||||
let uri =
|
||||
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
|
||||
|
||||
// Create the elements
|
||||
let source = gst::ElementFactory::make("uridecodebin", Some("source"))
|
||||
let source = gst::ElementFactory::make("uridecodebin")
|
||||
.name("source")
|
||||
// Set the URI to play
|
||||
.property("uri", uri)
|
||||
.build()
|
||||
.expect("Could not create uridecodebin element.");
|
||||
let convert = gst::ElementFactory::make("audioconvert", Some("convert"))
|
||||
let convert = gst::ElementFactory::make("audioconvert")
|
||||
.name("convert")
|
||||
.build()
|
||||
.expect("Could not create convert element.");
|
||||
let sink = gst::ElementFactory::make("autoaudiosink", Some("sink"))
|
||||
let sink = gst::ElementFactory::make("autoaudiosink")
|
||||
.name("sink")
|
||||
.build()
|
||||
.expect("Could not create sink element.");
|
||||
let resample = gst::ElementFactory::make("audioresample", Some("resample"))
|
||||
let resample = gst::ElementFactory::make("audioresample")
|
||||
.name("resample")
|
||||
.build()
|
||||
.expect("Could not create resample element.");
|
||||
|
||||
// Create the empty pipeline
|
||||
|
@ -27,11 +40,6 @@ fn tutorial_main() {
|
|||
.unwrap();
|
||||
gst::Element::link_many(&[&convert, &resample, &sink]).expect("Elements could not be linked.");
|
||||
|
||||
// Set the URI to play
|
||||
let uri =
|
||||
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
|
||||
source.set_property("uri", uri);
|
||||
|
||||
// Connect the pad-added signal
|
||||
source.connect_pad_added(move |src, src_pad| {
|
||||
println!("Received new pad {} from {}", src_pad.name(), src.name());
|
||||
|
|
|
@ -24,14 +24,16 @@ fn tutorial_main() {
|
|||
// Initialize GStreamer
|
||||
gst::init().unwrap();
|
||||
|
||||
// Creat the playbin element
|
||||
let playbin = gst::ElementFactory::make("playbin", Some("playbin"))
|
||||
.expect("Failed to create playbin element");
|
||||
|
||||
// Set the URI to play
|
||||
let uri =
|
||||
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
|
||||
playbin.set_property("uri", uri);
|
||||
|
||||
// Creat the playbin element
|
||||
let playbin = gst::ElementFactory::make("playbin")
|
||||
.name("playbin")
|
||||
// Set the URI to play
|
||||
.property("uri", uri)
|
||||
.build()
|
||||
.expect("Failed to create playbin element");
|
||||
|
||||
// Start playing
|
||||
playbin
|
||||
|
|
|
@ -301,8 +301,10 @@ mod tutorial5 {
|
|||
|
||||
let uri = "https://www.freedesktop.org/software/gstreamer-sdk/\
|
||||
data/media/sintel_trailer-480p.webm";
|
||||
let playbin = gst::ElementFactory::make("playbin", None).unwrap();
|
||||
playbin.set_property("uri", uri);
|
||||
let playbin = gst::ElementFactory::make("playbin")
|
||||
.property("uri", uri)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
playbin.connect("video-tags-changed", false, |args| {
|
||||
let pipeline = args[0]
|
||||
|
|
|
@ -90,10 +90,14 @@ fn tutorial_main() {
|
|||
|
||||
// Ask the factories to instantiate actual elements
|
||||
let source = source_factory
|
||||
.create(Some("source"))
|
||||
.create()
|
||||
.name("source")
|
||||
.build()
|
||||
.expect("Failed to create source element");
|
||||
let sink = sink_factory
|
||||
.create(Some("sink"))
|
||||
.create()
|
||||
.name("sink")
|
||||
.build()
|
||||
.expect("Failed to create sink element");
|
||||
|
||||
// Create the empty pipeline
|
||||
|
|
|
@ -10,24 +10,52 @@ fn tutorial_main() {
|
|||
return;
|
||||
}
|
||||
|
||||
let audio_source = gst::ElementFactory::make("audiotestsrc", Some("audio_source")).unwrap();
|
||||
let tee = gst::ElementFactory::make("tee", Some("tee")).unwrap();
|
||||
let audio_queue = gst::ElementFactory::make("queue", Some("audio_queue")).unwrap();
|
||||
let audio_convert = gst::ElementFactory::make("audioconvert", Some("audio_convert")).unwrap();
|
||||
let audio_resample =
|
||||
gst::ElementFactory::make("audioresample", Some("audio_resample")).unwrap();
|
||||
let audio_sink = gst::ElementFactory::make("autoaudiosink", Some("audio_sink")).unwrap();
|
||||
let video_queue = gst::ElementFactory::make("queue", Some("video_queue")).unwrap();
|
||||
let visual = gst::ElementFactory::make("wavescope", Some("visual")).unwrap();
|
||||
let video_convert = gst::ElementFactory::make("videoconvert", Some("video_convert")).unwrap();
|
||||
let video_sink = gst::ElementFactory::make("autovideosink", Some("video_sink")).unwrap();
|
||||
let audio_source = gst::ElementFactory::make("audiotestsrc")
|
||||
.name("audio_source")
|
||||
.property("freq", 215.0)
|
||||
.build()
|
||||
.unwrap();
|
||||
let tee = gst::ElementFactory::make("tee")
|
||||
.name("tee")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_queue = gst::ElementFactory::make("queue")
|
||||
.name("audio_queue")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_convert = gst::ElementFactory::make("audioconvert")
|
||||
.name("audio_convert")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_resample = gst::ElementFactory::make("audioresample")
|
||||
.name("audio_resample")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_sink = gst::ElementFactory::make("autoaudiosink")
|
||||
.name("audio_sink")
|
||||
.build()
|
||||
.unwrap();
|
||||
let video_queue = gst::ElementFactory::make("queue")
|
||||
.name("video_queue")
|
||||
.build()
|
||||
.unwrap();
|
||||
let visual = gst::ElementFactory::make("wavescope")
|
||||
.name("visual")
|
||||
.property_from_str("shader", "none")
|
||||
.property_from_str("style", "lines")
|
||||
.build()
|
||||
.unwrap();
|
||||
let video_convert = gst::ElementFactory::make("videoconvert")
|
||||
.name("video_convert")
|
||||
.build()
|
||||
.unwrap();
|
||||
let video_sink = gst::ElementFactory::make("autovideosink")
|
||||
.name("video_sink")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let pipeline = gst::Pipeline::new(Some("test-pipeline"));
|
||||
|
||||
audio_source.set_property("freq", 215.0);
|
||||
visual.set_property_from_str("shader", "none");
|
||||
visual.set_property_from_str("style", "lines");
|
||||
|
||||
pipeline
|
||||
.add_many(&[
|
||||
&audio_source,
|
||||
|
|
|
@ -47,26 +47,63 @@ fn main() {
|
|||
return;
|
||||
}
|
||||
|
||||
let appsrc = gst::ElementFactory::make("appsrc", Some("audio_source")).unwrap();
|
||||
let tee = gst::ElementFactory::make("tee", Some("tee")).unwrap();
|
||||
let audio_queue = gst::ElementFactory::make("queue", Some("audio_queue")).unwrap();
|
||||
let audio_convert1 = gst::ElementFactory::make("audioconvert", Some("audio_convert1")).unwrap();
|
||||
let audio_resample =
|
||||
gst::ElementFactory::make("audioresample", Some("audio_resample")).unwrap();
|
||||
let audio_sink = gst::ElementFactory::make("autoaudiosink", Some("audio_sink")).unwrap();
|
||||
let video_queue = gst::ElementFactory::make("queue", Some("video_queue")).unwrap();
|
||||
let audio_convert2 = gst::ElementFactory::make("audioconvert", Some("audio_convert2")).unwrap();
|
||||
let visual = gst::ElementFactory::make("wavescope", Some("visual")).unwrap();
|
||||
let video_convert = gst::ElementFactory::make("videoconvert", Some("video_convert")).unwrap();
|
||||
let video_sink = gst::ElementFactory::make("autovideosink", Some("video_sink")).unwrap();
|
||||
let app_queue = gst::ElementFactory::make("queue", Some("app_queue")).unwrap();
|
||||
let appsink = gst::ElementFactory::make("appsink", Some("app_sink")).unwrap();
|
||||
let appsrc = gst::ElementFactory::make("appsrc")
|
||||
.name("audio_source")
|
||||
.build()
|
||||
.unwrap();
|
||||
let tee = gst::ElementFactory::make("tee")
|
||||
.name("tee")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_queue = gst::ElementFactory::make("queue")
|
||||
.name("audio_queue")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_convert1 = gst::ElementFactory::make("audioconvert")
|
||||
.name("audio_convert1")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_resample = gst::ElementFactory::make("audioresample")
|
||||
.name("audio_resample")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_sink = gst::ElementFactory::make("autoaudiosink")
|
||||
.name("audio_sink")
|
||||
.build()
|
||||
.unwrap();
|
||||
let video_queue = gst::ElementFactory::make("queue")
|
||||
.name("video_queue")
|
||||
.build()
|
||||
.unwrap();
|
||||
let audio_convert2 = gst::ElementFactory::make("audioconvert")
|
||||
.name("audio_convert2")
|
||||
.build()
|
||||
.unwrap();
|
||||
let visual = gst::ElementFactory::make("wavescope")
|
||||
.name("visual")
|
||||
.property_from_str("shader", "none")
|
||||
.property_from_str("style", "lines")
|
||||
.build()
|
||||
.unwrap();
|
||||
let video_convert = gst::ElementFactory::make("videoconvert")
|
||||
.name("video_convert")
|
||||
.build()
|
||||
.unwrap();
|
||||
let video_sink = gst::ElementFactory::make("autovideosink")
|
||||
.name("video_sink")
|
||||
.build()
|
||||
.unwrap();
|
||||
let app_queue = gst::ElementFactory::make("queue")
|
||||
.name("app_queue")
|
||||
.build()
|
||||
.unwrap();
|
||||
let appsink = gst::ElementFactory::make("appsink")
|
||||
.name("app_sink")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let pipeline = gst::Pipeline::new(Some("test-pipeline"));
|
||||
|
||||
visual.set_property_from_str("shader", "none");
|
||||
visual.set_property_from_str("style", "lines");
|
||||
|
||||
pipeline
|
||||
.add_many(&[
|
||||
&appsrc,
|
||||
|
|
|
@ -107,13 +107,17 @@ fn tutorial_main() -> Result<(), Error> {
|
|||
// Initialize GStreamer
|
||||
gst::init()?;
|
||||
|
||||
// Create PlayBin element
|
||||
let playbin = gst::ElementFactory::make("playbin", Some("playbin"))?;
|
||||
|
||||
// Set URI to play
|
||||
let uri =
|
||||
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_cropped_multilingual.webm";
|
||||
playbin.set_property("uri", uri);
|
||||
|
||||
// Create PlayBin element
|
||||
let playbin = gst::ElementFactory::make("playbin")
|
||||
.name("playbin")
|
||||
// Set URI to play
|
||||
.property("uri", uri)
|
||||
// Set connection speed. This will affect some internal decisions of playbin
|
||||
.property("connection-speed", 56u64)
|
||||
.build()?;
|
||||
|
||||
// Set flags to show Audio and Video but ignore Subtitles
|
||||
let flags = playbin.property_value("flags");
|
||||
|
@ -129,9 +133,6 @@ fn tutorial_main() -> Result<(), Error> {
|
|||
.unwrap();
|
||||
playbin.set_property_from_value("flags", &flags);
|
||||
|
||||
// Set connection speed. This will affect some internal decisions of playbin
|
||||
playbin.set_property("connection-speed", 56u64);
|
||||
|
||||
// Handle keyboard input
|
||||
let playbin_clone = playbin.clone();
|
||||
let main_loop_clone = main_loop.clone();
|
||||
|
|
|
@ -109,19 +109,20 @@ fn tutorial_main() -> Result<(), Error> {
|
|||
// Initialize GStreamer
|
||||
gst::init()?;
|
||||
|
||||
// Create PlayBin element
|
||||
let playbin = gst::ElementFactory::make("playbin", Some("playbin"))?;
|
||||
|
||||
// Set URI to play
|
||||
let uri =
|
||||
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.ogv";
|
||||
playbin.set_property("uri", uri);
|
||||
|
||||
// Set the subtitle URI and font description
|
||||
let subtitle_uri =
|
||||
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer_gr.srt";
|
||||
playbin.set_property("suburi", subtitle_uri);
|
||||
playbin.set_property("subtitle-font-desc", "Sans, 18");
|
||||
|
||||
// Create PlayBin element
|
||||
let playbin = gst::ElementFactory::make("playbin")
|
||||
.name("playbin")
|
||||
// Set URI to play
|
||||
.property("uri", uri)
|
||||
// Set the subtitle URI and font description
|
||||
.property("suburi", subtitle_uri)
|
||||
.property("subtitle-font-desc", "Sans, 18")
|
||||
.build()?;
|
||||
|
||||
// Set flags to show Audio, Video and Subtitles
|
||||
let flags = playbin.property_value("flags");
|
||||
|
|
|
@ -19,8 +19,10 @@ fn tutorial_main() -> Result<(), Error> {
|
|||
// Build the pipeline
|
||||
let uri =
|
||||
"https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm";
|
||||
let pipeline = gst::ElementFactory::make("playbin", None)?;
|
||||
pipeline.set_property("uri", uri);
|
||||
let pipeline = gst::ElementFactory::make("playbin")
|
||||
.name("playbin")
|
||||
.property("uri", uri)
|
||||
.build()?;
|
||||
|
||||
// Set the download flag
|
||||
let flags = pipeline.property_value("flags");
|
||||
|
|
|
@ -43,7 +43,7 @@ fn tutorial_main() -> Result<(), Error> {
|
|||
// We have now selected a factory for the visualization element
|
||||
let name = vis_factory.longname();
|
||||
println!("Selected {}", name);
|
||||
let vis_plugin = vis_factory.create(None).unwrap();
|
||||
let vis_plugin = vis_factory.create().build().unwrap();
|
||||
|
||||
// Build the pipeline
|
||||
let pipeline = gst::parse_launch("playbin uri=http://radio.hbr1.com:19800/ambient.ogg")?;
|
||||
|
|
|
@ -14,11 +14,17 @@ fn tutorial_main() -> Result<(), Error> {
|
|||
"playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm")?;
|
||||
|
||||
// Create elements that go inside the sink bin
|
||||
let equalizer = gst::ElementFactory::make("equalizer-3bands", Some("equalizer"))
|
||||
let equalizer = gst::ElementFactory::make("equalizer-3bands")
|
||||
.name("equalizer")
|
||||
.build()
|
||||
.expect("Could not create equalizer element.");
|
||||
let convert = gst::ElementFactory::make("audioconvert", Some("convert"))
|
||||
let convert = gst::ElementFactory::make("audioconvert")
|
||||
.name("convert")
|
||||
.build()
|
||||
.expect("Could not create audioconvert element.");
|
||||
let sink = gst::ElementFactory::make("autoaudiosink", Some("audio_sink"))
|
||||
let sink = gst::ElementFactory::make("autoaudiosink")
|
||||
.name("audio_sink")
|
||||
.build()
|
||||
.expect("Could not create autoaudiosink element.");
|
||||
|
||||
// Create the sink bin, add the elements and link them
|
||||
|
|
Loading…
Reference in a new issue