gstreamer_pbutils/
element_properties.rs

1use std::ops::{Deref, DerefMut};
2
3use gst::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    gst::impl_builder_gvalue_extra_setters!(field);
154
155    pub fn field_value(mut self, property_name: &str, value: glib::SendValue) -> Self {
156        self.structure.set_value(property_name, value);
157        self
158    }
159
160    pub fn field_value_if_some(self, property_name: &str, value: Option<glib::SendValue>) -> Self {
161        if let Some(value) = value {
162            self.field_value(property_name, value)
163        } else {
164            self
165        }
166    }
167
168    pub fn build(self) -> ElementProperties {
169        ElementProperties(self.structure)
170    }
171}
172
173#[must_use = "The builder must be built to be used"]
174#[derive(Debug, Clone)]
175pub struct ElementPropertiesMapBuilder {
176    map: Vec<glib::SendValue>,
177}
178
179impl ElementPropertiesMapBuilder {
180    pub fn item(mut self, item: ElementPropertiesMapItem) -> Self {
181        self.map.push(item.into_inner().to_send_value());
182        self
183    }
184
185    pub fn item_if(self, item: ElementPropertiesMapItem, predicate: bool) -> Self {
186        if predicate {
187            self.item(item)
188        } else {
189            self
190        }
191    }
192
193    pub fn item_if_some(self, item: Option<ElementPropertiesMapItem>) -> Self {
194        if let Some(item) = item {
195            self.item(item)
196        } else {
197            self
198        }
199    }
200
201    pub fn build(self) -> ElementProperties {
202        ElementProperties(
203            gst::Structure::builder("element-properties-map")
204                .field("map", gst::List::new(self.map))
205                .build(),
206        )
207    }
208}
209
210// rustdoc-stripper-ignore-next
211/// Wrapper around `gst::Structure` for `element-properties-map` map item.
212///
213/// # Examples
214///
215/// ```rust
216/// # use gstreamer_pbutils::{ElementProperties, ElementPropertiesMapItem};
217/// # gst::init().unwrap();
218/// ElementProperties::builder_map()
219///     .item(
220///         ElementPropertiesMapItem::builder("vp8enc")
221///             .field("max-quantizer", 17)
222///             .field("buffer-size", 20000)
223///             .field("threads", 16)
224///             .build(),
225///     )
226///     .build();
227/// ```
228#[derive(Debug, Clone, PartialEq, Eq)]
229pub struct ElementPropertiesMapItem(gst::Structure);
230
231impl Deref for ElementPropertiesMapItem {
232    type Target = gst::StructureRef;
233
234    #[inline]
235    fn deref(&self) -> &Self::Target {
236        self.0.as_ref()
237    }
238}
239
240impl DerefMut for ElementPropertiesMapItem {
241    #[inline]
242    fn deref_mut(&mut self) -> &mut Self::Target {
243        self.0.deref_mut()
244    }
245}
246
247impl From<ElementPropertiesMapItem> for gst::Structure {
248    #[inline]
249    fn from(e: ElementPropertiesMapItem) -> Self {
250        skip_assert_initialized!();
251
252        e.into_inner()
253    }
254}
255
256impl ElementPropertiesMapItem {
257    pub fn builder(factory_name: &str) -> ElementPropertiesMapItemBuilder {
258        assert_initialized_main_thread!();
259
260        ElementPropertiesMapItemBuilder {
261            structure: gst::Structure::new_empty(factory_name),
262        }
263    }
264
265    #[inline]
266    pub fn into_inner(self) -> gst::Structure {
267        self.0
268    }
269}
270
271#[must_use = "The builder must be built to be used"]
272#[derive(Debug, Clone)]
273pub struct ElementPropertiesMapItemBuilder {
274    structure: gst::Structure,
275}
276
277impl ElementPropertiesMapItemBuilder {
278    // rustdoc-stripper-ignore-next
279    /// Sets property `property_name` to the given value `value`.
280    ///
281    /// Overrides any default or previously defined value for `property_name`.
282    pub fn field(
283        mut self,
284        property_name: impl glib::IntoGStr,
285        value: impl Into<glib::Value> + Send,
286    ) -> Self {
287        self.structure.set(property_name, value);
288        self
289    }
290
291    gst::impl_builder_gvalue_extra_setters!(field);
292
293    pub fn field_value(mut self, property_name: &str, value: glib::SendValue) -> Self {
294        self.structure.set_value(property_name, value);
295        self
296    }
297
298    pub fn field_value_if_some(self, property_name: &str, value: Option<glib::SendValue>) -> Self {
299        if let Some(value) = value {
300            self.field_value(property_name, value)
301        } else {
302            self
303        }
304    }
305
306    pub fn build(self) -> ElementPropertiesMapItem {
307        ElementPropertiesMapItem(self.structure)
308    }
309}
310
311#[cfg(test)]
312mod test {
313    use super::*;
314
315    #[test]
316    fn element_properties_getters() {
317        gst::init().unwrap();
318
319        let elem_props_general = ElementProperties::builder_general()
320            .field("string-prop", "hi")
321            .field("boolean-prop", true)
322            .build();
323        assert!(elem_props_general.is_general());
324        assert!(!elem_props_general.is_map());
325        assert_eq!(elem_props_general.map(), None);
326
327        let elem_factory_props_map = ElementPropertiesMapItem::builder("vp8enc")
328            .field("cq-level", 13)
329            .field("resize-allowed", false)
330            .build();
331        let elem_props_map = ElementProperties::builder_map()
332            .item(elem_factory_props_map.clone())
333            .build();
334        assert!(elem_props_map.is_map());
335        assert!(!elem_props_map.is_general());
336        assert_eq!(elem_props_map.map(), Some(vec![elem_factory_props_map]));
337    }
338
339    #[test]
340    fn element_properties_general_builder() {
341        gst::init().unwrap();
342
343        let elem_props = ElementProperties::builder_general()
344            .field("string-prop", "hi")
345            .field("boolean-prop", true)
346            .build();
347        assert_eq!(elem_props.n_fields(), 2);
348        assert_eq!(elem_props.name(), "element-properties");
349        assert_eq!(elem_props.get::<String>("string-prop").unwrap(), "hi");
350        assert!(elem_props.get::<bool>("boolean-prop").unwrap());
351    }
352
353    #[test]
354    fn element_properties_map_builder() {
355        gst::init().unwrap();
356
357        let props_map = ElementPropertiesMapItem::builder("vp8enc")
358            .field("cq-level", 13)
359            .field("resize-allowed", false)
360            .build();
361        assert_eq!(props_map.n_fields(), 2);
362        assert_eq!(props_map.name(), "vp8enc");
363        assert_eq!(props_map.get::<i32>("cq-level").unwrap(), 13);
364        assert!(!props_map.get::<bool>("resize-allowed").unwrap());
365
366        let elem_props = ElementProperties::builder_map()
367            .item(props_map.clone())
368            .build();
369        assert_eq!(elem_props.n_fields(), 1);
370
371        let list = elem_props.map().unwrap();
372        assert_eq!(list.len(), 1);
373        assert_eq!(list.first().unwrap(), &props_map);
374    }
375}