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