Skip to main content

gstreamer/
buffer_pool.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    marker::PhantomData,
5    mem, ops,
6    ops::{Deref, DerefMut},
7    ptr,
8};
9
10use glib::{prelude::*, translate::*};
11
12use crate::{AllocationParams, Allocator, BufferPool, Structure, StructureRef, ffi};
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15#[repr(transparent)]
16pub struct BufferPoolConfig(Structure);
17
18impl Deref for BufferPoolConfig {
19    type Target = BufferPoolConfigRef;
20
21    #[inline]
22    fn deref(&self) -> &BufferPoolConfigRef {
23        unsafe { &*(self.0.as_ptr() as *const StructureRef as *const BufferPoolConfigRef) }
24    }
25}
26
27impl DerefMut for BufferPoolConfig {
28    #[inline]
29    fn deref_mut(&mut self) -> &mut BufferPoolConfigRef {
30        unsafe { &mut *(self.0.as_ptr() as *mut StructureRef as *mut BufferPoolConfigRef) }
31    }
32}
33
34impl AsRef<BufferPoolConfigRef> for BufferPoolConfig {
35    #[inline]
36    fn as_ref(&self) -> &BufferPoolConfigRef {
37        self.deref()
38    }
39}
40
41impl AsMut<BufferPoolConfigRef> for BufferPoolConfig {
42    #[inline]
43    fn as_mut(&mut self) -> &mut BufferPoolConfigRef {
44        self.deref_mut()
45    }
46}
47
48#[derive(Debug)]
49#[repr(transparent)]
50pub struct BufferPoolConfigRef(StructureRef);
51
52impl BufferPoolConfigRef {
53    #[inline]
54    pub unsafe fn from_glib_borrow<'a>(ptr: *const ffi::GstStructure) -> &'a BufferPoolConfigRef {
55        unsafe {
56            debug_assert!(!ptr.is_null());
57
58            &*(ptr as *mut StructureRef as *mut BufferPoolConfigRef)
59        }
60    }
61
62    #[inline]
63    pub unsafe fn from_glib_borrow_mut<'a>(
64        ptr: *mut ffi::GstStructure,
65    ) -> &'a mut BufferPoolConfigRef {
66        unsafe {
67            debug_assert!(!ptr.is_null());
68
69            &mut *(ptr as *mut StructureRef as *mut BufferPoolConfigRef)
70        }
71    }
72
73    #[inline]
74    pub fn as_ptr(&self) -> *const ffi::GstStructure {
75        self as *const Self as *const ffi::GstStructure
76    }
77
78    #[inline]
79    pub fn as_mut_ptr(&self) -> *mut ffi::GstStructure {
80        self as *const Self as *mut ffi::GstStructure
81    }
82}
83
84impl ops::Deref for BufferPoolConfigRef {
85    type Target = crate::StructureRef;
86
87    #[inline]
88    fn deref(&self) -> &crate::StructureRef {
89        &self.0
90    }
91}
92
93impl ops::DerefMut for BufferPoolConfigRef {
94    #[inline]
95    fn deref_mut(&mut self) -> &mut crate::StructureRef {
96        &mut self.0
97    }
98}
99
100impl AsRef<crate::StructureRef> for BufferPoolConfigRef {
101    #[inline]
102    fn as_ref(&self) -> &crate::StructureRef {
103        &self.0
104    }
105}
106
107impl AsMut<crate::StructureRef> for BufferPoolConfigRef {
108    #[inline]
109    fn as_mut(&mut self) -> &mut crate::StructureRef {
110        &mut self.0
111    }
112}
113
114impl BufferPoolConfigRef {
115    #[doc(alias = "gst_buffer_pool_config_add_option")]
116    pub fn add_option(&mut self, option: &str) {
117        unsafe {
118            ffi::gst_buffer_pool_config_add_option(self.0.as_mut_ptr(), option.to_glib_none().0);
119        }
120    }
121
122    #[doc(alias = "gst_buffer_pool_config_has_option")]
123    pub fn has_option(&self, option: &str) -> bool {
124        unsafe {
125            from_glib(ffi::gst_buffer_pool_config_has_option(
126                self.0.as_mut_ptr(),
127                option.to_glib_none().0,
128            ))
129        }
130    }
131
132    #[doc(alias = "get_options")]
133    #[doc(alias = "gst_buffer_pool_config_n_options")]
134    #[doc(alias = "gst_buffer_pool_config_get_option")]
135    pub fn options(&self) -> OptionsIter<'_> {
136        OptionsIter::new(self)
137    }
138
139    #[doc(alias = "gst_buffer_pool_config_set_params")]
140    pub fn set_params(
141        &mut self,
142        caps: Option<&crate::Caps>,
143        size: u32,
144        min_buffers: u32,
145        max_buffers: u32,
146    ) {
147        unsafe {
148            ffi::gst_buffer_pool_config_set_params(
149                self.0.as_mut_ptr(),
150                caps.to_glib_none().0,
151                size,
152                min_buffers,
153                max_buffers,
154            );
155        }
156    }
157
158    #[doc(alias = "get_params")]
159    #[doc(alias = "gst_buffer_pool_config_get_params")]
160    pub fn params(&self) -> Option<(Option<crate::Caps>, u32, u32, u32)> {
161        unsafe {
162            let mut caps = ptr::null_mut();
163            let mut size = mem::MaybeUninit::uninit();
164            let mut min_buffers = mem::MaybeUninit::uninit();
165            let mut max_buffers = mem::MaybeUninit::uninit();
166
167            let ret: bool = from_glib(ffi::gst_buffer_pool_config_get_params(
168                self.0.as_mut_ptr(),
169                &mut caps,
170                size.as_mut_ptr(),
171                min_buffers.as_mut_ptr(),
172                max_buffers.as_mut_ptr(),
173            ));
174            if !ret {
175                return None;
176            }
177
178            Some((
179                from_glib_none(caps),
180                size.assume_init(),
181                min_buffers.assume_init(),
182                max_buffers.assume_init(),
183            ))
184        }
185    }
186
187    #[doc(alias = "gst_buffer_pool_config_validate_params")]
188    pub fn validate_params(
189        &self,
190        caps: Option<&crate::Caps>,
191        size: u32,
192        min_buffers: u32,
193        max_buffers: u32,
194    ) -> Result<(), glib::BoolError> {
195        unsafe {
196            glib::result_from_gboolean!(
197                ffi::gst_buffer_pool_config_validate_params(
198                    self.0.as_mut_ptr(),
199                    caps.to_glib_none().0,
200                    size,
201                    min_buffers,
202                    max_buffers,
203                ),
204                "Parameters are not valid in this context"
205            )
206        }
207    }
208
209    #[doc(alias = "get_allocator")]
210    #[doc(alias = "gst_buffer_pool_config_get_allocator")]
211    pub fn allocator(&self) -> Option<(Option<Allocator>, AllocationParams)> {
212        unsafe {
213            let mut allocator = ptr::null_mut();
214            let mut params = mem::MaybeUninit::uninit();
215            let ret = from_glib(ffi::gst_buffer_pool_config_get_allocator(
216                self.0.as_mut_ptr(),
217                &mut allocator,
218                params.as_mut_ptr(),
219            ));
220            if ret {
221                Some((from_glib_none(allocator), params.assume_init().into()))
222            } else {
223                None
224            }
225        }
226    }
227
228    #[doc(alias = "gst_buffer_pool_config_set_allocator")]
229    pub fn set_allocator(
230        &self,
231        allocator: Option<&impl IsA<Allocator>>,
232        params: Option<&AllocationParams>,
233    ) {
234        assert!(allocator.is_some() || params.is_some());
235        unsafe {
236            ffi::gst_buffer_pool_config_set_allocator(
237                self.0.as_mut_ptr(),
238                allocator.to_glib_none().0 as *mut ffi::GstAllocator,
239                match params {
240                    Some(val) => val.as_ptr(),
241                    None => ptr::null(),
242                },
243            )
244        }
245    }
246}
247
248crate::utils::define_fixed_size_iter!(
249    OptionsIter,
250    &'a BufferPoolConfigRef,
251    &'a glib::GStr,
252    |collection: &BufferPoolConfigRef| unsafe {
253        ffi::gst_buffer_pool_config_n_options(collection.as_mut_ptr()) as usize
254    },
255    |collection: &BufferPoolConfigRef, idx: usize| unsafe {
256        glib::GStr::from_ptr(ffi::gst_buffer_pool_config_get_option(
257            collection.as_mut_ptr(),
258            idx as u32,
259        ))
260    }
261);
262
263#[derive(Debug, Copy, Clone)]
264#[doc(alias = "GstBufferPoolAcquireParams")]
265pub struct BufferPoolAcquireParams(ffi::GstBufferPoolAcquireParams);
266
267unsafe impl Send for BufferPoolAcquireParams {}
268unsafe impl Sync for BufferPoolAcquireParams {}
269
270impl BufferPoolAcquireParams {
271    pub fn with_flags(flags: crate::BufferPoolAcquireFlags) -> Self {
272        skip_assert_initialized!();
273        BufferPoolAcquireParams(ffi::GstBufferPoolAcquireParams {
274            format: ffi::GST_FORMAT_UNDEFINED,
275            start: -1,
276            stop: -1,
277            flags: flags.into_glib(),
278            _gst_reserved: [ptr::null_mut(); 4],
279        })
280    }
281
282    pub fn with_start_stop<T: crate::format::SpecificFormattedValue>(
283        start: T,
284        stop: T,
285        flags: crate::BufferPoolAcquireFlags,
286    ) -> Self {
287        skip_assert_initialized!();
288        unsafe {
289            BufferPoolAcquireParams(ffi::GstBufferPoolAcquireParams {
290                format: start.format().into_glib(),
291                start: start.into_raw_value(),
292                stop: stop.into_raw_value(),
293                flags: flags.into_glib(),
294                _gst_reserved: [ptr::null_mut(); 4],
295            })
296        }
297    }
298
299    pub fn flags(&self) -> crate::BufferPoolAcquireFlags {
300        unsafe { from_glib(self.0.flags) }
301    }
302
303    pub fn format(&self) -> crate::Format {
304        unsafe { from_glib(self.0.format) }
305    }
306
307    pub fn start(&self) -> crate::GenericFormattedValue {
308        unsafe { crate::GenericFormattedValue::new(from_glib(self.0.format), self.0.start) }
309    }
310
311    pub fn stop(&self) -> crate::GenericFormattedValue {
312        unsafe { crate::GenericFormattedValue::new(from_glib(self.0.format), self.0.stop) }
313    }
314
315    pub fn set_flags(&mut self, flags: crate::BufferPoolAcquireFlags) {
316        self.0.flags = flags.into_glib();
317    }
318
319    pub fn set_format(&mut self, format: crate::Format) {
320        self.0.format = format.into_glib();
321    }
322
323    pub fn set_start(&mut self, start: crate::GenericFormattedValue) {
324        assert_eq!(self.format(), start.format());
325        self.0.start = start.value();
326    }
327
328    pub fn set_stop(&mut self, stop: crate::GenericFormattedValue) {
329        assert_eq!(self.format(), stop.format());
330        self.0.stop = stop.value();
331    }
332}
333
334impl PartialEq for BufferPoolAcquireParams {
335    fn eq(&self, other: &Self) -> bool {
336        self.flags() == other.flags()
337            && self.format() == other.format()
338            && self.start() == other.start()
339            && self.stop() == other.stop()
340    }
341}
342
343impl Eq for BufferPoolAcquireParams {}
344
345impl Default for BufferPoolAcquireParams {
346    fn default() -> Self {
347        Self(ffi::GstBufferPoolAcquireParams {
348            format: ffi::GST_FORMAT_UNDEFINED,
349            start: -1,
350            stop: -1,
351            flags: ffi::GST_BUFFER_POOL_ACQUIRE_FLAG_NONE,
352            _gst_reserved: [ptr::null_mut(); 4],
353        })
354    }
355}
356
357#[doc(hidden)]
358impl<'a> ToGlibPtr<'a, *const ffi::GstBufferPoolAcquireParams> for BufferPoolAcquireParams {
359    type Storage = PhantomData<&'a Self>;
360
361    #[inline]
362    fn to_glib_none(
363        &'a self,
364    ) -> glib::translate::Stash<'a, *const ffi::GstBufferPoolAcquireParams, Self> {
365        glib::translate::Stash(&self.0, PhantomData)
366    }
367}
368
369#[doc(hidden)]
370impl<'a> ToGlibPtrMut<'a, *mut ffi::GstBufferPoolAcquireParams> for BufferPoolAcquireParams {
371    type Storage = PhantomData<&'a mut Self>;
372
373    #[inline]
374    fn to_glib_none_mut(
375        &'a mut self,
376    ) -> glib::translate::StashMut<'a, *mut ffi::GstBufferPoolAcquireParams, Self> {
377        glib::translate::StashMut(&mut self.0, PhantomData)
378    }
379}
380
381#[doc(hidden)]
382impl FromGlibPtrNone<*mut ffi::GstBufferPoolAcquireParams> for BufferPoolAcquireParams {
383    #[inline]
384    unsafe fn from_glib_none(ptr: *mut ffi::GstBufferPoolAcquireParams) -> Self {
385        unsafe { Self(*ptr) }
386    }
387}
388
389pub trait BufferPoolExtManual: IsA<BufferPool> + 'static {
390    /// Gets a copy of the current configuration of the pool. This configuration
391    /// can be modified and used for the [`set_config()`][Self::set_config()] call.
392    ///
393    /// # Returns
394    ///
395    /// a copy of the current configuration of `self`.
396    #[doc(alias = "get_config")]
397    #[doc(alias = "gst_buffer_pool_get_config")]
398    fn config(&self) -> BufferPoolConfig {
399        unsafe {
400            let ptr = ffi::gst_buffer_pool_get_config(self.as_ref().to_glib_none().0);
401            BufferPoolConfig(from_glib_full(ptr))
402        }
403    }
404
405    /// Sets the configuration of the pool. If the pool is already configured, and
406    /// the configuration hasn't changed, this function will return [`true`]. If the
407    /// pool is active, this method will return [`false`] and active configuration
408    /// will remain. Buffers allocated from this pool must be returned or else this
409    /// function will do nothing and return [`false`].
410    ///
411    /// `config` is a [`Structure`][crate::Structure] that contains the configuration parameters for
412    /// the pool. A default and mandatory set of parameters can be configured with
413    /// `gst_buffer_pool_config_set_params()`, `gst_buffer_pool_config_set_allocator()`
414    /// and `gst_buffer_pool_config_add_option()`.
415    ///
416    /// If the parameters in `config` can not be set exactly, this function returns
417    /// [`false`] and will try to update as much state as possible. The new state can
418    /// then be retrieved and refined with [`config()`][Self::config()].
419    ///
420    /// This function takes ownership of `config`.
421    /// ## `config`
422    /// a [`Structure`][crate::Structure]
423    ///
424    /// # Returns
425    ///
426    /// [`true`] when the configuration could be set.
427    #[doc(alias = "gst_buffer_pool_set_config")]
428    fn set_config(&self, config: BufferPoolConfig) -> Result<(), glib::error::BoolError> {
429        unsafe {
430            glib::result_from_gboolean!(
431                ffi::gst_buffer_pool_set_config(
432                    self.as_ref().to_glib_none().0,
433                    config.0.into_glib_ptr()
434                ),
435                "Failed to set config",
436            )
437        }
438    }
439
440    fn is_flushing(&self) -> bool {
441        unsafe {
442            let stash = self.as_ref().to_glib_none();
443            let ptr: *mut ffi::GstBufferPool = stash.0;
444
445            from_glib((*ptr).flushing)
446        }
447    }
448
449    /// Acquires a buffer from `self`. `buffer` should point to a memory location that
450    /// can hold a pointer to the new buffer. When the pool is empty, this function
451    /// will by default block until a buffer is released into the pool again or when
452    /// the pool is set to flushing or deactivated.
453    ///
454    /// `params` can contain optional parameters to influence the allocation.
455    /// ## `params`
456    /// parameters.
457    ///
458    /// # Returns
459    ///
460    /// a [`FlowReturn`][crate::FlowReturn] such as [`FlowReturn::Flushing`][crate::FlowReturn::Flushing] when the pool is
461    /// inactive.
462    ///
463    /// ## `buffer`
464    /// a location for a [`Buffer`][crate::Buffer]
465    #[doc(alias = "gst_buffer_pool_acquire_buffer")]
466    fn acquire_buffer(
467        &self,
468        params: Option<&BufferPoolAcquireParams>,
469    ) -> Result<crate::Buffer, crate::FlowError> {
470        let params_ptr = params.to_glib_none().0 as *mut _;
471
472        unsafe {
473            let mut buffer = ptr::null_mut();
474            crate::FlowSuccess::try_from_glib(ffi::gst_buffer_pool_acquire_buffer(
475                self.as_ref().to_glib_none().0,
476                &mut buffer,
477                params_ptr,
478            ))
479            .map(|_| from_glib_full(buffer))
480        }
481    }
482}
483
484impl<O: IsA<BufferPool>> BufferPoolExtManual for O {}
485
486#[cfg(test)]
487mod tests {
488    use super::*;
489    use crate::prelude::*;
490
491    #[test]
492    fn pool_with_params() {
493        crate::init().unwrap();
494
495        let pool = crate::BufferPool::new();
496        let mut config = pool.config();
497        config.set_params(Some(&crate::Caps::builder("foo/bar").build()), 1024, 0, 2);
498        pool.set_config(config).unwrap();
499
500        pool.set_active(true).unwrap();
501
502        let params =
503            crate::BufferPoolAcquireParams::with_flags(crate::BufferPoolAcquireFlags::DONTWAIT);
504
505        let _buf1 = pool.acquire_buffer(Some(&params)).unwrap();
506        let buf2 = pool.acquire_buffer(Some(&params)).unwrap();
507
508        assert!(pool.acquire_buffer(Some(&params)).is_err());
509
510        drop(buf2);
511        let _buf2 = pool.acquire_buffer(Some(&params)).unwrap();
512
513        pool.set_active(false).unwrap();
514    }
515
516    #[test]
517    fn pool_no_params() {
518        crate::init().unwrap();
519
520        let pool = crate::BufferPool::new();
521        let mut config = pool.config();
522        config.set_params(None, 1024, 0, 2);
523        pool.set_config(config).unwrap();
524
525        pool.set_active(true).unwrap();
526        let _buf1 = pool.acquire_buffer(None).unwrap();
527        pool.set_active(false).unwrap();
528    }
529}