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")]
39 #[track_caller]
40 pub fn create_with_name(&self, name: Option<&str>) -> Result<Element, glib::BoolError> {
41 let mut builder = self.create();
42 if let Some(name) = name {
43 builder = builder.name(name);
44 }
45 builder.build()
46 }
47
48 #[doc(alias = "gst_element_factory_make")]
49 #[track_caller]
50 pub fn make_with_name(
51 factoryname: &str,
52 name: Option<&str>,
53 ) -> Result<Element, glib::BoolError> {
54 skip_assert_initialized!();
55 let mut builder = Self::make(factoryname);
56 if let Some(name) = name {
57 builder = builder.name(name);
58 }
59 builder.build()
60 }
61
62 #[doc(alias = "gst_element_factory_get_static_pad_templates")]
63 #[doc(alias = "get_static_pad_templates")]
64 pub fn static_pad_templates(&self) -> glib::List<StaticPadTemplate> {
65 unsafe {
66 glib::List::from_glib_none(ffi::gst_element_factory_get_static_pad_templates(
67 self.to_glib_none().0,
68 ))
69 }
70 }
71
72 #[doc(alias = "gst_element_factory_list_is_type")]
73 pub fn has_type(&self, type_: crate::ElementFactoryType) -> bool {
74 unsafe {
75 from_glib(ffi::gst_element_factory_list_is_type(
76 self.to_glib_none().0,
77 type_.into_glib(),
78 ))
79 }
80 }
81
82 #[doc(alias = "gst_element_factory_list_get_elements")]
83 pub fn factories_with_type(
84 type_: crate::ElementFactoryType,
85 minrank: Rank,
86 ) -> glib::List<ElementFactory> {
87 assert_initialized_main_thread!();
88 unsafe {
89 FromGlibPtrContainer::from_glib_full(ffi::gst_element_factory_list_get_elements(
90 type_.into_glib(),
91 minrank.into_glib(),
92 ))
93 }
94 }
95
96 #[doc(alias = "gst_element_factory_get_metadata")]
97 #[doc(alias = "get_metadata")]
98 pub fn metadata(&self, key: &str) -> Option<&str> {
99 unsafe {
100 let ptr =
101 ffi::gst_element_factory_get_metadata(self.to_glib_none().0, key.to_glib_none().0);
102
103 if ptr.is_null() {
104 None
105 } else {
106 Some(CStr::from_ptr(ptr).to_str().unwrap())
107 }
108 }
109 }
110
111 #[doc(alias = "get_longname")]
112 #[doc(alias = "gst_element_factory_get_longname")]
113 pub fn longname(&self) -> &str {
114 self.metadata(ELEMENT_METADATA_LONGNAME).unwrap()
115 }
116
117 #[doc(alias = "get_klass")]
118 #[doc(alias = "gst_element_factory_get_klass")]
119 pub fn klass(&self) -> &str {
120 self.metadata(ELEMENT_METADATA_KLASS).unwrap()
121 }
122
123 #[doc(alias = "get_description")]
124 #[doc(alias = "gst_element_factory_get_description")]
125 pub fn description(&self) -> &str {
126 self.metadata(ELEMENT_METADATA_DESCRIPTION).unwrap()
127 }
128
129 #[doc(alias = "get_author")]
130 #[doc(alias = "gst_element_factory_get_author")]
131 pub fn author(&self) -> &str {
132 self.metadata(ELEMENT_METADATA_AUTHOR).unwrap()
133 }
134
135 #[doc(alias = "get_documentation_uri")]
136 #[doc(alias = "gst_element_factory_get_documentation_uri")]
137 pub fn documentation_uri(&self) -> Option<&str> {
138 self.metadata(ELEMENT_METADATA_DOC_URI)
139 }
140
141 #[doc(alias = "get_icon_name")]
142 #[doc(alias = "gst_element_factory_get_icon_name")]
143 pub fn icon_name(&self) -> Option<&str> {
144 self.metadata(ELEMENT_METADATA_ICON_NAME)
145 }
146
147 #[doc(alias = "gst_element_factory_can_sink_all_caps")]
148 pub fn can_sink_all_caps(&self, caps: &CapsRef) -> bool {
149 unsafe {
150 from_glib(ffi::gst_element_factory_can_sink_all_caps(
151 self.to_glib_none().0,
152 caps.as_ptr(),
153 ))
154 }
155 }
156
157 #[doc(alias = "gst_element_factory_can_sink_any_caps")]
158 pub fn can_sink_any_caps(&self, caps: &CapsRef) -> bool {
159 unsafe {
160 from_glib(ffi::gst_element_factory_can_sink_any_caps(
161 self.to_glib_none().0,
162 caps.as_ptr(),
163 ))
164 }
165 }
166
167 #[doc(alias = "gst_element_factory_can_src_all_caps")]
168 pub fn can_src_all_caps(&self, caps: &CapsRef) -> bool {
169 unsafe {
170 from_glib(ffi::gst_element_factory_can_src_all_caps(
171 self.to_glib_none().0,
172 caps.as_ptr(),
173 ))
174 }
175 }
176
177 #[doc(alias = "gst_element_factory_can_src_any_caps")]
178 pub fn can_src_any_caps(&self, caps: &CapsRef) -> bool {
179 unsafe {
180 from_glib(ffi::gst_element_factory_can_src_any_caps(
181 self.to_glib_none().0,
182 caps.as_ptr(),
183 ))
184 }
185 }
186}
187
188#[must_use = "The builder must be built to be used"]
191pub struct ElementBuilder<'a> {
192 name_or_factory: NameOrFactory<'a>,
193 properties: smallvec::SmallVec<[(&'a str, ValueOrStr<'a>); 16]>,
194}
195
196#[derive(Copy, Clone)]
197enum NameOrFactory<'a> {
198 Name(&'a str),
199 Factory(&'a ElementFactory),
200}
201
202enum ValueOrStr<'a> {
203 Value(glib::Value),
204 Str(&'a str),
205}
206
207impl<'a> ElementBuilder<'a> {
208 #[inline]
211 pub fn name(self, name: impl Into<glib::GString>) -> Self {
212 self.property("name", name.into())
213 }
214
215 #[inline]
218 pub fn name_if_some(self, name: Option<impl Into<glib::GString>>) -> Self {
219 if let Some(name) = name {
220 self.name(name)
221 } else {
222 self
223 }
224 }
225
226 #[inline]
231 pub fn property(self, name: &'a str, value: impl Into<glib::Value> + 'a) -> Self {
232 Self {
233 name_or_factory: self.name_or_factory,
234 properties: {
235 let mut properties = self.properties;
236 properties.push((name, ValueOrStr::Value(value.into())));
237 properties
238 },
239 }
240 }
241
242 impl_builder_gvalue_extra_setters!(property);
243
244 #[inline]
247 pub fn property_from_str(self, name: &'a str, value: &'a str) -> Self {
248 Self {
249 name_or_factory: self.name_or_factory,
250 properties: {
251 let mut properties = self.properties;
252 properties.push((name, ValueOrStr::Str(value)));
253 properties
254 },
255 }
256 }
257
258 #[inline]
261 pub fn property_from_str_if_some(self, name: &'a str, value: Option<&'a str>) -> Self {
262 if let Some(value) = value {
263 self.property_from_str(name, value)
264 } else {
265 self
266 }
267 }
268
269 #[track_caller]
279 #[must_use = "Building the element without using it has no effect"]
280 pub fn build(self) -> Result<Element, glib::BoolError> {
281 let mut _factory_found = None;
282 let factory = match self.name_or_factory {
283 NameOrFactory::Name(name) => {
284 let factory = ElementFactory::find(name).ok_or_else(|| {
285 crate::warning!(crate::CAT_RUST, "element factory '{}' not found", name);
286 glib::bool_error!(
287 "Failed to find element factory with name '{}' for creating element",
288 name
289 )
290 })?;
291 _factory_found = Some(factory);
292 _factory_found.as_ref().unwrap()
293 }
294 NameOrFactory::Factory(factory) => factory,
295 };
296
297 use crate::prelude::{
301 ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual,
302 };
303
304 let factory = factory.load().map_err(|_| {
305 crate::warning!(
306 crate::CAT_RUST,
307 obj = factory,
308 "loading element factory '{}' failed",
309 factory.name(),
310 );
311 glib::bool_error!(
312 "Failed to load element factory '{}' for creating element",
313 factory.name()
314 )
315 })?;
316
317 let element_type = factory.element_type();
318 if !element_type.is_valid() {
319 crate::warning!(
320 crate::CAT_RUST,
321 obj = &factory,
322 "element factory '{}' has no type",
323 factory.name()
324 );
325 return Err(glib::bool_error!(
326 "Failed to create element from factory '{}'",
327 factory.name()
328 ));
329 }
330
331 let mut properties = smallvec::SmallVec::<[_; 16]>::with_capacity(self.properties.len());
332 let klass = glib::Class::<Element>::from_type(element_type).unwrap();
333 for (name, value) in self.properties {
334 match value {
335 ValueOrStr::Value(value) => {
336 properties.push((name, value));
337 }
338 ValueOrStr::Str(value) => {
339 use crate::value::GstValueExt;
340
341 let pspec = match klass.find_property(name) {
342 Some(pspec) => pspec,
343 None => {
344 panic!(
345 "property '{}' of element factory '{}' not found",
346 name,
347 factory.name()
348 );
349 }
350 };
351
352 let value = {
353 if pspec.value_type() == crate::Structure::static_type() && value == "NULL"
354 {
355 None::<crate::Structure>.to_value()
356 } else {
357 #[cfg(feature = "v1_20")]
358 {
359 glib::Value::deserialize_with_pspec(value, &pspec)
360 .unwrap_or_else(|_| {
361 panic!(
362 "property '{}' of element factory '{}' can't be set from string '{}'",
363 name,
364 factory.name(),
365 value,
366 )
367 })
368 }
369 #[cfg(not(feature = "v1_20"))]
370 {
371 glib::Value::deserialize(value, pspec.value_type())
372 .unwrap_or_else(|_| {
373 panic!(
374 "property '{}' of element factory '{}' can't be set from string '{}'",
375 name,
376 factory.name(),
377 value,
378 )
379 })
380 }
381 }
382 };
383
384 properties.push((name, value));
385 }
386 }
387 }
388
389 let element = unsafe {
390 glib::Object::with_mut_values(element_type, &mut properties)
391 .unsafe_cast::<crate::Element>()
392 };
393
394 unsafe {
395 use std::sync::atomic;
396
397 let klass = element.element_class();
398 let factory_ptr: &atomic::AtomicPtr<ffi::GstElementFactory> =
399 &*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory
400 as *const atomic::AtomicPtr<ffi::GstElementFactory>);
401 if factory_ptr
402 .compare_exchange(
403 std::ptr::null_mut(),
404 factory.as_ptr(),
405 atomic::Ordering::SeqCst,
406 atomic::Ordering::SeqCst,
407 )
408 .is_ok()
409 {
410 factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED);
411 }
412
413 if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _)
414 != glib::ffi::GFALSE
415 {
416 glib::g_critical!(
417 "GStreamer",
418 "The created element should be floating, this is probably caused by faulty bindings",
419 );
420 }
421 }
422
423 crate::log!(
424 crate::CAT_RUST,
425 obj = &factory,
426 "created element \"{}\"",
427 factory.name()
428 );
429
430 Ok(element)
431 }
432}