diff --git a/examples/src/bin/appsink.rs b/examples/src/bin/appsink.rs index 8a777fee6..687c90434 100644 --- a/examples/src/bin/appsink.rs +++ b/examples/src/bin/appsink.rs @@ -35,7 +35,7 @@ struct ErrorMessage { fn create_pipeline() -> Result { gst::init()?; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("audiotestsrc").build()?; let appsink = gst_app::AppSink::builder() // Tell the appsink what format we want. It will then be the audiotestsrc's job to diff --git a/examples/src/bin/appsrc.rs b/examples/src/bin/appsrc.rs index 6dc3b6fdb..e1020edd4 100644 --- a/examples/src/bin/appsrc.rs +++ b/examples/src/bin/appsrc.rs @@ -33,7 +33,7 @@ const HEIGHT: usize = 240; fn create_pipeline() -> Result { gst::init()?; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); // Specify the format we want to provide as application into the pipeline // by creating a video info with the given format and creating caps from it for the appsrc element. diff --git a/examples/src/bin/cairo_compositor.rs b/examples/src/bin/cairo_compositor.rs index 48401b991..309b00732 100644 --- a/examples/src/bin/cairo_compositor.rs +++ b/examples/src/bin/cairo_compositor.rs @@ -566,7 +566,7 @@ fn create_pipeline() -> Result { gst::init()?; // Create our pipeline with the compositor and two input streams. - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src1 = gst::ElementFactory::make("videotestsrc") .property_from_str("pattern", "ball") .build()?; diff --git a/examples/src/bin/custom_meta.rs b/examples/src/bin/custom_meta.rs index 1c462ad58..a129d99e5 100644 --- a/examples/src/bin/custom_meta.rs +++ b/examples/src/bin/custom_meta.rs @@ -181,7 +181,7 @@ fn example_main() { gst::init().unwrap(); // This creates a pipeline with appsrc and appsink. - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let appsrc = gst_app::AppSrc::builder().build(); let appsink = gst_app::AppSink::builder().build(); diff --git a/examples/src/bin/decodebin.rs b/examples/src/bin/decodebin.rs index b7204e544..9726e78dd 100644 --- a/examples/src/bin/decodebin.rs +++ b/examples/src/bin/decodebin.rs @@ -66,7 +66,7 @@ fn example_main() -> Result<(), Error> { std::process::exit(-1) }; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("filesrc") .property("location", uri) .build()?; diff --git a/examples/src/bin/encodebin.rs b/examples/src/bin/encodebin.rs index bb6d6b492..163c01765 100644 --- a/examples/src/bin/encodebin.rs +++ b/examples/src/bin/encodebin.rs @@ -85,7 +85,7 @@ fn example_main() -> Result<(), Error> { std::process::exit(-1) }; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("uridecodebin") .property("uri", uri) .build()?; diff --git a/examples/src/bin/fd_allocator.rs b/examples/src/bin/fd_allocator.rs index f9cb8fc95..93d632d5c 100644 --- a/examples/src/bin/fd_allocator.rs +++ b/examples/src/bin/fd_allocator.rs @@ -46,7 +46,7 @@ fn create_receiver_pipeline( ) -> Result { let caps = video_info.to_caps()?; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst_app::AppSrc::builder() .caps(&caps) .do_timestamp(true) @@ -117,7 +117,7 @@ fn create_sender_pipeline( let sender = Arc::new(Mutex::new(sender)); let caps = video_info.to_caps()?; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("videotestsrc") .property("num-buffers", 250i32) .build()?; diff --git a/examples/src/bin/gtksink.rs b/examples/src/bin/gtksink.rs index 82845a99d..d7adce5c0 100644 --- a/examples/src/bin/gtksink.rs +++ b/examples/src/bin/gtksink.rs @@ -19,7 +19,7 @@ use gtk::prelude::*; use std::cell::RefCell; fn create_ui(app: >k::Application) { - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); 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. diff --git a/examples/src/bin/gtkvideooverlay.rs b/examples/src/bin/gtkvideooverlay.rs index 92c13f4aa..5da1f7e04 100644 --- a/examples/src/bin/gtkvideooverlay.rs +++ b/examples/src/bin/gtkvideooverlay.rs @@ -101,7 +101,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 pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("videotestsrc").build().unwrap(); // Since using the window system to overlay our gui window is making diff --git a/examples/src/bin/overlay-composition.rs b/examples/src/bin/overlay-composition.rs index 412c313d3..f449e3000 100644 --- a/examples/src/bin/overlay-composition.rs +++ b/examples/src/bin/overlay-composition.rs @@ -53,7 +53,7 @@ unsafe impl Send for LayoutWrapper {} fn create_pipeline() -> Result { gst::init()?; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); // 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. diff --git a/examples/src/bin/pango-cairo.rs b/examples/src/bin/pango-cairo.rs index f9440f761..22ca3c119 100644 --- a/examples/src/bin/pango-cairo.rs +++ b/examples/src/bin/pango-cairo.rs @@ -56,7 +56,7 @@ unsafe impl Send for LayoutWrapper {} fn create_pipeline() -> Result { gst::init()?; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); 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. diff --git a/examples/src/bin/rtpfecclient.rs b/examples/src/bin/rtpfecclient.rs index 75d5621ee..a5c3e1f27 100644 --- a/examples/src/bin/rtpfecclient.rs +++ b/examples/src/bin/rtpfecclient.rs @@ -87,7 +87,7 @@ fn example_main() -> Result<(), Error> { let drop_probability = args[2].parse::()?; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let rtp_caps = gst::Caps::builder("application/x-rtp") .field("clock-rate", 90000i32) diff --git a/examples/src/bin/rtpfecserver.rs b/examples/src/bin/rtpfecserver.rs index 721f0bf6d..a02ff1478 100644 --- a/examples/src/bin/rtpfecserver.rs +++ b/examples/src/bin/rtpfecserver.rs @@ -77,7 +77,7 @@ fn example_main() -> Result<(), Error> { let video_caps = gst::Caps::builder("video/x-raw").build(); - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("uridecodebin") .property_from_str("pattern", "ball") .property("expose-all-streams", false) diff --git a/examples/src/bin/rtsp-server-subclass.rs b/examples/src/bin/rtsp-server-subclass.rs index 58f040b0c..b88be20b0 100644 --- a/examples/src/bin/rtsp-server-subclass.rs +++ b/examples/src/bin/rtsp-server-subclass.rs @@ -120,7 +120,7 @@ mod media_factory { impl RTSPMediaFactoryImpl for Factory { fn create_element(&self, _url: &gst_rtsp::RTSPUrl) -> Option { // Create a simple VP8 videotestsrc input - let bin = gst::Bin::new(None); + let bin = gst::Bin::default(); let src = gst::ElementFactory::make("videotestsrc") // Configure the videotestsrc live .property("is-live", true) diff --git a/examples/src/bin/subclass.rs b/examples/src/bin/subclass.rs index 40336837a..9c32c85f8 100644 --- a/examples/src/bin/subclass.rs +++ b/examples/src/bin/subclass.rs @@ -244,7 +244,7 @@ fn create_pipeline() -> Result { gst::init()?; // Create our pipeline with the custom element - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("audiotestsrc") .property_from_str("wave", "white-noise") .build()?; diff --git a/examples/src/bin/toc.rs b/examples/src/bin/toc.rs index d7a9d79b9..3edffb013 100644 --- a/examples/src/bin/toc.rs +++ b/examples/src/bin/toc.rs @@ -27,7 +27,7 @@ fn example_main() { std::process::exit(-1) }; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("filesrc") .property("location", uri) .build() diff --git a/examples/src/bin/transmux.rs b/examples/src/bin/transmux.rs index 403107420..535de3048 100644 --- a/examples/src/bin/transmux.rs +++ b/examples/src/bin/transmux.rs @@ -52,7 +52,7 @@ fn example_main() -> Result<(), Error> { std::process::exit(-1) }; - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); 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").build()?; diff --git a/examples/src/glupload.rs b/examples/src/glupload.rs index 30a5b2b9e..19597f458 100644 --- a/examples/src/glupload.rs +++ b/examples/src/glupload.rs @@ -530,7 +530,7 @@ impl App { fn create_pipeline( gl_element: Option<&gst::Element>, ) -> Result<(gst::Pipeline, gst_app::AppSink, gst::Element), Error> { - let pipeline = gst::Pipeline::new(None); + let pipeline = gst::Pipeline::default(); let src = gst::ElementFactory::make("videotestsrc").build()?; let caps = gst_video::VideoCapsBuilder::new() diff --git a/gstreamer/src/bin.rs b/gstreamer/src/bin.rs index 8bdc27c3e..6df65366a 100644 --- a/gstreamer/src/bin.rs +++ b/gstreamer/src/bin.rs @@ -15,6 +15,16 @@ use std::boxed::Box as Box_; use std::mem::transmute; use std::path; +impl Bin { + // rustdoc-stripper-ignore-next + /// Creates a new builder-pattern struct instance to construct [`Bin`] objects. + /// + /// This method returns an instance of [`BinBuilder`](crate::builders::BinBuilder) which can be used to create [`Bin`] objects. + pub fn builder() -> BinBuilder { + BinBuilder::default() + } +} + pub trait GstBinExtManual: 'static { #[doc(alias = "gst_bin_add_many")] fn add_many>(&self, elements: &[&E]) -> Result<(), glib::BoolError>; @@ -215,6 +225,64 @@ impl> GstBinExtManual for O { } } +impl Default for Bin { + fn default() -> Self { + glib::object::Object::new::(&[]) + } +} + +#[derive(Clone, Default)] +// rustdoc-stripper-ignore-next +/// A [builder-pattern] type to construct [`Bin`] objects. +/// +/// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html +#[must_use = "The builder must be built to be used"] +pub struct BinBuilder { + async_handling: Option, + message_forward: Option, + name: Option, +} + +impl BinBuilder { + // rustdoc-stripper-ignore-next + /// Create a new [`BinBuilder`]. + pub fn new() -> Self { + Self::default() + } + + // rustdoc-stripper-ignore-next + /// Build the [`Bin`]. + #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] + pub fn build(self) -> Bin { + let mut properties: Vec<(&str, &dyn ToValue)> = vec![]; + if let Some(ref async_handling) = self.async_handling { + properties.push(("async-handling", async_handling)); + } + if let Some(ref message_forward) = self.message_forward { + properties.push(("message-forward", message_forward)); + } + if let Some(ref name) = self.name { + properties.push(("name", name)); + } + glib::Object::new::(&properties) + } + + pub fn async_handling(mut self, async_handling: bool) -> Self { + self.async_handling = Some(async_handling); + self + } + + pub fn message_forward(mut self, message_forward: bool) -> Self { + self.message_forward = Some(message_forward); + self + } + + pub fn name(mut self, name: &str) -> Self { + self.name = Some(name.to_string()); + self + } +} + unsafe extern "C" fn do_latency_trampoline< P, F: Fn(&P) -> Result<(), LoggableError> + Send + Sync + 'static, diff --git a/gstreamer/src/pipeline.rs b/gstreamer/src/pipeline.rs index 1de699fda..f8e21d561 100644 --- a/gstreamer/src/pipeline.rs +++ b/gstreamer/src/pipeline.rs @@ -3,8 +3,19 @@ use glib::prelude::*; use glib::translate::*; +use crate::Pipeline; use crate::PipelineFlags; +impl Pipeline { + // rustdoc-stripper-ignore-next + /// Creates a new builder-pattern struct instance to construct [`Pipeline`] objects. + /// + /// This method returns an instance of [`PipelineBuilder`](crate::builders::PipelineBuilder) which can be used to create [`Pipeline`] objects. + pub fn builder() -> PipelineBuilder { + PipelineBuilder::default() + } +} + pub trait GstPipelineExtManual: 'static { fn set_pipeline_flags(&self, flags: PipelineFlags); @@ -39,3 +50,88 @@ impl> GstPipelineExtManual for O { } } } + +impl Default for Pipeline { + fn default() -> Self { + glib::object::Object::new::(&[]) + } +} + +#[derive(Clone, Default)] +// rustdoc-stripper-ignore-next +/// A [builder-pattern] type to construct [`Pipeline`] objects. +/// +/// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html +#[must_use = "The builder must be built to be used"] +pub struct PipelineBuilder { + auto_flush_bus: Option, + delay: Option, + latency: Option, + async_handling: Option, + message_forward: Option, + name: Option, +} + +impl PipelineBuilder { + // rustdoc-stripper-ignore-next + /// Create a new [`PipelineBuilder`]. + pub fn new() -> Self { + Self::default() + } + + // rustdoc-stripper-ignore-next + /// Build the [`Pipeline`]. + #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"] + pub fn build(self) -> Pipeline { + let mut properties: Vec<(&str, &dyn ToValue)> = vec![]; + if let Some(ref auto_flush_bus) = self.auto_flush_bus { + properties.push(("auto-flush-bus", auto_flush_bus)); + } + if let Some(ref delay) = self.delay { + properties.push(("delay", delay)); + } + if let Some(ref latency) = self.latency { + properties.push(("latency", latency)); + } + if let Some(ref async_handling) = self.async_handling { + properties.push(("async-handling", async_handling)); + } + if let Some(ref message_forward) = self.message_forward { + properties.push(("message-forward", message_forward)); + } + if let Some(ref name) = self.name { + properties.push(("name", name)); + } + glib::Object::new::(&properties) + } + + pub fn auto_flush_bus(mut self, auto_flush_bus: bool) -> Self { + self.auto_flush_bus = Some(auto_flush_bus); + self + } + + pub fn delay(mut self, delay: u64) -> Self { + self.delay = Some(delay); + self + } + + pub fn latency(mut self, latency: u64) -> Self { + self.latency = Some(latency); + self + } + + pub fn async_handling(mut self, async_handling: bool) -> Self { + self.async_handling = Some(async_handling); + self + } + + pub fn message_forward(mut self, message_forward: bool) -> Self { + self.message_forward = Some(message_forward); + self + } + + pub fn name(mut self, name: &str) -> Self { + self.name = Some(name.to_string()); + self + } +} diff --git a/tutorials/src/bin/basic-tutorial-2.rs b/tutorials/src/bin/basic-tutorial-2.rs index e73f3f71b..febb83473 100644 --- a/tutorials/src/bin/basic-tutorial-2.rs +++ b/tutorials/src/bin/basic-tutorial-2.rs @@ -19,7 +19,7 @@ fn tutorial_main() { .expect("Could not create sink element"); // Create the empty pipeline - let pipeline = gst::Pipeline::new(Some("test-pipeline")); + let pipeline = gst::Pipeline::builder().name("test-pipeline").build(); // Build the pipeline pipeline.add_many(&[&source, &sink]).unwrap(); diff --git a/tutorials/src/bin/basic-tutorial-3.rs b/tutorials/src/bin/basic-tutorial-3.rs index 9fb436df8..858d62390 100644 --- a/tutorials/src/bin/basic-tutorial-3.rs +++ b/tutorials/src/bin/basic-tutorial-3.rs @@ -31,7 +31,7 @@ fn tutorial_main() { .expect("Could not create resample element."); // Create the empty pipeline - let pipeline = gst::Pipeline::new(Some("test-pipeline")); + let pipeline = gst::Pipeline::builder().name("test-pipeline").build(); // Build the pipeline Note that we are NOT linking the source at this // point. We will do it later. diff --git a/tutorials/src/bin/basic-tutorial-6.rs b/tutorials/src/bin/basic-tutorial-6.rs index 4af38968f..667d9309c 100644 --- a/tutorials/src/bin/basic-tutorial-6.rs +++ b/tutorials/src/bin/basic-tutorial-6.rs @@ -101,7 +101,7 @@ fn tutorial_main() { .expect("Failed to create sink element"); // Create the empty pipeline - let pipeline = gst::Pipeline::new(Some("test-pipeline")); + let pipeline = gst::Pipeline::builder().name("test-pipeline").build(); pipeline.add_many(&[&source, &sink]).unwrap(); source.link(&sink).expect("Elements could not be linked."); diff --git a/tutorials/src/bin/basic-tutorial-7.rs b/tutorials/src/bin/basic-tutorial-7.rs index 37aafbcd1..65fcec204 100644 --- a/tutorials/src/bin/basic-tutorial-7.rs +++ b/tutorials/src/bin/basic-tutorial-7.rs @@ -54,7 +54,7 @@ fn tutorial_main() { .build() .unwrap(); - let pipeline = gst::Pipeline::new(Some("test-pipeline")); + let pipeline = gst::Pipeline::builder().name("test-pipeline").build(); pipeline .add_many(&[ diff --git a/tutorials/src/bin/basic-tutorial-8.rs b/tutorials/src/bin/basic-tutorial-8.rs index 1c03aebf5..e7822bb67 100644 --- a/tutorials/src/bin/basic-tutorial-8.rs +++ b/tutorials/src/bin/basic-tutorial-8.rs @@ -108,7 +108,7 @@ fn main() { .name("app_sink") .build(); - let pipeline = gst::Pipeline::new(Some("test-pipeline")); + let pipeline = gst::Pipeline::builder().name("test-pipeline").build(); pipeline .add_many(&[ diff --git a/tutorials/src/bin/playback-tutorial-7.rs b/tutorials/src/bin/playback-tutorial-7.rs index e736c2560..8e3fc8c36 100644 --- a/tutorials/src/bin/playback-tutorial-7.rs +++ b/tutorials/src/bin/playback-tutorial-7.rs @@ -28,7 +28,7 @@ fn tutorial_main() -> Result<(), Error> { .expect("Could not create autoaudiosink element."); // Create the sink bin, add the elements and link them - let bin = gst::Bin::new(Some("audio_sink_bin")); + let bin = gst::Bin::builder().name("audio_sink_bin").build(); bin.add_many(&[&equalizer, &convert, &sink]).unwrap(); gst::Element::link_many(&[&equalizer, &convert, &sink]).expect("Failed to link elements.");