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