1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4 cmp, fmt,
5 ops::{ControlFlow, RangeBounds},
6 ptr,
7};
8
9use glib::translate::*;
10
11use crate::{ffi, Buffer, BufferRef};
12
13mini_object_wrapper!(BufferList, BufferListRef, ffi::GstBufferList, || {
14 ffi::gst_buffer_list_get_type()
15});
16
17impl 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
31impl 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
214impl Default for BufferList {
215 fn default() -> Self {
216 Self::new()
217 }
218}
219
220impl fmt::Debug for BufferList {
221 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222 BufferListRef::fmt(self, f)
223 }
224}
225
226impl 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
246macro_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
339define_iter!(Iter, &'a BufferRef, |list: &'a BufferListRef, idx| {
340 list.get(idx)
341});
342
343define_iter!(IterOwned, Buffer, |list: &BufferListRef, idx| {
344 list.get_owned(idx)
345});
346
347impl<'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
356impl 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
369impl<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
382impl 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
399impl 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)]
406mod 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