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    /// Creates a new, empty [`BufferList`][crate::BufferList].
19    ///
20    /// # Returns
21    ///
22    /// the new [`BufferList`][crate::BufferList].
23    #[doc(alias = "gst_buffer_list_new")]
24    pub fn new() -> Self {
25        assert_initialized_main_thread!();
26        unsafe { from_glib_full(ffi::gst_buffer_list_new()) }
27    }
28
29    /// Creates a new, empty [`BufferList`][crate::BufferList]. The list will have `size` space
30    /// preallocated so that memory reallocations can be avoided.
31    /// ## `size`
32    /// an initial reserved size
33    ///
34    /// # Returns
35    ///
36    /// the new [`BufferList`][crate::BufferList].
37    #[doc(alias = "gst_buffer_list_new_sized")]
38    pub fn new_sized(size: usize) -> Self {
39        assert_initialized_main_thread!();
40        unsafe { from_glib_full(ffi::gst_buffer_list_new_sized(u32::try_from(size).unwrap())) }
41    }
42}
43
44impl BufferListRef {
45    #[doc(alias = "gst_buffer_list_insert")]
46    pub fn insert(&mut self, idx: impl Into<Option<usize>>, buffer: Buffer) {
47        unsafe {
48            let len = self.len();
49            debug_assert!(len <= u32::MAX as usize);
50
51            let idx = idx.into();
52            let idx = cmp::min(idx.unwrap_or(len), len) as i32;
53            ffi::gst_buffer_list_insert(self.as_mut_ptr(), idx, buffer.into_glib_ptr());
54        }
55    }
56
57    #[doc(alias = "gst_buffer_list_add")]
58    pub fn add(&mut self, buffer: Buffer) {
59        self.insert(None, buffer);
60    }
61
62    #[doc(alias = "gst_buffer_list_copy_deep")]
63    pub fn copy_deep(&self) -> BufferList {
64        unsafe { from_glib_full(ffi::gst_buffer_list_copy_deep(self.as_ptr())) }
65    }
66
67    fn buffer_range_to_start_end_idx(&self, range: impl RangeBounds<usize>) -> (usize, usize) {
68        let n = self.len();
69        debug_assert!(n <= u32::MAX as usize);
70
71        let start_idx = match range.start_bound() {
72            std::ops::Bound::Included(idx) => *idx,
73            std::ops::Bound::Excluded(idx) => idx.checked_add(1).unwrap(),
74            std::ops::Bound::Unbounded => 0,
75        };
76        assert!(start_idx < n);
77
78        let end_idx = match range.end_bound() {
79            std::ops::Bound::Included(idx) => idx.checked_add(1).unwrap(),
80            std::ops::Bound::Excluded(idx) => *idx,
81            std::ops::Bound::Unbounded => n,
82        };
83        assert!(end_idx <= n);
84
85        (start_idx, end_idx)
86    }
87
88    #[doc(alias = "gst_buffer_list_remove")]
89    pub fn remove(&mut self, range: impl RangeBounds<usize>) {
90        let (start_idx, end_idx) = self.buffer_range_to_start_end_idx(range);
91
92        unsafe {
93            ffi::gst_buffer_list_remove(
94                self.as_mut_ptr(),
95                start_idx as u32,
96                (end_idx - start_idx) as u32,
97            )
98        }
99    }
100
101    #[doc(alias = "gst_buffer_list_get")]
102    pub fn get(&self, idx: usize) -> Option<&BufferRef> {
103        unsafe {
104            if idx >= self.len() {
105                return None;
106            }
107            let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx as u32);
108            Some(BufferRef::from_ptr(ptr))
109        }
110    }
111
112    #[doc(alias = "gst_buffer_list_get")]
113    pub fn get_owned(&self, idx: usize) -> Option<Buffer> {
114        unsafe {
115            if idx >= self.len() {
116                return None;
117            }
118            let ptr = ffi::gst_buffer_list_get(self.as_mut_ptr(), idx as u32);
119            Some(from_glib_none(ptr))
120        }
121    }
122
123    #[doc(alias = "gst_buffer_list_get_writable")]
124    #[doc(alias = "get_writable")]
125    pub fn get_mut(&mut self, idx: usize) -> Option<&mut BufferRef> {
126        unsafe {
127            if idx >= self.len() {
128                return None;
129            }
130            let ptr = ffi::gst_buffer_list_get_writable(self.as_mut_ptr(), idx as u32);
131            Some(BufferRef::from_mut_ptr(ptr))
132        }
133    }
134
135    #[doc(alias = "gst_buffer_list_length")]
136    pub fn len(&self) -> usize {
137        unsafe { ffi::gst_buffer_list_length(self.as_mut_ptr()) as usize }
138    }
139
140    #[doc(alias = "gst_buffer_list_calculate_size")]
141    pub fn calculate_size(&self) -> usize {
142        unsafe { ffi::gst_buffer_list_calculate_size(self.as_mut_ptr()) }
143    }
144
145    pub fn is_empty(&self) -> bool {
146        self.len() == 0
147    }
148
149    pub fn iter(&self) -> Iter {
150        Iter::new(self)
151    }
152
153    pub fn iter_owned(&self) -> IterOwned {
154        IterOwned::new(self)
155    }
156
157    #[doc(alias = "gst_buffer_list_foreach")]
158    pub fn foreach<F: FnMut(&Buffer, usize) -> ControlFlow<(), ()>>(&self, func: F) {
159        unsafe extern "C" fn trampoline<F: FnMut(&Buffer, usize) -> ControlFlow<(), ()>>(
160            buffer: *mut *mut ffi::GstBuffer,
161            idx: u32,
162            user_data: glib::ffi::gpointer,
163        ) -> glib::ffi::gboolean {
164            let func = user_data as *mut F;
165            let res = (*func)(&Buffer::from_glib_borrow(*buffer), idx as usize);
166
167            matches!(res, ControlFlow::Continue(_)).into_glib()
168        }
169
170        unsafe {
171            let mut func = func;
172            let func_ptr: &mut F = &mut func;
173
174            let _ = ffi::gst_buffer_list_foreach(
175                self.as_ptr() as *mut _,
176                Some(trampoline::<F>),
177                func_ptr as *mut _ as *mut _,
178            );
179        }
180    }
181
182    #[doc(alias = "gst_buffer_list_foreach")]
183    pub fn foreach_mut<F: FnMut(Buffer, usize) -> ControlFlow<Option<Buffer>, Option<Buffer>>>(
184        &mut self,
185        func: F,
186    ) {
187        unsafe extern "C" fn trampoline<
188            F: FnMut(Buffer, usize) -> ControlFlow<Option<Buffer>, Option<Buffer>>,
189        >(
190            buffer: *mut *mut ffi::GstBuffer,
191            idx: u32,
192            user_data: glib::ffi::gpointer,
193        ) -> glib::ffi::gboolean {
194            let func = user_data as *mut F;
195            let res = (*func)(
196                Buffer::from_glib_full(ptr::replace(
197                    buffer as *mut *const ffi::GstBuffer,
198                    ptr::null_mut::<ffi::GstBuffer>(),
199                )),
200                idx as usize,
201            );
202
203            let (cont, res_buffer) = match res {
204                ControlFlow::Continue(res_buffer) => (true, res_buffer),
205                ControlFlow::Break(res_buffer) => (false, res_buffer),
206            };
207
208            match res_buffer {
209                None => {
210                    *buffer = ptr::null_mut();
211                }
212                Some(new_buffer) => {
213                    *buffer = new_buffer.into_glib_ptr();
214                }
215            }
216
217            cont.into_glib()
218        }
219
220        unsafe {
221            let mut func = func;
222            let func_ptr: &mut F = &mut func;
223
224            let _ = ffi::gst_buffer_list_foreach(
225                self.as_ptr() as *mut _,
226                Some(trampoline::<F>),
227                func_ptr as *mut _ as *mut _,
228            );
229        }
230    }
231
232    pub fn drain(&mut self, range: impl RangeBounds<usize>) -> Drain<'_> {
233        let (start_idx, end_idx) = self.buffer_range_to_start_end_idx(range);
234        Drain {
235            list: self,
236            start_idx,
237            end_idx,
238        }
239    }
240}
241
242impl Default for BufferList {
243    fn default() -> Self {
244        Self::new()
245    }
246}
247
248impl fmt::Debug for BufferList {
249    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
250        BufferListRef::fmt(self, f)
251    }
252}
253
254impl fmt::Debug for BufferListRef {
255    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
256        use crate::{utils::Displayable, ClockTime};
257
258        let size = self.iter().map(|b| b.size()).sum::<usize>();
259        let (pts, dts) = self
260            .get(0)
261            .map(|b| (b.pts(), b.dts()))
262            .unwrap_or((ClockTime::NONE, ClockTime::NONE));
263
264        f.debug_struct("BufferList")
265            .field("ptr", &self.as_ptr())
266            .field("buffers", &self.len())
267            .field("pts", &pts.display())
268            .field("dts", &dts.display())
269            .field("size", &size)
270            .finish()
271    }
272}
273
274macro_rules! define_iter(
275    ($name:ident, $styp:ty, $get_item:expr) => {
276        crate::utils::define_fixed_size_iter!(
277            $name, &'a BufferListRef, $styp,
278            |collection: &BufferListRef| collection.len(),
279            $get_item
280        );
281    }
282);
283
284define_iter!(Iter, &'a BufferRef, |list: &BufferListRef, idx| unsafe {
285    let ptr = ffi::gst_buffer_list_get(list.as_mut_ptr(), idx as u32);
286    BufferRef::from_ptr(ptr)
287});
288
289define_iter!(IterOwned, Buffer, |list: &BufferListRef, idx| unsafe {
290    let ptr = ffi::gst_buffer_list_get(list.as_mut_ptr(), idx as u32);
291    from_glib_none(ptr)
292});
293
294#[derive(Debug)]
295pub struct Drain<'a> {
296    list: &'a mut BufferListRef,
297    start_idx: usize,
298    end_idx: usize,
299}
300
301impl Iterator for Drain<'_> {
302    type Item = Buffer;
303
304    #[inline]
305    fn next(&mut self) -> Option<Self::Item> {
306        if self.start_idx >= self.end_idx {
307            return None;
308        }
309
310        let buffer = unsafe {
311            let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
312                self.list.as_mut_ptr(),
313                self.start_idx as u32,
314            ));
315            ffi::gst_buffer_list_remove(self.list.as_mut_ptr(), self.start_idx as u32, 1);
316            buffer
317        };
318
319        self.end_idx -= 1;
320
321        Some(buffer)
322    }
323
324    #[inline]
325    fn size_hint(&self) -> (usize, Option<usize>) {
326        let remaining = self.end_idx - self.start_idx;
327
328        (remaining, Some(remaining))
329    }
330
331    #[inline]
332    fn count(self) -> usize {
333        self.end_idx - self.start_idx
334    }
335
336    #[inline]
337    fn nth(&mut self, n: usize) -> Option<Self::Item> {
338        let (end, overflow) = self.start_idx.overflowing_add(n);
339        if end >= self.end_idx || overflow {
340            unsafe {
341                ffi::gst_buffer_list_remove(
342                    self.list.as_mut_ptr(),
343                    self.start_idx as u32,
344                    (self.end_idx - self.start_idx) as u32,
345                );
346            }
347            self.start_idx = self.end_idx;
348            None
349        } else {
350            let buffer = unsafe {
351                let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
352                    self.list.as_mut_ptr(),
353                    end as u32,
354                ));
355                ffi::gst_buffer_list_remove(
356                    self.list.as_mut_ptr(),
357                    self.start_idx as u32,
358                    n as u32,
359                );
360                buffer
361            };
362            self.end_idx -= n;
363            Some(buffer)
364        }
365    }
366
367    #[inline]
368    fn last(mut self) -> Option<Self::Item> {
369        if self.start_idx == self.end_idx {
370            None
371        } else {
372            let buffer = unsafe {
373                let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
374                    self.list.as_mut_ptr(),
375                    self.end_idx as u32 - 1,
376                ));
377                ffi::gst_buffer_list_remove(
378                    self.list.as_mut_ptr(),
379                    self.start_idx as u32,
380                    (self.end_idx - self.start_idx) as u32,
381                );
382                buffer
383            };
384            self.end_idx = self.start_idx;
385            Some(buffer)
386        }
387    }
388}
389
390impl DoubleEndedIterator for Drain<'_> {
391    #[inline]
392    fn next_back(&mut self) -> Option<Self::Item> {
393        if self.start_idx == self.end_idx {
394            return None;
395        }
396
397        self.end_idx -= 1;
398        let buffer = unsafe {
399            let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
400                self.list.as_mut_ptr(),
401                self.end_idx as u32,
402            ));
403            ffi::gst_buffer_list_remove(self.list.as_mut_ptr(), self.end_idx as u32, 1);
404            buffer
405        };
406
407        Some(buffer)
408    }
409
410    #[inline]
411    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
412        let (end, overflow) = self.end_idx.overflowing_sub(n);
413        if end <= self.start_idx || overflow {
414            unsafe {
415                ffi::gst_buffer_list_remove(
416                    self.list.as_mut_ptr(),
417                    self.start_idx as u32,
418                    (self.end_idx - self.start_idx) as u32,
419                );
420            }
421            self.start_idx = self.end_idx;
422            None
423        } else {
424            self.end_idx = end - 1;
425            let buffer = unsafe {
426                let buffer = Buffer::from_glib_none(ffi::gst_buffer_list_get(
427                    self.list.as_mut_ptr(),
428                    self.end_idx as u32,
429                ));
430                ffi::gst_buffer_list_remove(self.list.as_mut_ptr(), self.end_idx as u32, n as u32);
431                buffer
432            };
433
434            Some(buffer)
435        }
436    }
437}
438
439impl ExactSizeIterator for Drain<'_> {}
440
441impl std::iter::FusedIterator for Drain<'_> {}
442
443impl Drop for Drain<'_> {
444    fn drop(&mut self) {
445        if self.start_idx >= self.end_idx {
446            return;
447        }
448
449        unsafe {
450            ffi::gst_buffer_list_remove(
451                self.list.as_mut_ptr(),
452                self.start_idx as u32,
453                (self.end_idx - self.start_idx) as u32,
454            );
455        }
456    }
457}
458
459impl<'a> IntoIterator for &'a BufferListRef {
460    type IntoIter = Iter<'a>;
461    type Item = &'a BufferRef;
462
463    fn into_iter(self) -> Self::IntoIter {
464        self.iter()
465    }
466}
467
468impl From<Buffer> for BufferList {
469    fn from(value: Buffer) -> Self {
470        skip_assert_initialized!();
471
472        let mut list = BufferList::new_sized(1);
473        {
474            let list = list.get_mut().unwrap();
475            list.add(value);
476        }
477        list
478    }
479}
480
481impl<const N: usize> From<[Buffer; N]> for BufferList {
482    fn from(value: [Buffer; N]) -> Self {
483        skip_assert_initialized!();
484
485        let mut list = BufferList::new_sized(N);
486        {
487            let list = list.get_mut().unwrap();
488            value.into_iter().for_each(|b| list.add(b));
489        }
490        list
491    }
492}
493
494impl std::iter::FromIterator<Buffer> for BufferList {
495    fn from_iter<T: IntoIterator<Item = Buffer>>(iter: T) -> Self {
496        assert_initialized_main_thread!();
497
498        let iter = iter.into_iter();
499
500        let mut list = BufferList::new_sized(iter.size_hint().0);
501
502        {
503            let list = list.get_mut().unwrap();
504            iter.for_each(|b| list.add(b));
505        }
506
507        list
508    }
509}
510
511impl std::iter::Extend<Buffer> for BufferListRef {
512    fn extend<T: IntoIterator<Item = Buffer>>(&mut self, iter: T) {
513        iter.into_iter().for_each(|b| self.add(b));
514    }
515}
516
517#[cfg(test)]
518mod tests {
519    use super::*;
520    use crate::ClockTime;
521
522    fn make_buffer_list(size: usize) -> BufferList {
523        skip_assert_initialized!();
524
525        let mut buffer_list = BufferList::new();
526        {
527            let buffer_list = buffer_list.get_mut().unwrap();
528            for i in 0..size {
529                let mut buffer = Buffer::new();
530                buffer
531                    .get_mut()
532                    .unwrap()
533                    .set_pts(ClockTime::SECOND * i as u64);
534                buffer_list.add(buffer);
535            }
536        }
537        buffer_list
538    }
539
540    #[test]
541    fn test_foreach() {
542        crate::init().unwrap();
543
544        let buffer_list = make_buffer_list(2);
545
546        let mut res = vec![];
547        buffer_list.foreach(|buffer, idx| {
548            res.push((buffer.pts(), idx));
549            ControlFlow::Continue(())
550        });
551
552        assert_eq!(
553            res,
554            &[(Some(ClockTime::ZERO), 0), (Some(ClockTime::SECOND), 1)]
555        );
556    }
557
558    #[test]
559    fn test_foreach_mut() {
560        crate::init().unwrap();
561
562        let mut buffer_list = make_buffer_list(3);
563
564        let mut res = vec![];
565        buffer_list.get_mut().unwrap().foreach_mut(|buffer, idx| {
566            res.push((buffer.pts(), idx));
567
568            if let Some(ClockTime::ZERO) = buffer.pts() {
569                ControlFlow::Continue(Some(buffer))
570            } else if let Some(ClockTime::SECOND) = buffer.pts() {
571                ControlFlow::Continue(None)
572            } else {
573                let mut new_buffer = Buffer::new();
574                new_buffer.get_mut().unwrap().set_pts(3 * ClockTime::SECOND);
575                ControlFlow::Continue(Some(new_buffer))
576            }
577        });
578
579        assert_eq!(
580            res,
581            &[
582                (Some(ClockTime::ZERO), 0),
583                (Some(ClockTime::SECOND), 1),
584                (Some(2 * ClockTime::SECOND), 1)
585            ]
586        );
587
588        let mut res = vec![];
589        buffer_list.foreach(|buffer, idx| {
590            res.push((buffer.pts(), idx));
591            ControlFlow::Continue(())
592        });
593
594        assert_eq!(
595            res,
596            &[(Some(ClockTime::ZERO), 0), (Some(3 * ClockTime::SECOND), 1)]
597        );
598
599        // Try removing buffers from inside foreach_mut
600        let mut buffer_list = BufferList::new();
601        for i in 0..10 {
602            let buffer_list = buffer_list.get_mut().unwrap();
603            let mut buffer = Buffer::new();
604            buffer.get_mut().unwrap().set_pts(i * ClockTime::SECOND);
605            buffer_list.add(buffer);
606        }
607
608        assert_eq!(buffer_list.len(), 10);
609
610        let buffer_list_ref = buffer_list.make_mut();
611
612        buffer_list_ref.foreach_mut(|buf, _n| {
613            let keep_packet = (buf.pts().unwrap() / ClockTime::SECOND) % 3 != 0;
614            ControlFlow::Continue(keep_packet.then_some(buf))
615        });
616
617        assert_eq!(buffer_list.len(), 6);
618
619        let res = buffer_list
620            .iter()
621            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
622            .collect::<Vec<_>>();
623
624        assert_eq!(res, &[1, 2, 4, 5, 7, 8]);
625    }
626
627    #[test]
628    fn test_remove() {
629        crate::init().unwrap();
630
631        let mut buffer_list = make_buffer_list(10);
632
633        buffer_list.make_mut().remove(0..2);
634
635        let buffers_left = buffer_list
636            .iter()
637            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
638            .collect::<Vec<_>>();
639
640        assert_eq!(buffers_left, &[2, 3, 4, 5, 6, 7, 8, 9]);
641
642        buffer_list.make_mut().remove(0..=2);
643
644        let buffers_left = buffer_list
645            .iter()
646            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
647            .collect::<Vec<_>>();
648
649        assert_eq!(buffers_left, &[5, 6, 7, 8, 9]);
650
651        buffer_list.make_mut().remove(2..);
652
653        let buffers_left = buffer_list
654            .iter()
655            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
656            .collect::<Vec<_>>();
657
658        assert_eq!(buffers_left, &[5, 6]);
659
660        buffer_list.make_mut().remove(..);
661
662        assert!(buffer_list.is_empty());
663    }
664
665    #[test]
666    fn test_drain() {
667        crate::init().unwrap();
668
669        let mut buffer_list = make_buffer_list(10);
670
671        let buffers_removed = buffer_list
672            .make_mut()
673            .drain(0..2)
674            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
675            .collect::<Vec<_>>();
676
677        assert_eq!(buffers_removed, &[0, 1]);
678
679        let buffers_left = buffer_list
680            .iter()
681            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
682            .collect::<Vec<_>>();
683
684        assert_eq!(buffers_left, &[2, 3, 4, 5, 6, 7, 8, 9]);
685
686        let buffers_removed = buffer_list
687            .make_mut()
688            .drain(0..=2)
689            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
690            .collect::<Vec<_>>();
691
692        assert_eq!(buffers_removed, &[2, 3, 4]);
693
694        let buffers_left = buffer_list
695            .iter()
696            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
697            .collect::<Vec<_>>();
698
699        assert_eq!(buffers_left, &[5, 6, 7, 8, 9]);
700
701        let buffers_removed = buffer_list
702            .make_mut()
703            .drain(2..)
704            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
705            .collect::<Vec<_>>();
706
707        assert_eq!(buffers_removed, &[7, 8, 9]);
708
709        let buffers_left = buffer_list
710            .iter()
711            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
712            .collect::<Vec<_>>();
713
714        assert_eq!(buffers_left, &[5, 6]);
715
716        let buffers_removed = buffer_list
717            .make_mut()
718            .drain(..)
719            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
720            .collect::<Vec<_>>();
721
722        assert_eq!(buffers_removed, &[5, 6]);
723
724        assert!(buffer_list.is_empty());
725    }
726
727    #[test]
728    fn test_drain_drop() {
729        crate::init().unwrap();
730
731        let mut buffer_list = make_buffer_list(10);
732
733        buffer_list.make_mut().drain(0..2);
734
735        let buffers_left = buffer_list
736            .iter()
737            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
738            .collect::<Vec<_>>();
739
740        assert_eq!(buffers_left, &[2, 3, 4, 5, 6, 7, 8, 9]);
741
742        buffer_list.make_mut().drain(0..=2);
743
744        let buffers_left = buffer_list
745            .iter()
746            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
747            .collect::<Vec<_>>();
748
749        assert_eq!(buffers_left, &[5, 6, 7, 8, 9]);
750
751        buffer_list.make_mut().drain(2..);
752
753        let buffers_left = buffer_list
754            .iter()
755            .map(|buf| buf.pts().unwrap() / ClockTime::SECOND)
756            .collect::<Vec<_>>();
757
758        assert_eq!(buffers_left, &[5, 6]);
759
760        buffer_list.make_mut().drain(..);
761
762        assert!(buffer_list.is_empty());
763    }
764}