gstreamer: Manually implement Object::set_property_from_str() to be able to catch deserialization errors

This commit is contained in:
Sebastian Dröge 2021-08-17 08:47:42 +03:00
parent 43bfd1ae85
commit bdccaeee0d
9 changed files with 53 additions and 21 deletions

View file

@ -89,7 +89,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// The videotestsrc supports multiple test patterns. In this example, we will use the // 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. // 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. // The PangoFontMap represents the set of fonts available for a particular rendering system.
let fontmap = pangocairo::FontMap::new().unwrap(); let fontmap = pangocairo::FontMap::new().unwrap();

View file

@ -87,7 +87,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
// The videotestsrc supports multiple test patterns. In this example, we will use the // 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. // 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. // The PangoFontMap represents the set of fonts available for a particular rendering system.
let fontmap = pangocairo::FontMap::new().unwrap(); let fontmap = pangocairo::FontMap::new().unwrap();

View file

@ -135,7 +135,7 @@ fn example_main() -> Result<(), Error> {
pipeline.add_many(&[&enc, &mux, &sink])?; pipeline.add_many(&[&enc, &mux, &sink])?;
gst::Element::link_many(&[&filter, &enc, &mux, &sink])?; gst::Element::link_many(&[&filter, &enc, &mux, &sink])?;
sink.set_property("location", &"out.mkv")?; 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"); eprintln!("Recording to out.mkv");
} }
_ => return Err(Error::from(UsageError(args[0].clone()))), _ => return Err(Error::from(UsageError(args[0].clone()))),

View file

@ -151,14 +151,14 @@ fn example_main() -> Result<(), Error> {
let video_caps = gst::Caps::new_simple("video/x-raw", &[]); 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("host", &"127.0.0.1")?;
sink.set_property("sync", &true)?; sink.set_property("sync", &true)?;
enc.set_property("keyframe-max-dist", &30i32)?; enc.set_property("keyframe-max-dist", &30i32)?;
enc.set_property("threads", &12i32)?; enc.set_property("threads", &12i32)?;
enc.set_property("cpu-used", &(-16i32))?; enc.set_property("cpu-used", &(-16i32))?;
enc.set_property("deadline", &1i64)?; 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("expose-all-streams", &false)?;
src.set_property("caps", &video_caps)?; src.set_property("caps", &video_caps)?;
src.set_property("uri", &uri)?; src.set_property("uri", &uri)?;

View file

@ -273,7 +273,7 @@ fn create_pipeline() -> Result<gst::Pipeline, Error> {
filter.link(&conv)?; filter.link(&conv)?;
conv.link(&sink)?; 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, // Create a windowed sinc lowpass filter at 1/64 sample rate,
// i.e. 689Hz for 44.1kHz sample rate // i.e. 689Hz for 44.1kHz sample rate

View file

@ -1,20 +1,52 @@
// Take a look at the license at the top of the repository in the LICENSE file. // Take a look at the license at the top of the repository in the LICENSE file.
use crate::GstValueExt;
use glib::prelude::*; use glib::prelude::*;
use glib::translate::ToGlibPtr;
pub trait GObjectExtManualGst: 'static { 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<O: IsA<glib::Object>> GObjectExtManualGst for O { impl<O: IsA<glib::Object>> GObjectExtManualGst for O {
fn set_property_from_str(&self, name: &str, value: &str) { fn set_property_from_str(&self, name: &str, value: &str) -> Result<(), glib::BoolError> {
unsafe { let pspec = self.find_property(name).ok_or_else(|| {
ffi::gst_util_set_object_arg( glib::bool_error!("property '{}' of type '{}' not found", name, self.type_())
self.as_ref().to_glib_none().0, })?;
name.to_glib_none().0,
value.to_glib_none().0, let value = {
); if pspec.value_type() == crate::Structure::static_type() && value == "NULL" {
} None::<crate::Structure>.to_value()
} else {
#[cfg(feature = "v1_20")]
{
glib::Value::deserialize_with_pspec(value, &pspec)?
}
#[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");
} }
} }

View file

@ -21,7 +21,7 @@ fn tutorial_main() {
source.link(&sink).expect("Elements could not be linked."); source.link(&sink).expect("Elements could not be linked.");
// Modify the source's properties // Modify the source's properties
source.set_property_from_str("pattern", "smpte"); source.set_property_from_str("pattern", "smpte").unwrap();
// Start playing // Start playing
pipeline pipeline

View file

@ -25,8 +25,8 @@ fn tutorial_main() {
let pipeline = gst::Pipeline::new(Some("test-pipeline")); let pipeline = gst::Pipeline::new(Some("test-pipeline"));
audio_source.set_property("freq", &215.0).unwrap(); audio_source.set_property("freq", &215.0).unwrap();
visual.set_property_from_str("shader", "none"); visual.set_property_from_str("shader", "none").unwrap();
visual.set_property_from_str("style", "lines"); visual.set_property_from_str("style", "lines").unwrap();
pipeline pipeline
.add_many(&[ .add_many(&[

View file

@ -64,8 +64,8 @@ fn main() {
let pipeline = gst::Pipeline::new(Some("test-pipeline")); let pipeline = gst::Pipeline::new(Some("test-pipeline"));
visual.set_property_from_str("shader", "none"); visual.set_property_from_str("shader", "none").unwrap();
visual.set_property_from_str("style", "lines"); visual.set_property_from_str("style", "lines").unwrap();
pipeline pipeline
.add_many(&[ .add_many(&[