From 7423b1dea649ea27bb0e0b97da90a9bb2be567f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 19 Oct 2022 14:13:57 +0300 Subject: [PATCH] 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. --- examples/src/bin/appsink.rs | 9 +- examples/src/bin/appsrc.rs | 12 +- examples/src/bin/cairo_compositor.rs | 20 +- examples/src/bin/custom_meta.rs | 7 +- examples/src/bin/decodebin.rs | 38 +-- examples/src/bin/encodebin.rs | 38 +-- examples/src/bin/fd_allocator.rs | 23 +- examples/src/bin/gtksink.rs | 12 +- examples/src/bin/gtkvideooverlay.rs | 6 +- examples/src/bin/iterator.rs | 2 +- examples/src/bin/overlay-composition.rs | 35 +-- examples/src/bin/pango-cairo.rs | 35 +-- examples/src/bin/playbin.rs | 6 +- examples/src/bin/rtpfecclient.rs | 88 +++--- examples/src/bin/rtpfecserver.rs | 72 ++--- examples/src/bin/rtsp-server-subclass.rs | 23 +- examples/src/bin/subclass.rs | 17 +- examples/src/bin/thumbnail.rs | 4 - examples/src/bin/toc.rs | 13 +- examples/src/bin/transmux.rs | 38 ++- examples/src/glupload.rs | 27 +- gstreamer-app/src/app_sink.rs | 9 +- gstreamer-app/src/app_src.rs | 9 +- gstreamer/Gir.toml | 8 +- gstreamer/src/auto/element_factory.rs | 24 -- gstreamer/src/bin.rs | 18 +- gstreamer/src/element.rs | 6 +- gstreamer/src/element_factory.rs | 345 ++++++++++++++++++----- gstreamer/src/gobject.rs | 20 +- gstreamer/src/iterator.rs | 8 +- gstreamer/src/lib.rs | 2 +- gstreamer/src/object.rs | 5 +- gstreamer/src/plugin_feature.rs | 2 +- gstreamer/src/subclass/element.rs | 9 +- tutorials/src/bin/basic-tutorial-2.rs | 12 +- tutorials/src/bin/basic-tutorial-3.rs | 26 +- tutorials/src/bin/basic-tutorial-4.rs | 14 +- tutorials/src/bin/basic-tutorial-5.rs | 6 +- tutorials/src/bin/basic-tutorial-6.rs | 8 +- tutorials/src/bin/basic-tutorial-7.rs | 58 +++- tutorials/src/bin/basic-tutorial-8.rs | 71 +++-- tutorials/src/bin/playback-tutorial-1.rs | 17 +- tutorials/src/bin/playback-tutorial-2.rs | 19 +- tutorials/src/bin/playback-tutorial-4.rs | 6 +- tutorials/src/bin/playback-tutorial-6.rs | 2 +- tutorials/src/bin/playback-tutorial-7.rs | 12 +- 46 files changed, 723 insertions(+), 518 deletions(-) diff --git a/examples/src/bin/appsink.rs b/examples/src/bin/appsink.rs index e6e8e6a73..3b2119d66 100644 --- a/examples/src/bin/appsink.rs +++ b/examples/src/bin/appsink.rs @@ -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::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)?; diff --git a/examples/src/bin/appsrc.rs b/examples/src/bin/appsrc.rs index 5349750dc..1d0109310 100644 --- a/examples/src/bin/appsrc.rs +++ b/examples/src/bin/appsrc.rs @@ -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::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])?; diff --git a/examples/src/bin/cairo_compositor.rs b/examples/src/bin/cairo_compositor.rs index 64ec19393..f6adb31f0 100644 --- a/examples/src/bin/cairo_compositor.rs +++ b/examples/src/bin/cairo_compositor.rs @@ -567,12 +567,17 @@ fn create_pipeline() -> Result { // 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 { .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; diff --git a/examples/src/bin/custom_meta.rs b/examples/src/bin/custom_meta.rs index 4289aa5f6..6c6270d10 100644 --- a/examples/src/bin/custom_meta.rs +++ b/examples/src/bin/custom_meta.rs @@ -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::() .unwrap(); - let appsink = gst::ElementFactory::make("appsink", None) + let appsink = gst::ElementFactory::make("appsink") + .build() .unwrap() .downcast::() .unwrap(); diff --git a/examples/src/bin/decodebin.rs b/examples/src/bin/decodebin.rs index 328aafe84..b7204e544 100644 --- a/examples/src/bin/decodebin.rs +++ b/examples/src/bin/decodebin.rs @@ -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)?; diff --git a/examples/src/bin/encodebin.rs b/examples/src/bin/encodebin.rs index 5db2cc527..bb6d6b492 100644 --- a/examples/src/bin/encodebin.rs +++ b/examples/src/bin/encodebin.rs @@ -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 diff --git a/examples/src/bin/fd_allocator.rs b/examples/src/bin/fd_allocator.rs index 8094d087a..9edc57653 100644 --- a/examples/src/bin/fd_allocator.rs +++ b/examples/src/bin/fd_allocator.rs @@ -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::(); - 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::() .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::() .ok_or_else(|| anyhow::anyhow!("is not a appsink"))? diff --git a/examples/src/bin/gtksink.rs b/examples/src/bin/gtksink.rs index e9cec0a30..82845a99d 100644 --- a/examples/src/bin/gtksink.rs +++ b/examples/src/bin/gtksink.rs @@ -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::("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::("widget"); diff --git a/examples/src/bin/gtkvideooverlay.rs b/examples/src/bin/gtkvideooverlay.rs index 7bb64d258..92c13f4aa 100644 --- a/examples/src/bin/gtkvideooverlay.rs +++ b/examples/src/bin/gtkvideooverlay.rs @@ -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- diff --git a/examples/src/bin/iterator.rs b/examples/src/bin/iterator.rs index b8703b04d..d29d7b9b1 100644 --- a/examples/src/bin/iterator.rs +++ b/examples/src/bin/iterator.rs @@ -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 { diff --git a/examples/src/bin/overlay-composition.rs b/examples/src/bin/overlay-composition.rs index 103e30f84..412c313d3 100644 --- a/examples/src/bin/overlay-composition.rs +++ b/examples/src/bin/overlay-composition.rs @@ -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::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 { .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(); diff --git a/examples/src/bin/pango-cairo.rs b/examples/src/bin/pango-cairo.rs index 81badbced..f9440f761 100644 --- a/examples/src/bin/pango-cairo.rs +++ b/examples/src/bin/pango-cairo.rs @@ -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::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 { .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(); diff --git a/examples/src/bin/playbin.rs b/examples/src/bin/playbin.rs index b6c2a44f5..1d024e60a 100644 --- a/examples/src/bin/playbin.rs +++ b/examples/src/bin/playbin.rs @@ -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 diff --git a/examples/src/bin/rtpfecclient.rs b/examples/src/bin/rtpfecclient.rs index a2f0610ca..75d5621ee 100644 --- a/examples/src/bin/rtpfecclient.rs +++ b/examples/src/bin/rtpfecclient.rs @@ -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 { - 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 { 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 Result { 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 { - let fecdec = make_element("rtpulpfecdec", None)?; let internal_storage = rtpbin.emit_by_name::("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::()?; 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!"); diff --git a/examples/src/bin/rtpfecserver.rs b/examples/src/bin/rtpfecserver.rs index 74e9d9f8d..721f0bf6d 100644 --- a/examples/src/bin/rtpfecserver.rs +++ b/examples/src/bin/rtpfecserver.rs @@ -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 { - 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 { 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 Result { 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 { - 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::()?; + 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!"); diff --git a/examples/src/bin/rtsp-server-subclass.rs b/examples/src/bin/rtsp-server-subclass.rs index ffa9d5742..58f040b0c 100644 --- a/examples/src/bin/rtsp-server-subclass.rs +++ b/examples/src/bin/rtsp-server-subclass.rs @@ -121,17 +121,22 @@ mod media_factory { fn create_element(&self, _url: &gst_rtsp::RTSPUrl) -> Option { // 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(); diff --git a/examples/src/bin/subclass.rs b/examples/src/bin/subclass.rs index 62cde50ee..40336837a 100644 --- a/examples/src/bin/subclass.rs +++ b/examples/src/bin/subclass.rs @@ -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 { // 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; diff --git a/examples/src/bin/thumbnail.rs b/examples/src/bin/thumbnail.rs index 33f87f699..52d519050 100644 --- a/examples/src/bin/thumbnail.rs +++ b/examples/src/bin/thumbnail.rs @@ -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 { diff --git a/examples/src/bin/toc.rs b/examples/src/bin/toc.rs index 3e218a7dc..d7a9d79b9 100644 --- a/examples/src/bin/toc.rs +++ b/examples/src/bin/toc.rs @@ -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(); diff --git a/examples/src/bin/transmux.rs b/examples/src/bin/transmux.rs index b50ef90ff..403107420 100644 --- a/examples/src/bin/transmux.rs +++ b/examples/src/bin/transmux.rs @@ -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); diff --git a/examples/src/glupload.rs b/examples/src/glupload.rs index 7b007ae61..e13266de6 100644 --- a/examples/src/glupload.rs +++ b/examples/src/glupload.rs @@ -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::() .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)?; diff --git a/gstreamer-app/src/app_sink.rs b/gstreamer-app/src/app_sink.rs index 39a43837e..c46bb4d8e 100644 --- a/gstreamer-app/src/app_sink.rs +++ b/gstreamer-app/src/app_sink.rs @@ -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(); diff --git a/gstreamer-app/src/app_src.rs b/gstreamer-app/src/app_src.rs index e6dfbae0c..4c94f4cb7 100644 --- a/gstreamer-app/src/app_src.rs +++ b/gstreamer-app/src/app_src.rs @@ -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(); diff --git a/gstreamer/Gir.toml b/gstreamer/Gir.toml index b05d65b88..ba1a009d1 100644 --- a/gstreamer/Gir.toml +++ b/gstreamer/Gir.toml @@ -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" diff --git a/gstreamer/src/auto/element_factory.rs b/gstreamer/src/auto/element_factory.rs index 148fafd39..e8878291e 100644 --- a/gstreamer/src/auto/element_factory.rs +++ b/gstreamer/src/auto/element_factory.rs @@ -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 { - 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 { - 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 {} diff --git a/gstreamer/src/bin.rs b/gstreamer/src/bin.rs index d4dd784c2..8bdc27c3e 100644 --- a/gstreamer/src/bin.rs +++ b/gstreamer/src/bin.rs @@ -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() diff --git a/gstreamer/src/element.rs b/gstreamer/src/element.rs index f309a9134..2f439732e 100644 --- a/gstreamer/src/element.rs +++ b/gstreamer/src/element.rs @@ -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 |_| { diff --git a/gstreamer/src/element_factory.rs b/gstreamer/src/element_factory.rs index 07fe5bd5e..84ee8364d 100644 --- a/gstreamer/src/element_factory.rs +++ b/gstreamer/src/element_factory.rs @@ -25,64 +25,12 @@ impl ElementFactory { ) -> Result { 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::() - .unwrap(); - unsafe { - use std::sync::atomic; - - let klass = element.element_class(); - let factory_ptr: &atomic::AtomicPtr = - &*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory - as *const atomic::AtomicPtr); - 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 { 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 { + 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 { + 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(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 { + 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::::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::.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::() + .unwrap(); + + unsafe { + use std::sync::atomic; + + let klass = element.element_class(); + let factory_ptr: &atomic::AtomicPtr = + &*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory + as *const atomic::AtomicPtr); + 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) + } +} diff --git a/gstreamer/src/gobject.rs b/gstreamer/src/gobject.rs index e80e2f47e..be2645445 100644 --- a/gstreamer/src/gobject.rs +++ b/gstreamer/src/gobject.rs @@ -21,11 +21,25 @@ impl> 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(); diff --git a/gstreamer/src/iterator.rs b/gstreamer/src/iterator.rs index 9a916c69c..6f90dad9c 100644 --- a/gstreamer/src/iterator.rs +++ b/gstreamer/src/iterator.rs @@ -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(); diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 876e415ca..91255848c 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -145,7 +145,7 @@ pub use promise::{Promise, PromiseError}; pub mod bus; mod element; -mod element_factory; +pub mod element_factory; mod bin; diff --git a/gstreamer/src/object.rs b/gstreamer/src/object.rs index 2770904b4..62ac57524 100644 --- a/gstreamer/src/object.rs +++ b/gstreamer/src/object.rs @@ -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)); diff --git a/gstreamer/src/plugin_feature.rs b/gstreamer/src/plugin_feature.rs index e13f316fd..d6b76d0ef 100644 --- a/gstreamer/src/plugin_feature.rs +++ b/gstreamer/src/plugin_feature.rs @@ -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(); } } diff --git a/gstreamer/src/subclass/element.rs b/gstreamer/src/subclass/element.rs index 11245d53b..13bb9e144 100644 --- a/gstreamer/src/subclass/element.rs +++ b/gstreamer/src/subclass/element.rs @@ -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]) diff --git a/tutorials/src/bin/basic-tutorial-2.rs b/tutorials/src/bin/basic-tutorial-2.rs index 0cb0a8067..e73f3f71b 100644 --- a/tutorials/src/bin/basic-tutorial-2.rs +++ b/tutorials/src/bin/basic-tutorial-2.rs @@ -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) diff --git a/tutorials/src/bin/basic-tutorial-3.rs b/tutorials/src/bin/basic-tutorial-3.rs index e8de962b2..9fb436df8 100644 --- a/tutorials/src/bin/basic-tutorial-3.rs +++ b/tutorials/src/bin/basic-tutorial-3.rs @@ -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()); diff --git a/tutorials/src/bin/basic-tutorial-4.rs b/tutorials/src/bin/basic-tutorial-4.rs index 372cf1c65..47d9832bb 100644 --- a/tutorials/src/bin/basic-tutorial-4.rs +++ b/tutorials/src/bin/basic-tutorial-4.rs @@ -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 diff --git a/tutorials/src/bin/basic-tutorial-5.rs b/tutorials/src/bin/basic-tutorial-5.rs index 3bf3f6f58..41b7cd67c 100644 --- a/tutorials/src/bin/basic-tutorial-5.rs +++ b/tutorials/src/bin/basic-tutorial-5.rs @@ -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] diff --git a/tutorials/src/bin/basic-tutorial-6.rs b/tutorials/src/bin/basic-tutorial-6.rs index bca32490e..4af38968f 100644 --- a/tutorials/src/bin/basic-tutorial-6.rs +++ b/tutorials/src/bin/basic-tutorial-6.rs @@ -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 diff --git a/tutorials/src/bin/basic-tutorial-7.rs b/tutorials/src/bin/basic-tutorial-7.rs index d1113d570..37aafbcd1 100644 --- a/tutorials/src/bin/basic-tutorial-7.rs +++ b/tutorials/src/bin/basic-tutorial-7.rs @@ -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, diff --git a/tutorials/src/bin/basic-tutorial-8.rs b/tutorials/src/bin/basic-tutorial-8.rs index be5c220cd..cc747fec4 100644 --- a/tutorials/src/bin/basic-tutorial-8.rs +++ b/tutorials/src/bin/basic-tutorial-8.rs @@ -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, diff --git a/tutorials/src/bin/playback-tutorial-1.rs b/tutorials/src/bin/playback-tutorial-1.rs index 1366ea0a4..2ae670c2b 100644 --- a/tutorials/src/bin/playback-tutorial-1.rs +++ b/tutorials/src/bin/playback-tutorial-1.rs @@ -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(); diff --git a/tutorials/src/bin/playback-tutorial-2.rs b/tutorials/src/bin/playback-tutorial-2.rs index 34f4f9b24..4858edf32 100644 --- a/tutorials/src/bin/playback-tutorial-2.rs +++ b/tutorials/src/bin/playback-tutorial-2.rs @@ -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"); diff --git a/tutorials/src/bin/playback-tutorial-4.rs b/tutorials/src/bin/playback-tutorial-4.rs index f11c85a5d..1643e3572 100644 --- a/tutorials/src/bin/playback-tutorial-4.rs +++ b/tutorials/src/bin/playback-tutorial-4.rs @@ -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"); diff --git a/tutorials/src/bin/playback-tutorial-6.rs b/tutorials/src/bin/playback-tutorial-6.rs index 13e8cfe2a..cac0e5f74 100644 --- a/tutorials/src/bin/playback-tutorial-6.rs +++ b/tutorials/src/bin/playback-tutorial-6.rs @@ -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")?; diff --git a/tutorials/src/bin/playback-tutorial-7.rs b/tutorials/src/bin/playback-tutorial-7.rs index ac299150f..e736c2560 100644 --- a/tutorials/src/bin/playback-tutorial-7.rs +++ b/tutorials/src/bin/playback-tutorial-7.rs @@ -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