1use 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 #[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 #[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 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#[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 #[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 #[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 #[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}