Skip to main content

gstreamer_pbutils/
element_properties.rs

1use std::ops::{Deref, DerefMut};
2
3use gst::{IdStr, prelude::*};
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 { self.item(item) } else { self }
255    }
256
257    pub fn item_if_some(self, item: Option<ElementPropertiesMapItem>) -> Self {
258        if let Some(item) = item {
259            self.item(item)
260        } else {
261            self
262        }
263    }
264
265    pub fn build(self) -> ElementProperties {
266        ElementProperties(
267            gst::Structure::builder("element-properties-map")
268                .field("map", gst::List::new(self.map))
269                .build(),
270        )
271    }
272}
273
274// rustdoc-stripper-ignore-next
275/// Wrapper around `gst::Structure` for `element-properties-map` map item.
276///
277/// # Examples
278///
279/// ```rust
280/// # use gstreamer_pbutils::{ElementProperties, ElementPropertiesMapItem};
281/// # gst::init().unwrap();
282/// ElementProperties::builder_map()
283///     .item(
284///         ElementPropertiesMapItem::builder("vp8enc")
285///             .field("max-quantizer", 17)
286///             .field("buffer-size", 20000)
287///             .field("threads", 16)
288///             .build(),
289///     )
290///     .build();
291/// ```
292#[derive(Debug, Clone, PartialEq, Eq)]
293pub struct ElementPropertiesMapItem(gst::Structure);
294
295impl Deref for ElementPropertiesMapItem {
296    type Target = gst::StructureRef;
297
298    #[inline]
299    fn deref(&self) -> &Self::Target {
300        self.0.as_ref()
301    }
302}
303
304impl DerefMut for ElementPropertiesMapItem {
305    #[inline]
306    fn deref_mut(&mut self) -> &mut Self::Target {
307        self.0.deref_mut()
308    }
309}
310
311impl From<ElementPropertiesMapItem> for gst::Structure {
312    #[inline]
313    fn from(e: ElementPropertiesMapItem) -> Self {
314        skip_assert_initialized!();
315
316        e.into_inner()
317    }
318}
319
320impl ElementPropertiesMapItem {
321    pub fn builder(factory_name: &str) -> ElementPropertiesMapItemBuilder {
322        assert_initialized_main_thread!();
323
324        ElementPropertiesMapItemBuilder {
325            structure: gst::Structure::new_empty(factory_name),
326        }
327    }
328
329    #[inline]
330    pub fn into_inner(self) -> gst::Structure {
331        self.0
332    }
333}
334
335#[must_use = "The builder must be built to be used"]
336#[derive(Debug, Clone)]
337pub struct ElementPropertiesMapItemBuilder {
338    structure: gst::Structure,
339}
340
341impl ElementPropertiesMapItemBuilder {
342    // rustdoc-stripper-ignore-next
343    /// Sets property `property_name` to the given value `value`.
344    ///
345    /// Overrides any default or previously defined value for `property_name`.
346    pub fn field(
347        mut self,
348        property_name: impl glib::IntoGStr,
349        value: impl Into<glib::Value> + Send,
350    ) -> Self {
351        self.structure.set(property_name, value);
352        self
353    }
354
355    // rustdoc-stripper-ignore-next
356    /// Sets property `property_name` to the given value `value`.
357    ///
358    /// Overrides any default or previously defined value for `property_name`.
359    pub fn field_with_static(
360        mut self,
361        property_name: impl AsRef<glib::GStr> + 'static,
362        value: impl Into<glib::Value> + Send,
363    ) -> Self {
364        self.structure.set_with_static(property_name, value);
365        self
366    }
367
368    // rustdoc-stripper-ignore-next
369    /// Sets property `property_name` to the given value `value`.
370    ///
371    /// Overrides any default or previously defined value for `property_name`.
372    pub fn field_with_id(
373        mut self,
374        property_name: impl AsRef<IdStr>,
375        value: impl Into<glib::Value> + Send,
376    ) -> Self {
377        self.structure.set_with_id(property_name, value);
378        self
379    }
380
381    gst::impl_builder_gvalue_extra_setters!(field);
382
383    pub fn field_value(mut self, property_name: &str, value: glib::SendValue) -> Self {
384        self.structure.set_value(property_name, value);
385        self
386    }
387
388    pub fn field_value_with_static(
389        mut self,
390        property_name: impl AsRef<glib::GStr> + 'static,
391        value: glib::SendValue,
392    ) -> Self {
393        self.structure.set_value_with_static(property_name, value);
394        self
395    }
396
397    pub fn field_value_with_id(
398        mut self,
399        property_name: impl AsRef<IdStr>,
400        value: glib::SendValue,
401    ) -> Self {
402        self.structure.set_value_with_id(property_name, value);
403        self
404    }
405
406    pub fn field_value_if_some(self, property_name: &str, value: Option<glib::SendValue>) -> Self {
407        if let Some(value) = value {
408            self.field_value(property_name, value)
409        } else {
410            self
411        }
412    }
413
414    pub fn field_value_with_static_if_some(
415        self,
416        property_name: impl AsRef<glib::GStr> + 'static,
417        value: Option<glib::SendValue>,
418    ) -> Self {
419        if let Some(value) = value {
420            self.field_value_with_static(property_name, value)
421        } else {
422            self
423        }
424    }
425
426    pub fn field_value_with_id_if_some(
427        self,
428        property_name: impl AsRef<IdStr>,
429        value: Option<glib::SendValue>,
430    ) -> Self {
431        if let Some(value) = value {
432            self.field_value_with_id(property_name, value)
433        } else {
434            self
435        }
436    }
437
438    pub fn build(self) -> ElementPropertiesMapItem {
439        ElementPropertiesMapItem(self.structure)
440    }
441}
442
443#[cfg(test)]
444mod test {
445    use super::*;
446    use gst::idstr;
447
448    #[test]
449    fn element_properties_getters() {
450        gst::init().unwrap();
451
452        let elem_props_general = ElementProperties::builder_general()
453            .field("string-prop", "hi")
454            .field("boolean-prop", true)
455            .build();
456        assert!(elem_props_general.is_general());
457        assert!(!elem_props_general.is_map());
458        assert_eq!(elem_props_general.map(), None);
459
460        let elem_factory_props_map = ElementPropertiesMapItem::builder("vp8enc")
461            .field_with_id(idstr!("cq-level"), 13)
462            .field("resize-allowed", false)
463            .build();
464        let elem_props_map = ElementProperties::builder_map()
465            .item(elem_factory_props_map.clone())
466            .build();
467        assert!(elem_props_map.is_map());
468        assert!(!elem_props_map.is_general());
469        assert_eq!(elem_props_map.map(), Some(vec![elem_factory_props_map]));
470    }
471
472    #[test]
473    fn element_properties_general_builder() {
474        gst::init().unwrap();
475
476        let elem_props = ElementProperties::builder_general()
477            .field("string-prop", "hi")
478            .field("boolean-prop", true)
479            .build();
480        assert_eq!(elem_props.n_fields(), 2);
481        assert_eq!(elem_props.name(), "element-properties");
482        assert_eq!(elem_props.get::<String>("string-prop").unwrap(), "hi");
483        assert!(elem_props.get::<bool>("boolean-prop").unwrap());
484    }
485
486    #[test]
487    fn element_properties_map_builder() {
488        gst::init().unwrap();
489
490        let props_map = ElementPropertiesMapItem::builder("vp8enc")
491            .field("cq-level", 13)
492            .field("resize-allowed", false)
493            .build();
494        assert_eq!(props_map.n_fields(), 2);
495        assert_eq!(props_map.name(), "vp8enc");
496        assert_eq!(props_map.get::<i32>("cq-level").unwrap(), 13);
497        assert!(!props_map.get::<bool>("resize-allowed").unwrap());
498
499        let elem_props = ElementProperties::builder_map()
500            .item(props_map.clone())
501            .build();
502        assert_eq!(elem_props.n_fields(), 1);
503
504        let list = elem_props.map().unwrap();
505        assert_eq!(list.len(), 1);
506        assert_eq!(list.first().unwrap(), &props_map);
507    }
508}