1 // Copyright (C) 2018 Sebastian Dröge <sebastian@centricular.com>
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 use AllocationParams;
10 use Allocator;
11 use BufferPool;
12 use Structure;
13 
14 use glib;
15 use glib::translate::{from_glib, from_glib_full, from_glib_none, ToGlib, ToGlibPtr, ToGlibPtrMut};
16 use glib::IsA;
17 
18 use gst_sys;
19 
20 use std::mem;
21 use std::ops;
22 use std::ptr;
23 
24 #[derive(Debug, Clone, PartialEq, Eq)]
25 pub struct BufferPoolConfig(Structure);
26 
27 impl ops::Deref for BufferPoolConfig {
28     type Target = ::StructureRef;
29 
deref(&self) -> &::StructureRef30     fn deref(&self) -> &::StructureRef {
31         self.0.deref()
32     }
33 }
34 
35 impl ops::DerefMut for BufferPoolConfig {
deref_mut(&mut self) -> &mut ::StructureRef36     fn deref_mut(&mut self) -> &mut ::StructureRef {
37         self.0.deref_mut()
38     }
39 }
40 
41 impl AsRef<::StructureRef> for BufferPoolConfig {
as_ref(&self) -> &::StructureRef42     fn as_ref(&self) -> &::StructureRef {
43         self.0.as_ref()
44     }
45 }
46 
47 impl AsMut<::StructureRef> for BufferPoolConfig {
as_mut(&mut self) -> &mut ::StructureRef48     fn as_mut(&mut self) -> &mut ::StructureRef {
49         self.0.as_mut()
50     }
51 }
52 
53 impl BufferPoolConfig {
add_option(&mut self, option: &str)54     pub fn add_option(&mut self, option: &str) {
55         unsafe {
56             gst_sys::gst_buffer_pool_config_add_option(
57                 self.0.to_glib_none_mut().0,
58                 option.to_glib_none().0,
59             );
60         }
61     }
62 
has_option(&self, option: &str) -> bool63     pub fn has_option(&self, option: &str) -> bool {
64         unsafe {
65             from_glib(gst_sys::gst_buffer_pool_config_has_option(
66                 self.0.to_glib_none().0,
67                 option.to_glib_none().0,
68             ))
69         }
70     }
71 
get_options(&self) -> Vec<String>72     pub fn get_options(&self) -> Vec<String> {
73         unsafe {
74             let n = gst_sys::gst_buffer_pool_config_n_options(self.0.to_glib_none().0) as usize;
75             let mut options = Vec::with_capacity(n);
76 
77             for i in 0..n {
78                 options.push(from_glib_none(gst_sys::gst_buffer_pool_config_get_option(
79                     self.0.to_glib_none().0,
80                     i as u32,
81                 )));
82             }
83 
84             options
85         }
86     }
87 
set_params( &mut self, caps: Option<&::Caps>, size: u32, min_buffers: u32, max_buffers: u32, )88     pub fn set_params(
89         &mut self,
90         caps: Option<&::Caps>,
91         size: u32,
92         min_buffers: u32,
93         max_buffers: u32,
94     ) {
95         unsafe {
96             gst_sys::gst_buffer_pool_config_set_params(
97                 self.0.to_glib_none_mut().0,
98                 caps.to_glib_none().0,
99                 size,
100                 min_buffers,
101                 max_buffers,
102             );
103         }
104     }
105 
get_params(&self) -> Option<(Option<::Caps>, u32, u32, u32)>106     pub fn get_params(&self) -> Option<(Option<::Caps>, u32, u32, u32)> {
107         unsafe {
108             let mut caps = ptr::null_mut();
109             let mut size = mem::MaybeUninit::uninit();
110             let mut min_buffers = mem::MaybeUninit::uninit();
111             let mut max_buffers = mem::MaybeUninit::uninit();
112 
113             let ret: bool = from_glib(gst_sys::gst_buffer_pool_config_get_params(
114                 self.0.to_glib_none().0,
115                 &mut caps,
116                 size.as_mut_ptr(),
117                 min_buffers.as_mut_ptr(),
118                 max_buffers.as_mut_ptr(),
119             ));
120             if !ret {
121                 return None;
122             }
123 
124             Some((
125                 from_glib_none(caps),
126                 size.assume_init(),
127                 min_buffers.assume_init(),
128                 max_buffers.assume_init(),
129             ))
130         }
131     }
132 
validate_params( &self, caps: Option<&::Caps>, size: u32, min_buffers: u32, max_buffers: u32, ) -> Result<(), glib::BoolError>133     pub fn validate_params(
134         &self,
135         caps: Option<&::Caps>,
136         size: u32,
137         min_buffers: u32,
138         max_buffers: u32,
139     ) -> Result<(), glib::BoolError> {
140         unsafe {
141             glib_result_from_gboolean!(
142                 gst_sys::gst_buffer_pool_config_validate_params(
143                     self.0.to_glib_none().0,
144                     caps.to_glib_none().0,
145                     size,
146                     min_buffers,
147                     max_buffers,
148                 ),
149                 "Parameters are not valid in this context"
150             )
151         }
152     }
153 
get_allocator(&self) -> Option<(Option<Allocator>, AllocationParams)>154     pub fn get_allocator(&self) -> Option<(Option<Allocator>, AllocationParams)> {
155         unsafe {
156             let mut allocator = ptr::null_mut();
157             let mut params = mem::MaybeUninit::zeroed();
158             let ret = from_glib(gst_sys::gst_buffer_pool_config_get_allocator(
159                 self.0.to_glib_none().0,
160                 &mut allocator,
161                 params.as_mut_ptr(),
162             ));
163             if ret {
164                 Some((from_glib_none(allocator), params.assume_init().into()))
165             } else {
166                 None
167             }
168         }
169     }
170 
set_allocator(&self, allocator: Option<&Allocator>, params: Option<&AllocationParams>)171     pub fn set_allocator(&self, allocator: Option<&Allocator>, params: Option<&AllocationParams>) {
172         assert!(allocator.is_some() || params.is_some());
173         unsafe {
174             gst_sys::gst_buffer_pool_config_set_allocator(
175                 self.0.to_glib_none().0,
176                 allocator.to_glib_none().0,
177                 match params {
178                     Some(val) => val.as_ptr(),
179                     None => ptr::null(),
180                 },
181             )
182         }
183     }
184     // TODO: options iterator
185 }
186 
187 #[derive(Debug)]
188 pub struct BufferPoolAcquireParams(gst_sys::GstBufferPoolAcquireParams);
189 
190 unsafe impl Send for BufferPoolAcquireParams {}
191 unsafe impl Sync for BufferPoolAcquireParams {}
192 
193 impl BufferPoolAcquireParams {
with_flags(flags: ::BufferPoolAcquireFlags) -> Self194     pub fn with_flags(flags: ::BufferPoolAcquireFlags) -> Self {
195         BufferPoolAcquireParams(gst_sys::GstBufferPoolAcquireParams {
196             format: gst_sys::GST_FORMAT_UNDEFINED,
197             start: -1,
198             stop: -1,
199             flags: flags.to_glib(),
200             _gst_reserved: [ptr::null_mut(); 4],
201         })
202     }
203 
with_start_stop<T: ::SpecificFormattedValue>( start: T, stop: T, flags: ::BufferPoolAcquireFlags, ) -> Self204     pub fn with_start_stop<T: ::SpecificFormattedValue>(
205         start: T,
206         stop: T,
207         flags: ::BufferPoolAcquireFlags,
208     ) -> Self {
209         unsafe {
210             BufferPoolAcquireParams(gst_sys::GstBufferPoolAcquireParams {
211                 format: start.get_format().to_glib(),
212                 start: start.to_raw_value(),
213                 stop: stop.to_raw_value(),
214                 flags: flags.to_glib(),
215                 _gst_reserved: [ptr::null_mut(); 4],
216             })
217         }
218     }
219 
flags(&self) -> ::BufferPoolAcquireFlags220     pub fn flags(&self) -> ::BufferPoolAcquireFlags {
221         from_glib(self.0.flags)
222     }
223 
format(&self) -> ::Format224     pub fn format(&self) -> ::Format {
225         from_glib(self.0.format)
226     }
227 
start(&self) -> ::GenericFormattedValue228     pub fn start(&self) -> ::GenericFormattedValue {
229         ::GenericFormattedValue::new(from_glib(self.0.format), self.0.start)
230     }
231 
stop(&self) -> ::GenericFormattedValue232     pub fn stop(&self) -> ::GenericFormattedValue {
233         ::GenericFormattedValue::new(from_glib(self.0.format), self.0.stop)
234     }
235 }
236 
237 impl PartialEq for BufferPoolAcquireParams {
eq(&self, other: &Self) -> bool238     fn eq(&self, other: &Self) -> bool {
239         self.format() == other.format()
240             && self.start() == other.start()
241             && self.stop() == other.stop()
242     }
243 }
244 
245 impl Eq for BufferPoolAcquireParams {}
246 
247 #[doc(hidden)]
248 impl<'a> ToGlibPtr<'a, *const gst_sys::GstBufferPoolAcquireParams> for BufferPoolAcquireParams {
249     type Storage = &'a Self;
250 
to_glib_none( &'a self, ) -> glib::translate::Stash<'a, *const gst_sys::GstBufferPoolAcquireParams, Self>251     fn to_glib_none(
252         &'a self,
253     ) -> glib::translate::Stash<'a, *const gst_sys::GstBufferPoolAcquireParams, Self> {
254         glib::translate::Stash(&self.0, self)
255     }
256 }
257 
258 #[doc(hidden)]
259 impl<'a> ToGlibPtrMut<'a, *mut gst_sys::GstBufferPoolAcquireParams> for BufferPoolAcquireParams {
260     type Storage = &'a mut Self;
261 
to_glib_none_mut( &'a mut self, ) -> glib::translate::StashMut<'a, *mut gst_sys::GstBufferPoolAcquireParams, Self>262     fn to_glib_none_mut(
263         &'a mut self,
264     ) -> glib::translate::StashMut<'a, *mut gst_sys::GstBufferPoolAcquireParams, Self> {
265         glib::translate::StashMut(&mut self.0, self)
266     }
267 }
268 
269 impl BufferPool {
new() -> BufferPool270     pub fn new() -> BufferPool {
271         assert_initialized_main_thread!();
272         let (major, minor, _, _) = ::version();
273         if (major, minor) > (1, 12) {
274             unsafe { from_glib_full(gst_sys::gst_buffer_pool_new()) }
275         } else {
276             // Work-around for 1.14 switching from transfer-floating to transfer-full
277             unsafe { from_glib_none(gst_sys::gst_buffer_pool_new()) }
278         }
279     }
280 }
281 
282 impl Default for BufferPool {
default() -> Self283     fn default() -> Self {
284         Self::new()
285     }
286 }
287 
288 pub trait BufferPoolExtManual: 'static {
get_config(&self) -> BufferPoolConfig289     fn get_config(&self) -> BufferPoolConfig;
set_config(&self, config: BufferPoolConfig) -> Result<(), glib::error::BoolError>290     fn set_config(&self, config: BufferPoolConfig) -> Result<(), glib::error::BoolError>;
291 
is_flushing(&self) -> bool292     fn is_flushing(&self) -> bool;
293 
acquire_buffer( &self, params: Option<&BufferPoolAcquireParams>, ) -> Result<::Buffer, ::FlowError>294     fn acquire_buffer(
295         &self,
296         params: Option<&BufferPoolAcquireParams>,
297     ) -> Result<::Buffer, ::FlowError>;
release_buffer(&self, buffer: ::Buffer)298     fn release_buffer(&self, buffer: ::Buffer);
299 }
300 
301 impl<O: IsA<BufferPool>> BufferPoolExtManual for O {
get_config(&self) -> BufferPoolConfig302     fn get_config(&self) -> BufferPoolConfig {
303         unsafe {
304             let ptr = gst_sys::gst_buffer_pool_get_config(self.as_ref().to_glib_none().0);
305             BufferPoolConfig(from_glib_full(ptr))
306         }
307     }
308 
set_config(&self, config: BufferPoolConfig) -> Result<(), glib::error::BoolError>309     fn set_config(&self, config: BufferPoolConfig) -> Result<(), glib::error::BoolError> {
310         unsafe {
311             glib_result_from_gboolean!(
312                 gst_sys::gst_buffer_pool_set_config(
313                     self.as_ref().to_glib_none().0,
314                     config.0.into_ptr()
315                 ),
316                 "Failed to set config",
317             )
318         }
319     }
320 
is_flushing(&self) -> bool321     fn is_flushing(&self) -> bool {
322         unsafe {
323             let stash = self.as_ref().to_glib_none();
324             let ptr: *mut gst_sys::GstBufferPool = stash.0;
325 
326             from_glib((*ptr).flushing)
327         }
328     }
329 
acquire_buffer( &self, params: Option<&BufferPoolAcquireParams>, ) -> Result<::Buffer, ::FlowError>330     fn acquire_buffer(
331         &self,
332         params: Option<&BufferPoolAcquireParams>,
333     ) -> Result<::Buffer, ::FlowError> {
334         let params_ptr = params.to_glib_none().0 as *mut _;
335 
336         unsafe {
337             let mut buffer = ptr::null_mut();
338             let ret: ::FlowReturn = from_glib(gst_sys::gst_buffer_pool_acquire_buffer(
339                 self.as_ref().to_glib_none().0,
340                 &mut buffer,
341                 params_ptr,
342             ));
343 
344             ret.into_result_value(|| from_glib_full(buffer))
345         }
346     }
347 
release_buffer(&self, buffer: ::Buffer)348     fn release_buffer(&self, buffer: ::Buffer) {
349         unsafe {
350             gst_sys::gst_buffer_pool_release_buffer(
351                 self.as_ref().to_glib_none().0,
352                 buffer.into_ptr(),
353             );
354         }
355     }
356 }
357 
358 #[cfg(test)]
359 mod tests {
360     use super::*;
361     use prelude::*;
362 
363     #[test]
test_pool()364     fn test_pool() {
365         ::init().unwrap();
366 
367         let pool = ::BufferPool::new();
368         let mut config = pool.get_config();
369         config.set_params(Some(&::Caps::new_simple("foo/bar", &[])), 1024, 0, 2);
370         pool.set_config(config).unwrap();
371 
372         pool.set_active(true).unwrap();
373 
374         let params = ::BufferPoolAcquireParams::with_flags(::BufferPoolAcquireFlags::DONTWAIT);
375 
376         let _buf1 = pool.acquire_buffer(Some(&params)).unwrap();
377         let buf2 = pool.acquire_buffer(Some(&params)).unwrap();
378 
379         assert!(pool.acquire_buffer(Some(&params)).is_err());
380 
381         drop(buf2);
382         let _buf2 = pool.acquire_buffer(Some(&params)).unwrap();
383 
384         pool.set_active(false).unwrap();
385     }
386 }
387