gstreamer/
bin.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, mem::transmute, path};
4
5use glib::{
6    prelude::*,
7    signal::{connect_raw, SignalHandlerId},
8    translate::*,
9    GString,
10};
11
12use crate::{ffi, prelude::*, Bin, BinFlags, Element, LoggableError};
13
14impl Bin {
15    // rustdoc-stripper-ignore-next
16    /// Creates a new [`Bin`] object with a default name.
17    ///
18    /// Use [`Bin::with_name()`] to create a [`Bin`] with a specific name.
19    /// Use [`Bin::builder()`] for additional configuration.
20    #[doc(alias = "gst_bin_new")]
21    pub fn new() -> Bin {
22        assert_initialized_main_thread!();
23        unsafe { Element::from_glib_none(ffi::gst_bin_new(std::ptr::null())).unsafe_cast() }
24    }
25
26    // rustdoc-stripper-ignore-next
27    /// Creates a new [`Bin`] object with the specified name.
28    ///
29    /// Use [`Bin::builder()`] for additional configuration.
30    #[doc(alias = "gst_bin_new")]
31    pub fn with_name(name: &str) -> Bin {
32        assert_initialized_main_thread!();
33        unsafe { Element::from_glib_none(ffi::gst_bin_new(name.to_glib_none().0)).unsafe_cast() }
34    }
35
36    // rustdoc-stripper-ignore-next
37    /// Creates a new builder-pattern struct instance to construct [`Bin`] objects.
38    ///
39    /// This method returns an instance of [`BinBuilder`] which can be used to create [`Bin`] objects.
40    pub fn builder<'a>() -> BinBuilder<'a> {
41        assert_initialized_main_thread!();
42        BinBuilder {
43            builder: crate::Object::builder(),
44        }
45    }
46}
47
48pub trait GstBinExtManual: IsA<Bin> + 'static {
49    #[doc(alias = "gst_bin_add_many")]
50    fn add_many<E: AsRef<Element>>(
51        &self,
52        elements: impl IntoIterator<Item = E>,
53    ) -> Result<(), glib::BoolError> {
54        for e in elements {
55            unsafe {
56                glib::result_from_gboolean!(
57                    ffi::gst_bin_add(self.as_ref().to_glib_none().0, e.as_ref().to_glib_none().0),
58                    "Failed to add elements"
59                )?;
60            }
61        }
62
63        Ok(())
64    }
65
66    #[doc(alias = "gst_bin_remove_many")]
67    fn remove_many<E: AsRef<Element>>(
68        &self,
69        elements: impl IntoIterator<Item = E>,
70    ) -> Result<(), glib::BoolError> {
71        for e in elements {
72            unsafe {
73                glib::result_from_gboolean!(
74                    ffi::gst_bin_remove(
75                        self.as_ref().to_glib_none().0,
76                        e.as_ref().to_glib_none().0,
77                    ),
78                    "Failed to remove elements"
79                )?;
80            }
81        }
82
83        Ok(())
84    }
85
86    #[doc(alias = "do-latency")]
87    fn connect_do_latency<F: Fn(&Self) -> Result<(), LoggableError> + Send + Sync + 'static>(
88        &self,
89        f: F,
90    ) -> SignalHandlerId {
91        unsafe {
92            let f: Box_<F> = Box_::new(f);
93            connect_raw(
94                self.as_ptr() as *mut _,
95                b"do-latency\0".as_ptr() as *const _,
96                Some(transmute::<*const (), unsafe extern "C" fn()>(
97                    do_latency_trampoline::<Self, F> as *const (),
98                )),
99                Box_::into_raw(f),
100            )
101        }
102    }
103
104    #[cfg(feature = "v1_18")]
105    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
106    #[doc(alias = "gst_bin_iterate_all_by_element_factory_name")]
107    fn iterate_all_by_element_factory_name(&self, factory_name: &str) -> crate::Iterator<Element> {
108        unsafe {
109            from_glib_full(ffi::gst_bin_iterate_all_by_element_factory_name(
110                self.as_ref().to_glib_none().0,
111                factory_name.to_glib_none().0,
112            ))
113        }
114    }
115    #[doc(alias = "gst_bin_iterate_all_by_interface")]
116    fn iterate_all_by_interface(&self, iface: glib::types::Type) -> crate::Iterator<Element> {
117        unsafe {
118            from_glib_full(ffi::gst_bin_iterate_all_by_interface(
119                self.as_ref().to_glib_none().0,
120                iface.into_glib(),
121            ))
122        }
123    }
124
125    #[doc(alias = "gst_bin_iterate_elements")]
126    fn iterate_elements(&self) -> crate::Iterator<Element> {
127        unsafe {
128            from_glib_full(ffi::gst_bin_iterate_elements(
129                self.as_ref().to_glib_none().0,
130            ))
131        }
132    }
133
134    #[doc(alias = "gst_bin_iterate_recurse")]
135    fn iterate_recurse(&self) -> crate::Iterator<Element> {
136        unsafe { from_glib_full(ffi::gst_bin_iterate_recurse(self.as_ref().to_glib_none().0)) }
137    }
138
139    #[doc(alias = "gst_bin_iterate_sinks")]
140    fn iterate_sinks(&self) -> crate::Iterator<Element> {
141        unsafe { from_glib_full(ffi::gst_bin_iterate_sinks(self.as_ref().to_glib_none().0)) }
142    }
143
144    #[doc(alias = "gst_bin_iterate_sorted")]
145    fn iterate_sorted(&self) -> crate::Iterator<Element> {
146        unsafe { from_glib_full(ffi::gst_bin_iterate_sorted(self.as_ref().to_glib_none().0)) }
147    }
148
149    #[doc(alias = "gst_bin_iterate_sources")]
150    fn iterate_sources(&self) -> crate::Iterator<Element> {
151        unsafe { from_glib_full(ffi::gst_bin_iterate_sources(self.as_ref().to_glib_none().0)) }
152    }
153
154    #[doc(alias = "get_children")]
155    fn children(&self) -> Vec<Element> {
156        unsafe {
157            let bin: &ffi::GstBin = &*(self.as_ptr() as *const _);
158            let _guard = self.as_ref().object_lock();
159            FromGlibPtrContainer::from_glib_none(bin.children)
160        }
161    }
162
163    #[doc(alias = "gst_debug_bin_to_dot_data")]
164    fn debug_to_dot_data(&self, details: crate::DebugGraphDetails) -> GString {
165        crate::auto::functions::debug_bin_to_dot_data(self, details)
166    }
167
168    #[doc(alias = "GST_DEBUG_BIN_TO_DOT_FILE")]
169    #[doc(alias = "gst_debug_bin_to_dot_file")]
170    fn debug_to_dot_file(
171        &self,
172        details: crate::DebugGraphDetails,
173        file_name: impl AsRef<path::Path>,
174    ) {
175        crate::auto::functions::debug_bin_to_dot_file(self, details, file_name)
176    }
177
178    #[doc(alias = "GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS")]
179    #[doc(alias = "gst_debug_bin_to_dot_file_with_ts")]
180    fn debug_to_dot_file_with_ts(
181        &self,
182        details: crate::DebugGraphDetails,
183        file_name: impl AsRef<path::Path>,
184    ) {
185        crate::auto::functions::debug_bin_to_dot_file_with_ts(self, details, file_name)
186    }
187
188    fn set_bin_flags(&self, flags: BinFlags) {
189        unsafe {
190            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
191            let _guard = self.as_ref().object_lock();
192            (*ptr).flags |= flags.into_glib();
193        }
194    }
195
196    fn unset_bin_flags(&self, flags: BinFlags) {
197        unsafe {
198            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
199            let _guard = self.as_ref().object_lock();
200            (*ptr).flags &= !flags.into_glib();
201        }
202    }
203
204    #[doc(alias = "get_bin_flags")]
205    fn bin_flags(&self) -> BinFlags {
206        unsafe {
207            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
208            let _guard = self.as_ref().object_lock();
209            from_glib((*ptr).flags)
210        }
211    }
212}
213
214impl<O: IsA<Bin>> GstBinExtManual for O {}
215
216impl Default for Bin {
217    fn default() -> Self {
218        glib::object::Object::new()
219    }
220}
221
222// rustdoc-stripper-ignore-next
223/// A [builder-pattern] type to construct [`Bin`] objects.
224///
225/// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
226#[must_use = "The builder must be built to be used"]
227pub struct BinBuilder<'a> {
228    builder: crate::gobject::GObjectBuilder<'a, Bin>,
229}
230
231impl<'a> BinBuilder<'a> {
232    // rustdoc-stripper-ignore-next
233    /// Build the [`Bin`].
234    ///
235    /// # Panics
236    ///
237    /// This panics if the [`Bin`] doesn't have all the given properties or
238    /// property values of the wrong type are provided.
239    #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
240    pub fn build(self) -> Bin {
241        self.builder.build().unwrap()
242    }
243
244    pub fn async_handling(self, async_handling: bool) -> Self {
245        Self {
246            builder: self.builder.property("async-handling", async_handling),
247        }
248    }
249
250    pub fn async_handling_if_some(self, async_handling: Option<bool>) -> Self {
251        if let Some(async_handling) = async_handling {
252            self.async_handling(async_handling)
253        } else {
254            self
255        }
256    }
257
258    pub fn message_forward(self, message_forward: bool) -> Self {
259        Self {
260            builder: self.builder.property("message-forward", message_forward),
261        }
262    }
263
264    pub fn message_forward_if_some(self, message_forward: Option<bool>) -> Self {
265        if let Some(message_forward) = message_forward {
266            self.message_forward(message_forward)
267        } else {
268            self
269        }
270    }
271
272    // rustdoc-stripper-ignore-next
273    /// Sets property `name` to the given value `value`.
274    ///
275    /// Overrides any default or previously defined value for `name`.
276    #[inline]
277    pub fn property(self, name: &'a str, value: impl Into<glib::Value> + 'a) -> Self {
278        Self {
279            builder: self.builder.property(name, value),
280        }
281    }
282
283    // rustdoc-stripper-ignore-next
284    /// Sets property `name` to the given string value `value`.
285    #[inline]
286    pub fn property_from_str(self, name: &'a str, value: &'a str) -> Self {
287        Self {
288            builder: self.builder.property_from_str(name, value),
289        }
290    }
291
292    impl_builder_gvalue_extra_setters!(property_and_name);
293}
294
295unsafe extern "C" fn do_latency_trampoline<
296    P,
297    F: Fn(&P) -> Result<(), LoggableError> + Send + Sync + 'static,
298>(
299    this: *mut ffi::GstBin,
300    f: glib::ffi::gpointer,
301) -> glib::ffi::gboolean
302where
303    P: IsA<Bin>,
304{
305    let f: &F = &*(f as *const F);
306    match f(Bin::from_glib_borrow(this).unsafe_cast_ref()) {
307        Ok(()) => true,
308        Err(err) => {
309            err.log_with_object(&*Bin::from_glib_borrow(this));
310            false
311        }
312    }
313    .into_glib()
314}
315
316#[cfg(test)]
317mod tests {
318    use super::*;
319
320    #[test]
321    fn test_get_children() {
322        crate::init().unwrap();
323
324        let bin = crate::Bin::new();
325        bin.add(
326            &crate::ElementFactory::make("identity")
327                .name("identity0")
328                .build()
329                .unwrap(),
330        )
331        .unwrap();
332        bin.add(
333            &crate::ElementFactory::make("identity")
334                .name("identity1")
335                .build()
336                .unwrap(),
337        )
338        .unwrap();
339
340        let mut child_names = bin
341            .children()
342            .iter()
343            .map(|c| c.name())
344            .collect::<Vec<GString>>();
345        child_names.sort();
346        assert_eq!(
347            child_names,
348            vec![String::from("identity0"), String::from("identity1")]
349        );
350    }
351
352    #[test]
353    fn builder() {
354        crate::init().unwrap();
355
356        let msg_fwd = "message-forward";
357        let bin = Bin::builder()
358            .name("test-bin")
359            .property("async-handling", true)
360            .property_from_str(msg_fwd, "True")
361            .build();
362
363        assert_eq!(bin.name(), "test-bin");
364        assert!(bin.property::<bool>("async-handling"));
365        assert!(bin.property::<bool>("message-forward"));
366    }
367}