From bdccaeee0d69d150c7fe0009a578bf4c1f1b2cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 17 Aug 2021 08:47:42 +0300 Subject: [PATCH] gstreamer: Manually implement Object::set_property_from_str() to be able to catch deserialization errors --- examples/src/bin/overlay-composition.rs | 2 +- examples/src/bin/pango-cairo.rs | 2 +- examples/src/bin/rtpfecclient.rs | 2 +- examples/src/bin/rtpfecserver.rs | 4 +- examples/src/bin/subclass.rs | 2 +- gstreamer/src/gobject.rs | 52 ++++++++++++++++++++----- tutorials/src/bin/basic-tutorial-2.rs | 2 +- tutorials/src/bin/basic-tutorial-7.rs | 4 +- tutorials/src/bin/basic-tutorial-8.rs | 4 +- 9 files changed, 53 insertions(+), 21 deletions(-) diff --git a/examples/src/bin/overlay-composition.rs b/examples/src/bin/overlay-composition.rs index aece2d3f1..fb550cc2e 100644 --- a/examples/src/bin/overlay-composition.rs +++ b/examples/src/bin/overlay-composition.rs @@ -89,7 +89,7 @@ fn create_pipeline() -> Result { // 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"); + src.set_property_from_str("pattern", "ball").unwrap(); // The PangoFontMap represents the set of fonts available for a particular rendering system. let fontmap = pangocairo::FontMap::new().unwrap(); diff --git a/examples/src/bin/pango-cairo.rs b/examples/src/bin/pango-cairo.rs index 93415a4fc..417f8831c 100644 --- a/examples/src/bin/pango-cairo.rs +++ b/examples/src/bin/pango-cairo.rs @@ -87,7 +87,7 @@ fn create_pipeline() -> Result { // 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"); + src.set_property_from_str("pattern", "ball").unwrap(); // The PangoFontMap represents the set of fonts available for a particular rendering system. let fontmap = pangocairo::FontMap::new().unwrap(); diff --git a/examples/src/bin/rtpfecclient.rs b/examples/src/bin/rtpfecclient.rs index f9986c01a..78455f5a4 100644 --- a/examples/src/bin/rtpfecclient.rs +++ b/examples/src/bin/rtpfecclient.rs @@ -135,7 +135,7 @@ fn example_main() -> Result<(), Error> { 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"); + enc.set_property_from_str("tune", "zerolatency")?; eprintln!("Recording to out.mkv"); } _ => return Err(Error::from(UsageError(args[0].clone()))), diff --git a/examples/src/bin/rtpfecserver.rs b/examples/src/bin/rtpfecserver.rs index 64195a09c..fecd4ed86 100644 --- a/examples/src/bin/rtpfecserver.rs +++ b/examples/src/bin/rtpfecserver.rs @@ -151,14 +151,14 @@ fn example_main() -> Result<(), Error> { let video_caps = gst::Caps::new_simple("video/x-raw", &[]); - src.set_property_from_str("pattern", "ball"); + 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"); + 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)?; diff --git a/examples/src/bin/subclass.rs b/examples/src/bin/subclass.rs index 89e2630be..7256faef9 100644 --- a/examples/src/bin/subclass.rs +++ b/examples/src/bin/subclass.rs @@ -273,7 +273,7 @@ fn create_pipeline() -> Result { filter.link(&conv)?; conv.link(&sink)?; - src.set_property_from_str("wave", "white-noise"); + src.set_property_from_str("wave", "white-noise").unwrap(); // Create a windowed sinc lowpass filter at 1/64 sample rate, // i.e. 689Hz for 44.1kHz sample rate diff --git a/gstreamer/src/gobject.rs b/gstreamer/src/gobject.rs index 4c4682364..47050c5d7 100644 --- a/gstreamer/src/gobject.rs +++ b/gstreamer/src/gobject.rs @@ -1,20 +1,52 @@ // Take a look at the license at the top of the repository in the LICENSE file. +use crate::GstValueExt; use glib::prelude::*; -use glib::translate::ToGlibPtr; pub trait GObjectExtManualGst: 'static { - fn set_property_from_str(&self, name: &str, value: &str); + #[doc(alias = "gst_util_set_object_arg")] + fn set_property_from_str(&self, name: &str, value: &str) -> Result<(), glib::BoolError>; } impl> GObjectExtManualGst for O { - fn set_property_from_str(&self, name: &str, value: &str) { - unsafe { - ffi::gst_util_set_object_arg( - self.as_ref().to_glib_none().0, - name.to_glib_none().0, - value.to_glib_none().0, - ); - } + fn set_property_from_str(&self, name: &str, value: &str) -> Result<(), glib::BoolError> { + let pspec = self.find_property(name).ok_or_else(|| { + glib::bool_error!("property '{}' of type '{}' not found", name, self.type_()) + })?; + + 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)? + } + #[cfg(not(feature = "v1_20"))] + { + glib::Value::deserialize(value, pspec.value_type())? + } + } + }; + + self.set_property_from_value(name, &value) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_set_property_from_str() { + crate::init().unwrap(); + + let fakesink = crate::ElementFactory::make("fakesink", None).unwrap(); + fakesink + .set_property_from_str("state-error", "ready-to-paused") + .unwrap(); + let v = fakesink.property("state-error").unwrap(); + let e = glib::EnumValue::from_value(&v).unwrap(); + assert_eq!(e.nick(), "ready-to-paused"); } } diff --git a/tutorials/src/bin/basic-tutorial-2.rs b/tutorials/src/bin/basic-tutorial-2.rs index 0cb0a8067..ce70b09e4 100644 --- a/tutorials/src/bin/basic-tutorial-2.rs +++ b/tutorials/src/bin/basic-tutorial-2.rs @@ -21,7 +21,7 @@ fn tutorial_main() { source.link(&sink).expect("Elements could not be linked."); // Modify the source's properties - source.set_property_from_str("pattern", "smpte"); + source.set_property_from_str("pattern", "smpte").unwrap(); // Start playing pipeline diff --git a/tutorials/src/bin/basic-tutorial-7.rs b/tutorials/src/bin/basic-tutorial-7.rs index 3bc3f23ef..f0b96a765 100644 --- a/tutorials/src/bin/basic-tutorial-7.rs +++ b/tutorials/src/bin/basic-tutorial-7.rs @@ -25,8 +25,8 @@ fn tutorial_main() { let pipeline = gst::Pipeline::new(Some("test-pipeline")); audio_source.set_property("freq", &215.0).unwrap(); - visual.set_property_from_str("shader", "none"); - visual.set_property_from_str("style", "lines"); + visual.set_property_from_str("shader", "none").unwrap(); + visual.set_property_from_str("style", "lines").unwrap(); pipeline .add_many(&[ diff --git a/tutorials/src/bin/basic-tutorial-8.rs b/tutorials/src/bin/basic-tutorial-8.rs index ed24e454e..ff2624d17 100644 --- a/tutorials/src/bin/basic-tutorial-8.rs +++ b/tutorials/src/bin/basic-tutorial-8.rs @@ -64,8 +64,8 @@ fn main() { let pipeline = gst::Pipeline::new(Some("test-pipeline")); - visual.set_property_from_str("shader", "none"); - visual.set_property_from_str("style", "lines"); + visual.set_property_from_str("shader", "none").unwrap(); + visual.set_property_from_str("style", "lines").unwrap(); pipeline .add_many(&[