gstreamer_pbutils/
element_properties.rs

1use std::ops::{Deref, DerefMut};
2
3use gst::{prelude::*, IdStr};
4
5// rustdoc-stripper-ignore-next
6/// Wrapper around `gst::Structure` for `element-properties`
7/// property of `EncodingProfile`.
8///
9/// # Examples
10///
11/// ```rust
12/// # use gstreamer_pbutils::ElementProperties;
13/// # gst::init().unwrap();
14/// ElementProperties::builder_general()
15///     .field("threads", 16)
16///     .build();
17/// ```
18///
19/// ```rust
20/// # use gstreamer_pbutils::{ElementProperties, ElementPropertiesMapItem};
21/// # gst::init().unwrap();
22/// ElementProperties::builder_map()
23///     .item(
24///         ElementPropertiesMapItem::builder("vp8enc")
25///             .field("max-quantizer", 17)
26///             .field("buffer-size", 20000)
27///             .field("threads", 16)
28///             .build(),
29///     )
30///     .build();
31/// ```
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct ElementProperties(pub(crate) gst::Structure);
34
35impl Default for ElementProperties {
36    fn default() -> Self {
37        Self::builder_general().build()
38    }
39}
40
41impl Deref for ElementProperties {
42    type Target = gst::StructureRef;
43
44    #[inline]
45    fn deref(&self) -> &Self::Target {
46        self.0.as_ref()
47    }
48}
49
50impl From<ElementProperties> for gst::Structure {
51    #[inline]
52    fn from(e: ElementProperties) -> Self {
53        skip_assert_initialized!();
54
55        e.into_inner()
56    }
57}
58
59impl ElementProperties {
60    // rustdoc-stripper-ignore-next
61    /// Creates an `ElementProperties` builder that build into
62    /// something similar to the following:
63    ///
64    /// [element-properties, boolean-prop=true, string-prop="hi"]
65    pub fn builder_general() -> ElementPropertiesGeneralBuilder {
66        assert_initialized_main_thread!();
67
68        ElementPropertiesGeneralBuilder {
69            structure: gst::Structure::new_empty("element-properties"),
70        }
71    }
72
73    // rustdoc-stripper-ignore-next
74    /// Creates an `ElementProperties` builder that build into
75    /// something similar to the following:
76    ///
77    /// element-properties-map, map = {
78    ///     [openh264enc, gop-size=32, ],
79    ///     [x264enc, key-int-max=32, tune=zerolatency],
80    /// }
81    pub fn builder_map() -> ElementPropertiesMapBuilder {
82        assert_initialized_main_thread!();
83
84        ElementPropertiesMapBuilder { map: Vec::new() }
85    }
86
87    // rustdoc-stripper-ignore-next
88    /// Returns true if self is built with `ElementPropertiesGeneralBuilder`.
89    pub fn is_general(&self) -> bool {
90        let structure_name = self.0.name();
91
92        if structure_name != "element-properties" {
93            debug_assert_eq!(structure_name, "element-properties-map");
94            return false;
95        }
96
97        true
98    }
99
100    // rustdoc-stripper-ignore-next
101    /// Returns true if self is built with `ElementPropertiesMapBuilder`.
102    pub fn is_map(&self) -> bool {
103        !self.is_general()
104    }
105
106    // rustdoc-stripper-ignore-next
107    /// Returns the inner vec of `ElementPropertiesMapItem` if self is_map()
108    /// or `None` if self is_general().
109    pub fn map(&self) -> Option<Vec<ElementPropertiesMapItem>> {
110        if !self.is_map() {
111            return None;
112        }
113
114        Some(
115            self.0
116                .get::<gst::List>("map")
117                .unwrap()
118                .as_slice()
119                .iter()
120                .map(|props_map| {
121                    ElementPropertiesMapItem(props_map.get::<gst::Structure>().unwrap())
122                })
123                .collect::<Vec<_>>(),
124        )
125    }
126
127    #[inline]
128    pub fn into_inner(self) -> gst::Structure {
129        self.0
130    }
131}
132
133#[must_use = "The builder must be built to be used"]
134#[derive(Debug, Clone)]
135pub struct ElementPropertiesGeneralBuilder {
136    structure: gst::Structure,
137}
138
139impl ElementPropertiesGeneralBuilder {
140    // rustdoc-stripper-ignore-next
141    /// Sets property `property_name` to the given value `value`.
142    ///
143    /// Overrides any default or previously defined value for `property_name`.
144    pub fn field(
145        mut self,
146        property_name: impl glib::IntoGStr,
147        value: impl Into<glib::Value> + Send,
148    ) -> Self {
149        self.structure.set(property_name, value);
150        self
151    }
152
153    // rustdoc-stripper-ignore-next
154    /// Sets property `property_name` to the given value `value`.
155    ///
156    /// Overrides any default or previously defined value for `property_name`.
157    pub fn field_with_static(
158        mut self,
159        property_name: impl AsRef<glib::GStr> + 'static,
160        value: impl Into<glib::Value> + Send,
161    ) -> Self {
162        self.structure.set_with_static(property_name, value);
163        self
164    }
165
166    // rustdoc-stripper-ignore-next
167    /// Sets property `property_name` to the given value `value`.
168    ///
169    /// Overrides any default or previously defined value for `property_name`.
170    pub fn field_with_id(
171        mut self,
172        property_name: impl AsRef<IdStr>,
173        value: impl Into<glib::Value> + Send,
174    ) -> Self {
175        self.structure.set_with_id(property_name, value);
176        self
177    }
178
179    gst::impl_builder_gvalue_extra_setters!(field);
180
181    pub fn field_value(mut self, property_name: &str, value: glib::SendValue) -> Self {
182        self.structure.set_value(property_name, value);
183        self
184    }
185
186    pub fn field_value_with_static(
187        mut self,
188        property_name: impl AsRef<glib::GStr> + 'static,
189        value: glib::SendValue,
190    ) -> Self {
191        self.structure.set_value_with_static(property_name, value);
192        self
193    }
194
195    pub fn field_value_with_id(
196        mut self,
197        property_name: impl AsRef<IdStr>,
198        value: glib::SendValue,
199    ) -> Self {
200        self.structure.set_value_with_id(property_name, value);
201        self
202    }
203
204    pub fn field_value_if_some(self, property_name: &str, value: Option<glib::SendValue>) -> Self {
205        if let Some(value) = value {
206            self.field_value(property_name, value)
207        } else {
208            self
209        }
210    }
211
212    pub fn field_value_with_static_if_some(
213        self,
214        property_name: impl AsRef<glib::GStr> + 'static,
215        value: Option<glib::SendValue>,
216    ) -> Self {
217        if let Some(value) = value {
218            self.field_value_with_static(property_name, value)
219        } else {
220            self
221        }
222    }
223
224    pub fn field_value_with_id_if_some(
225        self,
226        property_name: impl AsRef<IdStr>,
227        value: Option<glib::SendValue>,
228    ) -> Self {
229        if let Some(value) = value {
230            self.field_value_with_id(property_name, value)
231        } else {
232            self
233        }
234    }
235
236    pub fn build(self) -> ElementProperties {
237        ElementProperties(self.structure)
238    }
239}
240
241#[must_use = "The builder must be built to be used"]
242#[derive(Debug, Clone)]
243pub struct ElementPropertiesMapBuilder {
244    map: Vec<glib::SendValue>,
245}
246
247impl ElementPropertiesMapBuilder {
248    pub fn item(mut self, item: ElementPropertiesMapItem) -> Self {
249        self.map.push(item.into_inner().to_send_value());
250        self
251    }
252
253    pub fn item_if(self, item: ElementPropertiesMapItem, predicate: bool) -> Self {
254        if predicate {
255            self.item(item)
256        } else {
257            self
258        }
259    }
260
261    pub fn item_if_some(self, item: Option<ElementPropertiesMapItem>) -> Self {
262        if let Some(item) = item {
263            self.item(item)
264        } else {
265            self
266        }
267    }
268
269    pub fn build(self) -> ElementProperties {
270        ElementProperties(
271            gst::Structure::builder("element-properties-map")
272                .field("map", gst::List::new(self.map))
273                .build(),
274        )
275    }
276}
277
278// rustdoc-stripper-ignore-next
279/// Wrapper around `gst::Structure` for `element-properties-map` map item.
280///
281/// # Examples
282///
283/// ```rust
284/// # use gstreamer_pbutils::{ElementProperties, ElementPropertiesMapItem};
285/// # gst::init().unwrap();
286/// ElementProperties::builder_map()
287///     .item(
288///         ElementPropertiesMapItem::builder("vp8enc")
289///             .field("max-quantizer", 17)
290///             .field("buffer-size", 20000)
291///             .field("threads", 16)
292///             .build(),
293///     )
294///     .build();
295/// ```
296#[derive(Debug, Clone, PartialEq, Eq)]
297pub struct ElementPropertiesMapItem(gst::Structure);
298
299impl Deref for ElementPropertiesMapItem {
300    type Target = gst::StructureRef;
301
302    #[inline]
303    fn deref(&self) -> &Self::Target {
304        self.0.as_ref()
305    }
306}
307
308impl DerefMut for ElementPropertiesMapItem {
309    #[inline]
310    fn deref_mut(&mut self) -> &mut Self::Target {
311        self.0.deref_mut()
312    }
313}
314
315impl From<ElementPropertiesMapItem> for gst::Structure {
316    #[inline]
317    fn from(e: ElementPropertiesMapItem) -> Self {
318        skip_assert_initialized!();
319
320        e.into_inner()
321    }
322}
323
324impl ElementPropertiesMapItem {
325    pub fn builder(factory_name: &str) -> ElementPropertiesMapItemBuilder {
326        assert_initialized_main_thread!();
327
328        ElementPropertiesMapItemBuilder {
329            structure: gst::Structure::new_empty(factory_name),
330        }
331    }
332
333    #[inline]
334    pub fn into_inner(self) -> gst::Structure {
335        self.0
336    }
337}
338
339#[must_use = "The builder must be built to be used"]
340#[derive(Debug, Clone)]
341pub struct ElementPropertiesMapItemBuilder {
342    structure: gst::Structure,
343}
344
345impl ElementPropertiesMapItemBuilder {
346    // rustdoc-stripper-ignore-next
347    /// Sets property `property_name` to the given value `value`.
348    ///
349    /// Overrides any default or previously defined value for `property_name`.
350    pub fn field(
351        mut self,
352        property_name: impl glib::IntoGStr,
353        value: impl Into<glib::Value> + Send,
354    ) -> Self {
355        self.structure.set(property_name, value);
356        self
357    }
358
359    // rustdoc-stripper-ignore-next
360    /// Sets property `property_name` to the given value `value`.
361    ///
362    /// Overrides any default or previously defined value for `property_name`.
363    pub fn field_with_static(
364        mut self,
365        property_name: impl AsRef<glib::GStr> + 'static,
366        value: impl Into<glib::Value> + Send,
367    ) -> Self {
368        self.structure.set_with_static(property_name, value);
369        self
370    }
371
372    // rustdoc-stripper-ignore-next
373    /// Sets property `property_name` to the given value `value`.
374    ///
375    /// Overrides any default or previously defined value for `property_name`.
376    pub fn field_with_id(
377        mut self,
378        property_name: impl AsRef<IdStr>,
379        value: impl Into<glib::Value> + Send,
380    ) -> Self {
381        self.structure.set_with_id(property_name, value);
382        self
383    }
384
385    gst::impl_builder_gvalue_extra_setters!(field);
386
387    pub fn field_value(mut self, property_name: &str, value: glib::SendValue) -> Self {
388        self.structure.set_value(property_name, value);
389        self
390    }
391
392    pub fn field_value_with_static(
393        mut self,
394        property_name: impl AsRef<glib::GStr> + 'static,
395        value: glib::SendValue,
396    ) -> Self {
397        self.structure.set_value_with_static(property_name, value);
398        self
399    }
400
401    pub fn field_value_with_id(
402        mut self,
403        property_name: impl AsRef<IdStr>,
404        value: glib::SendValue,
405    ) -> Self {
406        self.structure.set_value_with_id(property_name, value);
407        self
408    }
409
410    pub fn field_value_if_some(self, property_name: &str, value: Option<glib::SendValue>) -> Self {
411        if let Some(value) = value {
412            self.field_value(property_name, value)
413        } else {
414            self
415        }
416    }
417
418    pub fn field_value_with_static_if_some(
419        self,
420        property_name: impl AsRef<glib::GStr> + 'static,
421        value: Option<glib::SendValue>,
422    ) -> Self {
423        if let Some(value) = value {
424            self.field_value_with_static(property_name, value)
425        } else {
426            self
427        }
428    }
429
430    pub fn field_value_with_id_if_some(
431        self,
432        property_name: impl AsRef<IdStr>,
433        value: Option<glib::SendValue>,
434    ) -> Self {
435        if let Some(value) = value {
436            self.field_value_with_id(property_name, value)
437        } else {
438            self
439        }
440    }
441
442    pub fn build(self) -> ElementPropertiesMapItem {
443        ElementPropertiesMapItem(self.structure)
444    }
445}
446
447#[cfg(test)]
448mod test {
449    use super::*;
450    use gst::idstr;
451
452    #[test]
453    fn element_properties_getters() {
454        gst::init().unwrap();
455
456        let elem_props_general = ElementProperties::builder_general()
457            .field("string-prop", "hi")
458            .field("boolean-prop", true)
459            .build();
460        assert!(elem_props_general.is_general());
461        assert!(!elem_props_general.is_map());
462        assert_eq!(elem_props_general.map(), None);
463
464        let elem_factory_props_map = ElementPropertiesMapItem::builder("vp8enc")
465            .field_with_id(idstr!("cq-level"), 13)
466            .field("resize-allowed", false)
467            .build();
468        let elem_props_map = ElementProperties::builder_map()
469            .item(elem_factory_props_map.clone())
470            .build();
471        assert!(elem_props_map.is_map());
472        assert!(!elem_props_map.is_general());
473        assert_eq!(elem_props_map.map(), Some(vec![elem_factory_props_map]));
474    }
475
476    #[test]
477    fn element_properties_general_builder() {
478        gst::init().unwrap();
479
480        let elem_props = ElementProperties::builder_general()
481            .field("string-prop", "hi")
482            .field("boolean-prop", true)
483            .build();
484        assert_eq!(elem_props.n_fields(), 2);
485        assert_eq!(elem_props.name(), "element-properties");
486        assert_eq!(elem_props.get::<String>("string-prop").unwrap(), "hi");
487        assert!(elem_props.get::<bool>("boolean-prop").unwrap());
488    }
489
490    #[test]
491    fn element_properties_map_builder() {
492        gst::init().unwrap();
493
494        let props_map = ElementPropertiesMapItem::builder("vp8enc")
495            .field("cq-level", 13)
496            .field("resize-allowed", false)
497            .build();
498        assert_eq!(props_map.n_fields(), 2);
499        assert_eq!(props_map.name(), "vp8enc");
500        assert_eq!(props_map.get::<i32>("cq-level").unwrap(), 13);
501        assert!(!props_map.get::<bool>("resize-allowed").unwrap());
502
503        let elem_props = ElementProperties::builder_map()
504            .item(props_map.clone())
505            .build();
506        assert_eq!(elem_props.n_fields(), 1);
507
508        let list = elem_props.map().unwrap();
509        assert_eq!(list.len(), 1);
510        assert_eq!(list.first().unwrap(), &props_map);
511    }
512}