gstreamer: Implement ElementFactory::create_with_properties() manually

This way we can get the same property checks as normal object
construction would provide.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/issues/402
This commit is contained in:
Sebastian Dröge 2022-10-18 18:08:50 +03:00 committed by Sebastian Dröge
parent 5495acf77d
commit 9c282ec7c3

View file

@ -22,54 +22,99 @@ impl ElementFactory {
#[cfg(any(feature = "v1_20", feature = "dox"))] #[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
#[doc(alias = "gst_element_factory_create_with_properties")] #[doc(alias = "gst_element_factory_create_with_properties")]
#[track_caller]
pub fn create_with_properties( pub fn create_with_properties(
&self, &self,
properties: &[(&str, &dyn ToValue)], properties: &[(&str, &dyn ToValue)],
) -> Result<Element, glib::BoolError> { ) -> Result<Element, glib::BoolError> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
let n = properties.len() as u32;
let names = properties.iter().map(|(name, _)| *name).collect::<Vec<_>>();
let values = properties
.iter()
.map(|(_, value)| value.to_value())
.collect::<Vec<_>>();
unsafe { // The below is basically a reimplementation of the C function. We want to call
Option::<_>::from_glib_none(ffi::gst_element_factory_create_with_properties( // glib::Object::with_type() ourselves here for checking properties and their values
self.to_glib_none().0, // correctly and to provide consistent behaviour.
n, use crate::prelude::{
names.to_glib_none().0, ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual,
values.as_ptr() as *const glib::gobject_ffi::GValue, };
))
.ok_or_else(|| glib::bool_error!("Failed to create element from factory")) let factory = self.load().map_err(|_| {
crate::warning!(crate::CAT_RUST, obj: self, "loading plugin returned None");
glib::bool_error!("Failed to create element from factory")
})?;
let element_type = factory.element_type();
if !element_type.is_valid() {
crate::warning!(crate::CAT_RUST, obj: self, "factory has no type");
return Err(glib::bool_error!("Failed to create element from factory"));
} }
let element = glib::Object::with_type(element_type, properties)
.downcast::<crate::Element>()
.unwrap();
unsafe {
use std::sync::atomic;
let klass = element.element_class();
let factory_ptr: &atomic::AtomicPtr<ffi::GstElementFactory> =
&*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory
as *const atomic::AtomicPtr<ffi::GstElementFactory>);
if factory_ptr
.compare_exchange(
std::ptr::null_mut(),
factory.as_ptr(),
atomic::Ordering::SeqCst,
atomic::Ordering::SeqCst,
)
.is_ok()
{
factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED);
}
if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _)
!= glib::ffi::GFALSE
{
glib::g_critical!(
"GStreamer",
"The created element should be floating, this is probably caused by faulty bindings",
);
}
}
crate::log!(
crate::CAT_RUST,
obj: self,
"created element \"{}\"",
factory.name()
);
Ok(element)
} }
#[cfg(any(feature = "v1_20", feature = "dox"))] #[cfg(any(feature = "v1_20", feature = "dox"))]
#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))]
#[doc(alias = "gst_element_factory_make_with_properties")] #[doc(alias = "gst_element_factory_make_with_properties")]
#[track_caller]
pub fn make_with_properties( pub fn make_with_properties(
factoryname: &str, factoryname: &str,
properties: &[(&str, &dyn ToValue)], properties: &[(&str, &dyn ToValue)],
) -> Result<Element, glib::BoolError> { ) -> Result<Element, glib::BoolError> {
assert_initialized_main_thread!(); assert_initialized_main_thread!();
let n = properties.len() as u32;
let names = properties.iter().map(|(name, _)| *name).collect::<Vec<_>>();
let values = properties
.iter()
.map(|(_, value)| value.to_value())
.collect::<Vec<_>>();
assert_initialized_main_thread!(); crate::log!(
unsafe { crate::CAT_RUST,
Option::<_>::from_glib_none(ffi::gst_element_factory_make_with_properties( "gstelementfactory: make \"{}\"",
factoryname.to_glib_none().0, factoryname
n, );
names.to_glib_none().0,
values.as_ptr() as *const glib::gobject_ffi::GValue, let factory = Self::find(factoryname).ok_or_else(|| {
)) crate::warning!(
.ok_or_else(|| glib::bool_error!("Failed to create element from factory name")) crate::CAT_RUST,
} "gstelementfactory: make \"{}\"",
factoryname
);
glib::bool_error!("Failed to create element from factory name")
})?;
factory.create_with_properties(properties)
} }
#[doc(alias = "gst_element_factory_get_static_pad_templates")] #[doc(alias = "gst_element_factory_get_static_pad_templates")]