gstreamer/
bufferlist.rs

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(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(ffi::gst_buffer_list_new_sized(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 = self.iter().map(|b| b.size()).sum::<usize>();
231        let (pts, dts) = self
232            .get(0)
233            .map(|b| (b.pts(), b.dts()))
234            .unwrap_or((ClockTime::NONE, ClockTime::NONE));
235
236        f.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("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::new_sized(1);
361        {
362            let list = list.get_mut().unwrap();
363            list.add(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::new_sized(N);
374        {
375            let list = list.get_mut().unwrap();
376            value.into_iter().for_each(|b| list.add(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 = iter.into_iter();
387
388        let mut list = BufferList::new_sized(iter.size_hint().0);
389
390        {
391            let list = list.get_mut().unwrap();
392            iter.for_each(|b| list.add(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| self.add(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}