1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{fmt, ops::ControlFlow, ptr}; |
4 | |
5 | use glib::translate::*; |
6 | |
7 | use crate::{Buffer, BufferRef}; |
8 | |
9 | mini_object_wrapper!(BufferList, BufferListRef, ffi::GstBufferList, || { |
10 | ffi::gst_buffer_list_get_type() |
11 | }); |
12 | |
13 | impl BufferList { |
14 | #[doc (alias = "gst_buffer_list_new" )] |
15 | pub fn new() -> Self { |
16 | assert_initialized_main_thread!(); |
17 | unsafe { from_glib_full(ptr:ffi::gst_buffer_list_new()) } |
18 | } |
19 | |
20 | #[doc (alias = "gst_buffer_list_new_sized" )] |
21 | pub fn new_sized(size: usize) -> Self { |
22 | assert_initialized_main_thread!(); |
23 | unsafe { from_glib_full(ptr:ffi::gst_buffer_list_new_sized(size as u32)) } |
24 | } |
25 | } |
26 | |
27 | impl BufferListRef { |
28 | #[doc (alias = "gst_buffer_list_insert" )] |
29 | pub fn insert(&mut self, idx: i32, buffer: Buffer) { |
30 | unsafe { |
31 | ffi::gst_buffer_list_insert(self.as_mut_ptr(), idx, buffer.into_glib_ptr()); |
32 | } |
33 | } |
34 | |
35 | #[doc (alias = "gst_buffer_list_add" )] |
36 | pub fn add(&mut self, buffer: Buffer) { |
37 | self.insert(-1, buffer); |
38 | } |
39 | |
40 | #[doc (alias = "gst_buffer_list_copy_deep" )] |
41 | pub fn copy_deep(&self) -> BufferList { |
42 | unsafe { from_glib_full(ffi::gst_buffer_list_copy_deep(self.as_ptr())) } |
43 | } |
44 | |
45 | #[doc (alias = "gst_buffer_list_remove" )] |
46 | pub fn remove(&mut self, idx: u32, len: u32) { |
47 | unsafe { ffi::gst_buffer_list_remove(self.as_mut_ptr(), idx, len) } |
48 | } |
49 | |
50 | #[doc (alias = "gst_buffer_list_get" )] |
51 | pub fn get(&self, idx: u32) -> Option<&BufferRef> { |
52 | unsafe { |
53 | let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx); |
54 | if ptr.is_null() { |
55 | None |
56 | } else { |
57 | Some(BufferRef::from_ptr(ptr)) |
58 | } |
59 | } |
60 | } |
61 | |
62 | #[doc (alias = "gst_buffer_list_get" )] |
63 | pub fn get_owned(&self, idx: u32) -> Option<Buffer> { |
64 | unsafe { |
65 | let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx); |
66 | from_glib_none(ptr) |
67 | } |
68 | } |
69 | |
70 | #[doc (alias = "gst_buffer_list_get_writable" )] |
71 | #[doc (alias = "get_writable" )] |
72 | pub fn get_mut(&mut self, idx: u32) -> Option<&mut BufferRef> { |
73 | unsafe { |
74 | let ptr = ffi::gst_buffer_list_get_writable(self.as_mut_ptr(), idx); |
75 | if ptr.is_null() { |
76 | None |
77 | } else { |
78 | Some(BufferRef::from_mut_ptr(ptr)) |
79 | } |
80 | } |
81 | } |
82 | |
83 | #[doc (alias = "gst_buffer_list_length" )] |
84 | pub fn len(&self) -> usize { |
85 | unsafe { ffi::gst_buffer_list_length(self.as_mut_ptr()) as usize } |
86 | } |
87 | |
88 | #[doc (alias = "gst_buffer_list_calculate_size" )] |
89 | pub fn calculate_size(&self) -> usize { |
90 | unsafe { ffi::gst_buffer_list_calculate_size(self.as_mut_ptr()) } |
91 | } |
92 | |
93 | pub fn is_empty(&self) -> bool { |
94 | self.len() == 0 |
95 | } |
96 | |
97 | pub fn iter(&self) -> Iter { |
98 | Iter::new(self) |
99 | } |
100 | |
101 | pub fn iter_owned(&self) -> IterOwned { |
102 | IterOwned::new(self) |
103 | } |
104 | |
105 | #[doc (alias = "gst_buffer_list_foreach" )] |
106 | pub fn foreach<F: FnMut(&Buffer, u32) -> ControlFlow<(), ()>>(&self, func: F) -> bool { |
107 | unsafe extern "C" fn trampoline<F: FnMut(&Buffer, u32) -> ControlFlow<(), ()>>( |
108 | buffer: *mut *mut ffi::GstBuffer, |
109 | idx: u32, |
110 | user_data: glib::ffi::gpointer, |
111 | ) -> glib::ffi::gboolean { |
112 | let func = user_data as *const _ as usize as *mut F; |
113 | let res = (*func)(&Buffer::from_glib_borrow(*buffer), idx); |
114 | |
115 | matches!(res, ControlFlow::Continue(_)).into_glib() |
116 | } |
117 | |
118 | unsafe { |
119 | let func_ptr: &F = &func; |
120 | |
121 | from_glib(ffi::gst_buffer_list_foreach( |
122 | self.as_ptr() as *mut _, |
123 | Some(trampoline::<F>), |
124 | func_ptr as *const _ as usize as *mut _, |
125 | )) |
126 | } |
127 | } |
128 | |
129 | #[doc (alias = "gst_buffer_list_foreach" )] |
130 | pub fn foreach_mut<F: FnMut(Buffer, u32) -> ControlFlow<Option<Buffer>, Option<Buffer>>>( |
131 | &mut self, |
132 | func: F, |
133 | ) -> bool { |
134 | unsafe extern "C" fn trampoline< |
135 | F: FnMut(Buffer, u32) -> ControlFlow<Option<Buffer>, Option<Buffer>>, |
136 | >( |
137 | buffer: *mut *mut ffi::GstBuffer, |
138 | idx: u32, |
139 | user_data: glib::ffi::gpointer, |
140 | ) -> glib::ffi::gboolean { |
141 | let func = user_data as *const _ as usize as *mut F; |
142 | let res = (*func)( |
143 | Buffer::from_glib_full(ptr::replace( |
144 | buffer as *mut *const ffi::GstBuffer, |
145 | ptr::null_mut::<ffi::GstBuffer>(), |
146 | )), |
147 | idx, |
148 | ); |
149 | |
150 | let (cont, res_buffer) = match res { |
151 | ControlFlow::Continue(res_buffer) => (true, res_buffer), |
152 | ControlFlow::Break(res_buffer) => (false, res_buffer), |
153 | }; |
154 | |
155 | match res_buffer { |
156 | None => { |
157 | *buffer = ptr::null_mut(); |
158 | } |
159 | Some(new_buffer) => { |
160 | *buffer = new_buffer.into_glib_ptr(); |
161 | } |
162 | } |
163 | |
164 | cont.into_glib() |
165 | } |
166 | |
167 | unsafe { |
168 | let func_ptr: &F = &func; |
169 | |
170 | from_glib(ffi::gst_buffer_list_foreach( |
171 | self.as_ptr() as *mut _, |
172 | Some(trampoline::<F>), |
173 | func_ptr as *const _ as usize as *mut _, |
174 | )) |
175 | } |
176 | } |
177 | } |
178 | |
179 | impl Default for BufferList { |
180 | fn default() -> Self { |
181 | Self::new() |
182 | } |
183 | } |
184 | |
185 | impl fmt::Debug for BufferList { |
186 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
187 | BufferListRef::fmt(self, f) |
188 | } |
189 | } |
190 | |
191 | impl fmt::Debug for BufferListRef { |
192 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
193 | use crate::{utils::Displayable, ClockTime}; |
194 | |
195 | let size: usize = self.iter().map(|b: &BufferRef| b.size()).sum::<usize>(); |
196 | let (pts: Option, dts: Option) = self |
197 | .get(0) |
198 | .map(|b| (b.pts(), b.dts())) |
199 | .unwrap_or((ClockTime::NONE, ClockTime::NONE)); |
200 | |
201 | f&mut DebugStruct<'_, '_>.debug_struct("BufferList" ) |
202 | .field("ptr" , &self.as_ptr()) |
203 | .field("buffers" , &self.len()) |
204 | .field("pts" , &pts.display()) |
205 | .field("dts" , &dts.display()) |
206 | .field(name:"size" , &size) |
207 | .finish() |
208 | } |
209 | } |
210 | |
211 | macro_rules! define_iter( |
212 | ($name:ident, $styp:ty, $get_item:expr) => { |
213 | #[derive(Debug)] |
214 | pub struct $name<'a> { |
215 | list: &'a BufferListRef, |
216 | idx: usize, |
217 | size: usize, |
218 | } |
219 | |
220 | impl<'a> $name<'a> { |
221 | fn new(list: &'a BufferListRef) -> $name<'a> { |
222 | skip_assert_initialized!(); |
223 | $name { |
224 | list, |
225 | idx: 0, |
226 | size: list.len() as usize, |
227 | } |
228 | } |
229 | } |
230 | |
231 | #[allow(clippy::redundant_closure_call)] |
232 | impl<'a> Iterator for $name<'a> { |
233 | type Item = $styp; |
234 | |
235 | fn next(&mut self) -> Option<Self::Item> { |
236 | if self.idx >= self.size { |
237 | return None; |
238 | } |
239 | |
240 | let item = $get_item(self.list, self.idx as u32).unwrap(); |
241 | self.idx += 1; |
242 | |
243 | Some(item) |
244 | } |
245 | |
246 | fn size_hint(&self) -> (usize, Option<usize>) { |
247 | let remaining = self.size - self.idx; |
248 | |
249 | (remaining, Some(remaining)) |
250 | } |
251 | |
252 | fn count(self) -> usize { |
253 | self.size - self.idx |
254 | } |
255 | |
256 | fn nth(&mut self, n: usize) -> Option<Self::Item> { |
257 | let (end, overflow) = self.idx.overflowing_add(n); |
258 | if end >= self.size || overflow { |
259 | self.idx = self.size; |
260 | None |
261 | } else { |
262 | self.idx = end + 1; |
263 | Some($get_item(self.list, end as u32).unwrap()) |
264 | } |
265 | } |
266 | |
267 | fn last(self) -> Option<Self::Item> { |
268 | if self.idx == self.size { |
269 | None |
270 | } else { |
271 | Some($get_item(self.list, self.size as u32 - 1).unwrap()) |
272 | } |
273 | } |
274 | } |
275 | |
276 | #[allow(clippy::redundant_closure_call)] |
277 | impl<'a> DoubleEndedIterator for $name<'a> { |
278 | fn next_back(&mut self) -> Option<Self::Item> { |
279 | if self.idx == self.size { |
280 | return None; |
281 | } |
282 | |
283 | self.size -= 1; |
284 | Some($get_item(self.list, self.size as u32).unwrap()) |
285 | } |
286 | |
287 | fn nth_back(&mut self, n: usize) -> Option<Self::Item> { |
288 | let (end, overflow) = self.size.overflowing_sub(n); |
289 | if end <= self.idx || overflow { |
290 | self.idx = self.size; |
291 | None |
292 | } else { |
293 | self.size = end - 1; |
294 | Some($get_item(self.list, self.size as u32).unwrap()) |
295 | } |
296 | } |
297 | } |
298 | |
299 | impl<'a> ExactSizeIterator for $name<'a> {} |
300 | impl<'a> std::iter::FusedIterator for $name<'a> {} |
301 | } |
302 | ); |
303 | |
304 | define_iter!(Iter, &'a BufferRef, |list: &'a BufferListRef, idx| { |
305 | list.get(idx) |
306 | }); |
307 | |
308 | define_iter!(IterOwned, Buffer, |list: &BufferListRef, idx| { |
309 | list.get_owned(idx) |
310 | }); |
311 | |
312 | impl<'a> IntoIterator for &'a BufferListRef { |
313 | type IntoIter = Iter<'a>; |
314 | type Item = &'a BufferRef; |
315 | |
316 | fn into_iter(self) -> Self::IntoIter { |
317 | self.iter() |
318 | } |
319 | } |
320 | |
321 | impl From<Buffer> for BufferList { |
322 | fn from(value: Buffer) -> Self { |
323 | skip_assert_initialized!(); |
324 | |
325 | let mut list: BufferList = BufferList::new_sized(size:1); |
326 | { |
327 | let list: &mut BufferListRef = list.get_mut().unwrap(); |
328 | list.add(buffer:value); |
329 | } |
330 | list |
331 | } |
332 | } |
333 | |
334 | impl<const N: usize> From<[Buffer; N]> for BufferList { |
335 | fn from(value: [Buffer; N]) -> Self { |
336 | skip_assert_initialized!(); |
337 | |
338 | let mut list: BufferList = BufferList::new_sized(N); |
339 | { |
340 | let list: &mut BufferListRef = list.get_mut().unwrap(); |
341 | value.into_iter().for_each(|b: Buffer| list.add(buffer:b)); |
342 | } |
343 | list |
344 | } |
345 | } |
346 | |
347 | impl std::iter::FromIterator<Buffer> for BufferList { |
348 | fn from_iter<T: IntoIterator<Item = Buffer>>(iter: T) -> Self { |
349 | assert_initialized_main_thread!(); |
350 | |
351 | let iter: ::IntoIter = iter.into_iter(); |
352 | |
353 | let mut list: BufferList = BufferList::new_sized(size:iter.size_hint().0); |
354 | |
355 | { |
356 | let list: &mut BufferListRef = list.get_mut().unwrap(); |
357 | iter.for_each(|b: Buffer| list.add(buffer:b)); |
358 | } |
359 | |
360 | list |
361 | } |
362 | } |
363 | |
364 | impl std::iter::Extend<Buffer> for BufferListRef { |
365 | fn extend<T: IntoIterator<Item = Buffer>>(&mut self, iter: T) { |
366 | iter.into_iter().for_each(|b: Buffer| self.add(buffer:b)); |
367 | } |
368 | } |
369 | |
370 | #[cfg (test)] |
371 | mod tests { |
372 | use super::*; |
373 | use crate::ClockTime; |
374 | |
375 | #[test ] |
376 | fn test_foreach() { |
377 | crate::init().unwrap(); |
378 | |
379 | let mut buffer_list = BufferList::new(); |
380 | { |
381 | let buffer_list = buffer_list.get_mut().unwrap(); |
382 | let mut buffer = Buffer::new(); |
383 | buffer.get_mut().unwrap().set_pts(ClockTime::ZERO); |
384 | buffer_list.add(buffer); |
385 | |
386 | let mut buffer = Buffer::new(); |
387 | buffer.get_mut().unwrap().set_pts(ClockTime::SECOND); |
388 | buffer_list.add(buffer); |
389 | } |
390 | |
391 | let mut res = vec![]; |
392 | buffer_list.foreach(|buffer, idx| { |
393 | res.push((buffer.pts(), idx)); |
394 | ControlFlow::Continue(()) |
395 | }); |
396 | |
397 | assert_eq!( |
398 | res, |
399 | &[(Some(ClockTime::ZERO), 0), (Some(ClockTime::SECOND), 1)] |
400 | ); |
401 | } |
402 | |
403 | #[test ] |
404 | fn test_foreach_mut() { |
405 | crate::init().unwrap(); |
406 | |
407 | let mut buffer_list = BufferList::new(); |
408 | { |
409 | let buffer_list = buffer_list.get_mut().unwrap(); |
410 | let mut buffer = Buffer::new(); |
411 | buffer.get_mut().unwrap().set_pts(ClockTime::ZERO); |
412 | buffer_list.add(buffer); |
413 | |
414 | let mut buffer = Buffer::new(); |
415 | buffer.get_mut().unwrap().set_pts(ClockTime::SECOND); |
416 | buffer_list.add(buffer); |
417 | |
418 | let mut buffer = Buffer::new(); |
419 | buffer.get_mut().unwrap().set_pts(2 * ClockTime::SECOND); |
420 | buffer_list.add(buffer); |
421 | } |
422 | |
423 | let mut res = vec![]; |
424 | buffer_list.get_mut().unwrap().foreach_mut(|buffer, idx| { |
425 | res.push((buffer.pts(), idx)); |
426 | |
427 | if let Some(ClockTime::ZERO) = buffer.pts() { |
428 | ControlFlow::Continue(Some(buffer)) |
429 | } else if let Some(ClockTime::SECOND) = buffer.pts() { |
430 | ControlFlow::Continue(None) |
431 | } else { |
432 | let mut new_buffer = Buffer::new(); |
433 | new_buffer.get_mut().unwrap().set_pts(3 * ClockTime::SECOND); |
434 | ControlFlow::Continue(Some(new_buffer)) |
435 | } |
436 | }); |
437 | |
438 | assert_eq!( |
439 | res, |
440 | &[ |
441 | (Some(ClockTime::ZERO), 0), |
442 | (Some(ClockTime::SECOND), 1), |
443 | (Some(2 * ClockTime::SECOND), 1) |
444 | ] |
445 | ); |
446 | |
447 | let mut res = vec![]; |
448 | buffer_list.foreach(|buffer, idx| { |
449 | res.push((buffer.pts(), idx)); |
450 | ControlFlow::Continue(()) |
451 | }); |
452 | |
453 | assert_eq!( |
454 | res, |
455 | &[(Some(ClockTime::ZERO), 0), (Some(3 * ClockTime::SECOND), 1)] |
456 | ); |
457 | } |
458 | } |
459 | |