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