1use std::ffi::CStr;
4
5use glib::{prelude::*, translate::*};
6
7use crate::{
8 ffi, CapsRef, Element, ElementFactory, Rank, StaticPadTemplate, ELEMENT_METADATA_AUTHOR,
9 ELEMENT_METADATA_DESCRIPTION, ELEMENT_METADATA_DOC_URI, ELEMENT_METADATA_ICON_NAME,
10 ELEMENT_METADATA_KLASS, ELEMENT_METADATA_LONGNAME,
11};
12
13impl ElementFactory {
14 #[doc(alias = "gst_element_factory_create")]
15 #[doc(alias = "gst_element_factory_create_with_properties")]
16 #[track_caller]
17 pub fn create(&self) -> ElementBuilder {
18 assert_initialized_main_thread!();
19 ElementBuilder {
20 name_or_factory: NameOrFactory::Factory(self),
21 builder: crate::Object::builder_for_deferred_type(),
22 }
23 }
24
25 #[doc(alias = "gst_element_factory_make")]
26 #[doc(alias = "gst_element_factory_make_with_properties")]
27 #[track_caller]
28 pub fn make(factoryname: &str) -> ElementBuilder {
29 assert_initialized_main_thread!();
30 ElementBuilder {
31 name_or_factory: NameOrFactory::Name(factoryname),
32 builder: crate::Object::builder_for_deferred_type(),
33 }
34 }
35
36 #[doc(alias = "gst_element_factory_create")]
48 #[track_caller]
49 pub fn create_with_name(&self, name: Option<&str>) -> Result<Element, glib::BoolError> {
50 let mut builder = self.create();
51 if let Some(name) = name {
52 builder = builder.name(name);
53 }
54 builder.build()
55 }
56
57 #[doc(alias = "gst_element_factory_make")]
72 #[track_caller]
73 pub fn make_with_name(
74 factoryname: &str,
75 name: Option<&str>,
76 ) -> Result<Element, glib::BoolError> {
77 skip_assert_initialized!();
78 let mut builder = Self::make(factoryname);
79 if let Some(name) = name {
80 builder = builder.name(name);
81 }
82 builder.build()
83 }
84
85 #[doc(alias = "gst_element_factory_get_static_pad_templates")]
92 #[doc(alias = "get_static_pad_templates")]
93 pub fn static_pad_templates(&self) -> glib::List<StaticPadTemplate> {
94 unsafe {
95 glib::List::from_glib_none(ffi::gst_element_factory_get_static_pad_templates(
96 self.to_glib_none().0,
97 ))
98 }
99 }
100
101 #[doc(alias = "gst_element_factory_list_is_type")]
109 pub fn has_type(&self, type_: crate::ElementFactoryType) -> bool {
110 unsafe {
111 from_glib(ffi::gst_element_factory_list_is_type(
112 self.to_glib_none().0,
113 type_.into_glib(),
114 ))
115 }
116 }
117
118 #[doc(alias = "gst_element_factory_list_get_elements")]
132 pub fn factories_with_type(
133 type_: crate::ElementFactoryType,
134 minrank: Rank,
135 ) -> glib::List<ElementFactory> {
136 assert_initialized_main_thread!();
137 unsafe {
138 FromGlibPtrContainer::from_glib_full(ffi::gst_element_factory_list_get_elements(
139 type_.into_glib(),
140 minrank.into_glib(),
141 ))
142 }
143 }
144
145 #[doc(alias = "gst_element_factory_get_metadata")]
154 #[doc(alias = "get_metadata")]
155 pub fn metadata(&self, key: &str) -> Option<&str> {
156 unsafe {
157 let ptr =
158 ffi::gst_element_factory_get_metadata(self.to_glib_none().0, key.to_glib_none().0);
159
160 if ptr.is_null() {
161 None
162 } else {
163 Some(CStr::from_ptr(ptr).to_str().unwrap())
164 }
165 }
166 }
167
168 #[doc(alias = "get_longname")]
169 #[doc(alias = "gst_element_factory_get_longname")]
170 pub fn longname(&self) -> &str {
171 self.metadata(ELEMENT_METADATA_LONGNAME).unwrap()
172 }
173
174 #[doc(alias = "get_klass")]
175 #[doc(alias = "gst_element_factory_get_klass")]
176 pub fn klass(&self) -> &str {
177 self.metadata(ELEMENT_METADATA_KLASS).unwrap()
178 }
179
180 #[doc(alias = "get_description")]
181 #[doc(alias = "gst_element_factory_get_description")]
182 pub fn description(&self) -> &str {
183 self.metadata(ELEMENT_METADATA_DESCRIPTION).unwrap()
184 }
185
186 #[doc(alias = "get_author")]
187 #[doc(alias = "gst_element_factory_get_author")]
188 pub fn author(&self) -> &str {
189 self.metadata(ELEMENT_METADATA_AUTHOR).unwrap()
190 }
191
192 #[doc(alias = "get_documentation_uri")]
193 #[doc(alias = "gst_element_factory_get_documentation_uri")]
194 pub fn documentation_uri(&self) -> Option<&str> {
195 self.metadata(ELEMENT_METADATA_DOC_URI)
196 }
197
198 #[doc(alias = "get_icon_name")]
199 #[doc(alias = "gst_element_factory_get_icon_name")]
200 pub fn icon_name(&self) -> Option<&str> {
201 self.metadata(ELEMENT_METADATA_ICON_NAME)
202 }
203
204 #[doc(alias = "gst_element_factory_can_sink_all_caps")]
212 pub fn can_sink_all_caps(&self, caps: &CapsRef) -> bool {
213 unsafe {
214 from_glib(ffi::gst_element_factory_can_sink_all_caps(
215 self.to_glib_none().0,
216 caps.as_ptr(),
217 ))
218 }
219 }
220
221 #[doc(alias = "gst_element_factory_can_sink_any_caps")]
229 pub fn can_sink_any_caps(&self, caps: &CapsRef) -> bool {
230 unsafe {
231 from_glib(ffi::gst_element_factory_can_sink_any_caps(
232 self.to_glib_none().0,
233 caps.as_ptr(),
234 ))
235 }
236 }
237
238 #[doc(alias = "gst_element_factory_can_src_all_caps")]
246 pub fn can_src_all_caps(&self, caps: &CapsRef) -> bool {
247 unsafe {
248 from_glib(ffi::gst_element_factory_can_src_all_caps(
249 self.to_glib_none().0,
250 caps.as_ptr(),
251 ))
252 }
253 }
254
255 #[doc(alias = "gst_element_factory_can_src_any_caps")]
263 pub fn can_src_any_caps(&self, caps: &CapsRef) -> bool {
264 unsafe {
265 from_glib(ffi::gst_element_factory_can_src_any_caps(
266 self.to_glib_none().0,
267 caps.as_ptr(),
268 ))
269 }
270 }
271}
272
273#[must_use = "The builder must be built to be used"]
276pub struct ElementBuilder<'a> {
277 name_or_factory: NameOrFactory<'a>,
278 builder: crate::gobject::GObjectBuilder<'a, Element>,
279}
280
281#[derive(Copy, Clone)]
282enum NameOrFactory<'a> {
283 Name(&'a str),
284 Factory(&'a ElementFactory),
285}
286
287impl<'a> ElementBuilder<'a> {
288 #[inline]
293 pub fn property(self, name: &'a str, value: impl Into<glib::Value> + 'a) -> Self {
294 Self {
295 builder: self.builder.property(name, value),
296 ..self
297 }
298 }
299
300 #[inline]
303 pub fn property_from_str(self, name: &'a str, value: &'a str) -> Self {
304 Self {
305 builder: self.builder.property_from_str(name, value),
306 ..self
307 }
308 }
309
310 impl_builder_gvalue_extra_setters!(property_and_name);
311
312 #[track_caller]
324 #[must_use = "Building the element without using it has no effect"]
325 pub fn build(self) -> Result<Element, glib::BoolError> {
326 let mut _factory_found = None;
327 let factory = match self.name_or_factory {
328 NameOrFactory::Name(name) => {
329 let factory = ElementFactory::find(name).ok_or_else(|| {
330 crate::warning!(crate::CAT_RUST, "element factory '{}' not found", name);
331 glib::bool_error!(
332 "Failed to find element factory with name '{}' for creating element",
333 name
334 )
335 })?;
336 _factory_found = Some(factory);
337 _factory_found.as_ref().unwrap()
338 }
339 NameOrFactory::Factory(factory) => factory,
340 };
341
342 use crate::prelude::{
346 ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual,
347 };
348
349 let factory = factory.load().map_err(|_| {
350 crate::warning!(
351 crate::CAT_RUST,
352 obj = factory,
353 "loading element factory '{}' failed",
354 factory.name(),
355 );
356 glib::bool_error!(
357 "Failed to load element factory '{}' for creating element",
358 factory.name()
359 )
360 })?;
361
362 let element_type = factory.element_type();
363 if !element_type.is_valid() {
364 crate::warning!(
365 crate::CAT_RUST,
366 obj = &factory,
367 "element factory '{}' has no type",
368 factory.name()
369 );
370 return Err(glib::bool_error!(
371 "Failed to create element from factory '{}'",
372 factory.name()
373 ));
374 }
375
376 let element = self
377 .builder
378 .type_(element_type)
379 .build()
380 .map_err(|err| {
381 use crate::gobject::GObjectError::*;
382 match err {
383 PropertyNotFound { property, .. } => {
384 format!("property '{property}' of element factory '{}' not found", factory.name())
385 },
386 PropertyFromStr { property, value, .. } => {
387 format!("property '{property}' of element factory '{}' can't be set from string '{value}'", factory.name())
388 },
389 }
390 }).unwrap();
391
392 unsafe {
393 use std::sync::atomic;
394
395 let klass = element.element_class();
396 let factory_ptr: &atomic::AtomicPtr<ffi::GstElementFactory> =
397 &*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory
398 as *const atomic::AtomicPtr<ffi::GstElementFactory>);
399 if factory_ptr
400 .compare_exchange(
401 std::ptr::null_mut(),
402 factory.as_ptr(),
403 atomic::Ordering::SeqCst,
404 atomic::Ordering::SeqCst,
405 )
406 .is_ok()
407 {
408 factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED);
409 }
410
411 if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _)
412 != glib::ffi::GFALSE
413 {
414 glib::g_critical!(
415 "GStreamer",
416 "The created element should be floating, this is probably caused by faulty bindings",
417 );
418 }
419 }
420
421 crate::log!(
422 crate::CAT_RUST,
423 obj = &factory,
424 "created element \"{}\"",
425 factory.name()
426 );
427
428 Ok(element)
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435 use crate::prelude::*;
436
437 #[test]
438 fn builder() {
439 crate::init().unwrap();
440
441 let fakesink = ElementFactory::make("fakesink")
442 .name("test-fakesink")
443 .property("can-activate-pull", true)
444 .property_from_str("state-error", "ready-to-paused")
445 .build()
446 .unwrap();
447
448 assert_eq!(fakesink.name(), "test-fakesink");
449 assert!(fakesink.property::<bool>("can-activate-pull"));
450 let v = fakesink.property_value("state-error");
451 let (_klass, e) = glib::EnumValue::from_value(&v).unwrap();
452 assert_eq!(e.nick(), "ready-to-paused");
453 }
454}