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
20 ElementBuilder {
21 name_or_factory: NameOrFactory::Factory(self),
22 properties: smallvec::SmallVec::new(),
23 }
24 }
25
26 #[doc(alias = "gst_element_factory_make")]
27 #[doc(alias = "gst_element_factory_make_with_properties")]
28 #[track_caller]
29 pub fn make(factoryname: &str) -> ElementBuilder {
30 assert_initialized_main_thread!();
31
32 ElementBuilder {
33 name_or_factory: NameOrFactory::Name(factoryname),
34 properties: smallvec::SmallVec::new(),
35 }
36 }
37
38 #[doc(alias = "gst_element_factory_create")]
50 #[track_caller]
51 pub fn create_with_name(&self, name: Option<&str>) -> Result<Element, glib::BoolError> {
52 let mut builder = self.create();
53 if let Some(name) = name {
54 builder = builder.name(name);
55 }
56 builder.build()
57 }
58
59 #[doc(alias = "gst_element_factory_make")]
74 #[track_caller]
75 pub fn make_with_name(
76 factoryname: &str,
77 name: Option<&str>,
78 ) -> Result<Element, glib::BoolError> {
79 skip_assert_initialized!();
80 let mut builder = Self::make(factoryname);
81 if let Some(name) = name {
82 builder = builder.name(name);
83 }
84 builder.build()
85 }
86
87 #[doc(alias = "gst_element_factory_get_static_pad_templates")]
94 #[doc(alias = "get_static_pad_templates")]
95 pub fn static_pad_templates(&self) -> glib::List<StaticPadTemplate> {
96 unsafe {
97 glib::List::from_glib_none(ffi::gst_element_factory_get_static_pad_templates(
98 self.to_glib_none().0,
99 ))
100 }
101 }
102
103 #[doc(alias = "gst_element_factory_list_is_type")]
111 pub fn has_type(&self, type_: crate::ElementFactoryType) -> bool {
112 unsafe {
113 from_glib(ffi::gst_element_factory_list_is_type(
114 self.to_glib_none().0,
115 type_.into_glib(),
116 ))
117 }
118 }
119
120 #[doc(alias = "gst_element_factory_list_get_elements")]
134 pub fn factories_with_type(
135 type_: crate::ElementFactoryType,
136 minrank: Rank,
137 ) -> glib::List<ElementFactory> {
138 assert_initialized_main_thread!();
139 unsafe {
140 FromGlibPtrContainer::from_glib_full(ffi::gst_element_factory_list_get_elements(
141 type_.into_glib(),
142 minrank.into_glib(),
143 ))
144 }
145 }
146
147 #[doc(alias = "gst_element_factory_get_metadata")]
156 #[doc(alias = "get_metadata")]
157 pub fn metadata(&self, key: &str) -> Option<&str> {
158 unsafe {
159 let ptr =
160 ffi::gst_element_factory_get_metadata(self.to_glib_none().0, key.to_glib_none().0);
161
162 if ptr.is_null() {
163 None
164 } else {
165 Some(CStr::from_ptr(ptr).to_str().unwrap())
166 }
167 }
168 }
169
170 #[doc(alias = "get_longname")]
171 #[doc(alias = "gst_element_factory_get_longname")]
172 pub fn longname(&self) -> &str {
173 self.metadata(ELEMENT_METADATA_LONGNAME).unwrap()
174 }
175
176 #[doc(alias = "get_klass")]
177 #[doc(alias = "gst_element_factory_get_klass")]
178 pub fn klass(&self) -> &str {
179 self.metadata(ELEMENT_METADATA_KLASS).unwrap()
180 }
181
182 #[doc(alias = "get_description")]
183 #[doc(alias = "gst_element_factory_get_description")]
184 pub fn description(&self) -> &str {
185 self.metadata(ELEMENT_METADATA_DESCRIPTION).unwrap()
186 }
187
188 #[doc(alias = "get_author")]
189 #[doc(alias = "gst_element_factory_get_author")]
190 pub fn author(&self) -> &str {
191 self.metadata(ELEMENT_METADATA_AUTHOR).unwrap()
192 }
193
194 #[doc(alias = "get_documentation_uri")]
195 #[doc(alias = "gst_element_factory_get_documentation_uri")]
196 pub fn documentation_uri(&self) -> Option<&str> {
197 self.metadata(ELEMENT_METADATA_DOC_URI)
198 }
199
200 #[doc(alias = "get_icon_name")]
201 #[doc(alias = "gst_element_factory_get_icon_name")]
202 pub fn icon_name(&self) -> Option<&str> {
203 self.metadata(ELEMENT_METADATA_ICON_NAME)
204 }
205
206 #[doc(alias = "gst_element_factory_can_sink_all_caps")]
214 pub fn can_sink_all_caps(&self, caps: &CapsRef) -> bool {
215 unsafe {
216 from_glib(ffi::gst_element_factory_can_sink_all_caps(
217 self.to_glib_none().0,
218 caps.as_ptr(),
219 ))
220 }
221 }
222
223 #[doc(alias = "gst_element_factory_can_sink_any_caps")]
231 pub fn can_sink_any_caps(&self, caps: &CapsRef) -> bool {
232 unsafe {
233 from_glib(ffi::gst_element_factory_can_sink_any_caps(
234 self.to_glib_none().0,
235 caps.as_ptr(),
236 ))
237 }
238 }
239
240 #[doc(alias = "gst_element_factory_can_src_all_caps")]
248 pub fn can_src_all_caps(&self, caps: &CapsRef) -> bool {
249 unsafe {
250 from_glib(ffi::gst_element_factory_can_src_all_caps(
251 self.to_glib_none().0,
252 caps.as_ptr(),
253 ))
254 }
255 }
256
257 #[doc(alias = "gst_element_factory_can_src_any_caps")]
265 pub fn can_src_any_caps(&self, caps: &CapsRef) -> bool {
266 unsafe {
267 from_glib(ffi::gst_element_factory_can_src_any_caps(
268 self.to_glib_none().0,
269 caps.as_ptr(),
270 ))
271 }
272 }
273}
274
275#[must_use = "The builder must be built to be used"]
278pub struct ElementBuilder<'a> {
279 name_or_factory: NameOrFactory<'a>,
280 properties: smallvec::SmallVec<[(&'a str, ValueOrStr<'a>); 16]>,
281}
282
283#[derive(Copy, Clone)]
284enum NameOrFactory<'a> {
285 Name(&'a str),
286 Factory(&'a ElementFactory),
287}
288
289enum ValueOrStr<'a> {
290 Value(glib::Value),
291 Str(&'a str),
292}
293
294impl<'a> ElementBuilder<'a> {
295 #[inline]
298 pub fn name(self, name: impl Into<glib::GString>) -> Self {
299 self.property("name", name.into())
300 }
301
302 #[inline]
305 pub fn name_if_some(self, name: Option<impl Into<glib::GString>>) -> Self {
306 if let Some(name) = name {
307 self.name(name)
308 } else {
309 self
310 }
311 }
312
313 #[inline]
318 pub fn property(self, name: &'a str, value: impl Into<glib::Value> + 'a) -> Self {
319 Self {
320 name_or_factory: self.name_or_factory,
321 properties: {
322 let mut properties = self.properties;
323 properties.push((name, ValueOrStr::Value(value.into())));
324 properties
325 },
326 }
327 }
328
329 impl_builder_gvalue_extra_setters!(property);
330
331 #[inline]
334 pub fn property_from_str(self, name: &'a str, value: &'a str) -> Self {
335 Self {
336 name_or_factory: self.name_or_factory,
337 properties: {
338 let mut properties = self.properties;
339 properties.push((name, ValueOrStr::Str(value)));
340 properties
341 },
342 }
343 }
344
345 #[inline]
348 pub fn property_from_str_if_some(self, name: &'a str, value: Option<&'a str>) -> Self {
349 if let Some(value) = value {
350 self.property_from_str(name, value)
351 } else {
352 self
353 }
354 }
355
356 #[track_caller]
366 #[must_use = "Building the element without using it has no effect"]
367 pub fn build(self) -> Result<Element, glib::BoolError> {
368 let mut _factory_found = None;
369 let factory = match self.name_or_factory {
370 NameOrFactory::Name(name) => {
371 let factory = ElementFactory::find(name).ok_or_else(|| {
372 crate::warning!(crate::CAT_RUST, "element factory '{}' not found", name);
373 glib::bool_error!(
374 "Failed to find element factory with name '{}' for creating element",
375 name
376 )
377 })?;
378 _factory_found = Some(factory);
379 _factory_found.as_ref().unwrap()
380 }
381 NameOrFactory::Factory(factory) => factory,
382 };
383
384 use crate::prelude::{
388 ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual,
389 };
390
391 let factory = factory.load().map_err(|_| {
392 crate::warning!(
393 crate::CAT_RUST,
394 obj = factory,
395 "loading element factory '{}' failed",
396 factory.name(),
397 );
398 glib::bool_error!(
399 "Failed to load element factory '{}' for creating element",
400 factory.name()
401 )
402 })?;
403
404 let element_type = factory.element_type();
405 if !element_type.is_valid() {
406 crate::warning!(
407 crate::CAT_RUST,
408 obj = &factory,
409 "element factory '{}' has no type",
410 factory.name()
411 );
412 return Err(glib::bool_error!(
413 "Failed to create element from factory '{}'",
414 factory.name()
415 ));
416 }
417
418 let mut properties = smallvec::SmallVec::<[_; 16]>::with_capacity(self.properties.len());
419 let klass = glib::Class::<Element>::from_type(element_type).unwrap();
420 for (name, value) in self.properties {
421 match value {
422 ValueOrStr::Value(value) => {
423 properties.push((name, value));
424 }
425 ValueOrStr::Str(value) => {
426 use crate::value::GstValueExt;
427
428 let pspec = match klass.find_property(name) {
429 Some(pspec) => pspec,
430 None => {
431 panic!(
432 "property '{}' of element factory '{}' not found",
433 name,
434 factory.name()
435 );
436 }
437 };
438
439 let value = {
440 if pspec.value_type() == crate::Structure::static_type() && value == "NULL"
441 {
442 None::<crate::Structure>.to_value()
443 } else {
444 #[cfg(feature = "v1_20")]
445 {
446 glib::Value::deserialize_with_pspec(value, &pspec)
447 .unwrap_or_else(|_| {
448 panic!(
449 "property '{}' of element factory '{}' can't be set from string '{}'",
450 name,
451 factory.name(),
452 value,
453 )
454 })
455 }
456 #[cfg(not(feature = "v1_20"))]
457 {
458 glib::Value::deserialize(value, pspec.value_type())
459 .unwrap_or_else(|_| {
460 panic!(
461 "property '{}' of element factory '{}' can't be set from string '{}'",
462 name,
463 factory.name(),
464 value,
465 )
466 })
467 }
468 }
469 };
470
471 properties.push((name, value));
472 }
473 }
474 }
475
476 let element = unsafe {
477 glib::Object::with_mut_values(element_type, &mut properties)
478 .unsafe_cast::<crate::Element>()
479 };
480
481 unsafe {
482 use std::sync::atomic;
483
484 let klass = element.element_class();
485 let factory_ptr: &atomic::AtomicPtr<ffi::GstElementFactory> =
486 &*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory
487 as *const atomic::AtomicPtr<ffi::GstElementFactory>);
488 if factory_ptr
489 .compare_exchange(
490 std::ptr::null_mut(),
491 factory.as_ptr(),
492 atomic::Ordering::SeqCst,
493 atomic::Ordering::SeqCst,
494 )
495 .is_ok()
496 {
497 factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED);
498 }
499
500 if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _)
501 != glib::ffi::GFALSE
502 {
503 glib::g_critical!(
504 "GStreamer",
505 "The created element should be floating, this is probably caused by faulty bindings",
506 );
507 }
508 }
509
510 crate::log!(
511 crate::CAT_RUST,
512 obj = &factory,
513 "created element \"{}\"",
514 factory.name()
515 );
516
517 Ok(element)
518 }
519}