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