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")]
37 #[track_caller]
38 pub fn create_with_name(&self, name: Option<&str>) -> Result<Element, glib::BoolError> {
39 let mut builder = self.create();
40 if let Some(name) = name {
41 builder = builder.name(name);
42 }
43 builder.build()
44 }
45
46 #[doc(alias = "gst_element_factory_make")]
47 #[track_caller]
48 pub fn make_with_name(
49 factoryname: &str,
50 name: Option<&str>,
51 ) -> Result<Element, glib::BoolError> {
52 skip_assert_initialized!();
53 let mut builder = Self::make(factoryname);
54 if let Some(name) = name {
55 builder = builder.name(name);
56 }
57 builder.build()
58 }
59
60 #[doc(alias = "gst_element_factory_get_static_pad_templates")]
61 #[doc(alias = "get_static_pad_templates")]
62 pub fn static_pad_templates(&self) -> glib::List<StaticPadTemplate> {
63 unsafe {
64 glib::List::from_glib_none(ffi::gst_element_factory_get_static_pad_templates(
65 self.to_glib_none().0,
66 ))
67 }
68 }
69
70 #[doc(alias = "gst_element_factory_list_is_type")]
71 pub fn has_type(&self, type_: crate::ElementFactoryType) -> bool {
72 unsafe {
73 from_glib(ffi::gst_element_factory_list_is_type(
74 self.to_glib_none().0,
75 type_.into_glib(),
76 ))
77 }
78 }
79
80 #[doc(alias = "gst_element_factory_list_get_elements")]
81 pub fn factories_with_type(
82 type_: crate::ElementFactoryType,
83 minrank: Rank,
84 ) -> glib::List<ElementFactory> {
85 assert_initialized_main_thread!();
86 unsafe {
87 FromGlibPtrContainer::from_glib_full(ffi::gst_element_factory_list_get_elements(
88 type_.into_glib(),
89 minrank.into_glib(),
90 ))
91 }
92 }
93
94 #[doc(alias = "gst_element_factory_get_metadata")]
95 #[doc(alias = "get_metadata")]
96 pub fn metadata(&self, key: &str) -> Option<&str> {
97 unsafe {
98 let ptr =
99 ffi::gst_element_factory_get_metadata(self.to_glib_none().0, key.to_glib_none().0);
100
101 if ptr.is_null() {
102 None
103 } else {
104 Some(CStr::from_ptr(ptr).to_str().unwrap())
105 }
106 }
107 }
108
109 #[doc(alias = "get_longname")]
110 #[doc(alias = "gst_element_factory_get_longname")]
111 pub fn longname(&self) -> &str {
112 self.metadata(ELEMENT_METADATA_LONGNAME).unwrap()
113 }
114
115 #[doc(alias = "get_klass")]
116 #[doc(alias = "gst_element_factory_get_klass")]
117 pub fn klass(&self) -> &str {
118 self.metadata(ELEMENT_METADATA_KLASS).unwrap()
119 }
120
121 #[doc(alias = "get_description")]
122 #[doc(alias = "gst_element_factory_get_description")]
123 pub fn description(&self) -> &str {
124 self.metadata(ELEMENT_METADATA_DESCRIPTION).unwrap()
125 }
126
127 #[doc(alias = "get_author")]
128 #[doc(alias = "gst_element_factory_get_author")]
129 pub fn author(&self) -> &str {
130 self.metadata(ELEMENT_METADATA_AUTHOR).unwrap()
131 }
132
133 #[doc(alias = "get_documentation_uri")]
134 #[doc(alias = "gst_element_factory_get_documentation_uri")]
135 pub fn documentation_uri(&self) -> Option<&str> {
136 self.metadata(ELEMENT_METADATA_DOC_URI)
137 }
138
139 #[doc(alias = "get_icon_name")]
140 #[doc(alias = "gst_element_factory_get_icon_name")]
141 pub fn icon_name(&self) -> Option<&str> {
142 self.metadata(ELEMENT_METADATA_ICON_NAME)
143 }
144
145 #[doc(alias = "gst_element_factory_can_sink_all_caps")]
146 pub fn can_sink_all_caps(&self, caps: &CapsRef) -> bool {
147 unsafe {
148 from_glib(ffi::gst_element_factory_can_sink_all_caps(
149 self.to_glib_none().0,
150 caps.as_ptr(),
151 ))
152 }
153 }
154
155 #[doc(alias = "gst_element_factory_can_sink_any_caps")]
156 pub fn can_sink_any_caps(&self, caps: &CapsRef) -> bool {
157 unsafe {
158 from_glib(ffi::gst_element_factory_can_sink_any_caps(
159 self.to_glib_none().0,
160 caps.as_ptr(),
161 ))
162 }
163 }
164
165 #[doc(alias = "gst_element_factory_can_src_all_caps")]
166 pub fn can_src_all_caps(&self, caps: &CapsRef) -> bool {
167 unsafe {
168 from_glib(ffi::gst_element_factory_can_src_all_caps(
169 self.to_glib_none().0,
170 caps.as_ptr(),
171 ))
172 }
173 }
174
175 #[doc(alias = "gst_element_factory_can_src_any_caps")]
176 pub fn can_src_any_caps(&self, caps: &CapsRef) -> bool {
177 unsafe {
178 from_glib(ffi::gst_element_factory_can_src_any_caps(
179 self.to_glib_none().0,
180 caps.as_ptr(),
181 ))
182 }
183 }
184}
185
186#[must_use = "The builder must be built to be used"]
189pub struct ElementBuilder<'a> {
190 name_or_factory: NameOrFactory<'a>,
191 builder: crate::gobject::GObjectBuilder<'a, Element>,
192}
193
194#[derive(Copy, Clone)]
195enum NameOrFactory<'a> {
196 Name(&'a str),
197 Factory(&'a ElementFactory),
198}
199
200impl<'a> ElementBuilder<'a> {
201 #[inline]
206 pub fn property(self, name: &'a str, value: impl Into<glib::Value> + 'a) -> Self {
207 Self {
208 builder: self.builder.property(name, value),
209 ..self
210 }
211 }
212
213 #[inline]
216 pub fn property_from_str(self, name: &'a str, value: &'a str) -> Self {
217 Self {
218 builder: self.builder.property_from_str(name, value),
219 ..self
220 }
221 }
222
223 impl_builder_gvalue_extra_setters!(property_and_name);
224
225 #[track_caller]
237 #[must_use = "Building the element without using it has no effect"]
238 pub fn build(self) -> Result<Element, glib::BoolError> {
239 let mut _factory_found = None;
240 let factory = match self.name_or_factory {
241 NameOrFactory::Name(name) => {
242 let factory = ElementFactory::find(name).ok_or_else(|| {
243 crate::warning!(crate::CAT_RUST, "element factory '{}' not found", name);
244 glib::bool_error!(
245 "Failed to find element factory with name '{}' for creating element",
246 name
247 )
248 })?;
249 _factory_found = Some(factory);
250 _factory_found.as_ref().unwrap()
251 }
252 NameOrFactory::Factory(factory) => factory,
253 };
254
255 use crate::prelude::{
259 ElementExtManual, GstObjectExt, GstObjectExtManual, PluginFeatureExtManual,
260 };
261
262 let factory = factory.load().map_err(|_| {
263 crate::warning!(
264 crate::CAT_RUST,
265 obj = factory,
266 "loading element factory '{}' failed",
267 factory.name(),
268 );
269 glib::bool_error!(
270 "Failed to load element factory '{}' for creating element",
271 factory.name()
272 )
273 })?;
274
275 let element_type = factory.element_type();
276 if !element_type.is_valid() {
277 crate::warning!(
278 crate::CAT_RUST,
279 obj = &factory,
280 "element factory '{}' has no type",
281 factory.name()
282 );
283 return Err(glib::bool_error!(
284 "Failed to create element from factory '{}'",
285 factory.name()
286 ));
287 }
288
289 let element = self
290 .builder
291 .type_(element_type)
292 .build()
293 .map_err(|err| {
294 use crate::gobject::GObjectError::*;
295 match err {
296 PropertyNotFound { property, .. } => {
297 format!("property '{property}' of element factory '{}' not found", factory.name())
298 },
299 PropertyFromStr { property, value, .. } => {
300 format!("property '{property}' of element factory '{}' can't be set from string '{value}'", factory.name())
301 },
302 }
303 }).unwrap();
304
305 unsafe {
306 use std::sync::atomic;
307
308 let klass = element.element_class();
309 let factory_ptr: &atomic::AtomicPtr<ffi::GstElementFactory> =
310 &*(&klass.as_ref().elementfactory as *const *mut ffi::GstElementFactory
311 as *const atomic::AtomicPtr<ffi::GstElementFactory>);
312 if factory_ptr
313 .compare_exchange(
314 std::ptr::null_mut(),
315 factory.as_ptr(),
316 atomic::Ordering::SeqCst,
317 atomic::Ordering::SeqCst,
318 )
319 .is_ok()
320 {
321 factory.set_object_flags(crate::ObjectFlags::MAY_BE_LEAKED);
322 }
323
324 if glib::gobject_ffi::g_object_is_floating(factory.as_ptr() as *mut _)
325 != glib::ffi::GFALSE
326 {
327 glib::g_critical!(
328 "GStreamer",
329 "The created element should be floating, this is probably caused by faulty bindings",
330 );
331 }
332 }
333
334 crate::log!(
335 crate::CAT_RUST,
336 obj = &factory,
337 "created element \"{}\"",
338 factory.name()
339 );
340
341 Ok(element)
342 }
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348 use crate::prelude::*;
349
350 #[test]
351 fn builder() {
352 crate::init().unwrap();
353
354 let fakesink = ElementFactory::make("fakesink")
355 .name("test-fakesink")
356 .property("can-activate-pull", true)
357 .property_from_str("state-error", "ready-to-paused")
358 .build()
359 .unwrap();
360
361 assert_eq!(fakesink.name(), "test-fakesink");
362 assert!(fakesink.property::<bool>("can-activate-pull"));
363 let v = fakesink.property_value("state-error");
364 let (_klass, e) = glib::EnumValue::from_value(&v).unwrap();
365 assert_eq!(e.nick(), "ready-to-paused");
366 }
367}