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