1use std::ptr;
4
5use glib::{
6 prelude::*,
7 subclass::{InitializingObject, prelude::*},
8 translate::*,
9};
10use libc::c_char;
11
12use super::prelude::*;
13use crate::{BufferPool, BufferPoolAcquireParams, BufferPoolConfigRef, ffi};
14
15pub trait BufferPoolImpl: GstObjectImpl + ObjectSubclass<Type: IsA<BufferPool>> {
16 fn acquire_buffer(
33 &self,
34 params: Option<&BufferPoolAcquireParams>,
35 ) -> Result<crate::Buffer, crate::FlowError> {
36 self.parent_acquire_buffer(params)
37 }
38
39 fn alloc_buffer(
56 &self,
57 params: Option<&BufferPoolAcquireParams>,
58 ) -> Result<crate::Buffer, crate::FlowError> {
59 self.parent_alloc_buffer(params)
60 }
61
62 fn flush_start(&self) {
64 self.parent_flush_start()
65 }
66
67 fn flush_stop(&self) {
69 self.parent_flush_stop()
70 }
71
72 fn free_buffer(&self, buffer: crate::Buffer) {
76 self.parent_free_buffer(buffer)
77 }
78
79 fn release_buffer(&self, buffer: crate::Buffer) {
87 self.parent_release_buffer(buffer)
88 }
89
90 fn reset_buffer(&self, buffer: &mut crate::BufferRef) {
99 self.parent_reset_buffer(buffer)
100 }
101
102 fn start(&self) -> bool {
112 self.parent_start()
113 }
114
115 fn stop(&self) -> bool {
123 self.parent_stop()
124 }
125
126 fn options() -> &'static [&'static str] {
135 &[]
136 }
137
138 fn set_config(&self, config: &mut BufferPoolConfigRef) -> bool {
161 self.parent_set_config(config)
162 }
163}
164
165pub trait BufferPoolImplExt: BufferPoolImpl {
166 fn parent_acquire_buffer(
167 &self,
168 params: Option<&BufferPoolAcquireParams>,
169 ) -> Result<crate::Buffer, crate::FlowError> {
170 unsafe {
171 let data = Self::type_data();
172 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
173 if let Some(f) = (*parent_class).acquire_buffer {
174 let params_ptr = mut_override(params.to_glib_none().0);
175 let mut buffer = std::ptr::null_mut();
176
177 let result = f(
178 self.obj()
179 .unsafe_cast_ref::<crate::BufferPool>()
180 .to_glib_none()
181 .0,
182 &mut buffer,
183 params_ptr,
184 );
185
186 crate::FlowSuccess::try_from_glib(result).map(|_| from_glib_full(buffer))
187 } else {
188 Err(crate::FlowError::NotSupported)
189 }
190 }
191 }
192
193 fn parent_alloc_buffer(
194 &self,
195 params: Option<&BufferPoolAcquireParams>,
196 ) -> Result<crate::Buffer, crate::FlowError> {
197 unsafe {
198 let data = Self::type_data();
199 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
200 if let Some(f) = (*parent_class).alloc_buffer {
201 let params_ptr = mut_override(params.to_glib_none().0);
202 let mut buffer = std::ptr::null_mut();
203
204 let result = f(
205 self.obj()
206 .unsafe_cast_ref::<crate::BufferPool>()
207 .to_glib_none()
208 .0,
209 &mut buffer,
210 params_ptr,
211 );
212
213 crate::FlowSuccess::try_from_glib(result).map(|_| from_glib_full(buffer))
214 } else {
215 Err(crate::FlowError::NotSupported)
216 }
217 }
218 }
219
220 fn parent_free_buffer(&self, buffer: crate::Buffer) {
221 unsafe {
222 let data = Self::type_data();
223 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
224 if let Some(f) = (*parent_class).free_buffer {
225 f(
226 self.obj()
227 .unsafe_cast_ref::<crate::BufferPool>()
228 .to_glib_none()
229 .0,
230 buffer.into_glib_ptr(),
231 )
232 }
233 }
234 }
235
236 fn parent_release_buffer(&self, buffer: crate::Buffer) {
237 unsafe {
238 let data = Self::type_data();
239 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
240 if let Some(f) = (*parent_class).release_buffer {
241 f(
242 self.obj()
243 .unsafe_cast_ref::<crate::BufferPool>()
244 .to_glib_none()
245 .0,
246 buffer.into_glib_ptr(),
247 )
248 }
249 }
250 }
251
252 fn parent_reset_buffer(&self, buffer: &mut crate::BufferRef) {
253 unsafe {
254 let data = Self::type_data();
255 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
256 if let Some(f) = (*parent_class).reset_buffer {
257 f(
258 self.obj()
259 .unsafe_cast_ref::<crate::BufferPool>()
260 .to_glib_none()
261 .0,
262 buffer.as_mut_ptr(),
263 )
264 }
265 }
266 }
267
268 fn parent_start(&self) -> bool {
269 unsafe {
270 let data = Self::type_data();
271 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
272 if let Some(f) = (*parent_class).start {
273 let result = f(self
274 .obj()
275 .unsafe_cast_ref::<crate::BufferPool>()
276 .to_glib_none()
277 .0);
278
279 from_glib(result)
280 } else {
281 true
282 }
283 }
284 }
285
286 fn parent_stop(&self) -> bool {
287 unsafe {
288 let data = Self::type_data();
289 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
290 if let Some(f) = (*parent_class).stop {
291 let result = f(self
292 .obj()
293 .unsafe_cast_ref::<crate::BufferPool>()
294 .to_glib_none()
295 .0);
296
297 from_glib(result)
298 } else {
299 true
300 }
301 }
302 }
303
304 fn parent_set_config(&self, config: &mut BufferPoolConfigRef) -> bool {
305 unsafe {
306 let data = Self::type_data();
307 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
308 if let Some(f) = (*parent_class).set_config {
309 let result = f(
310 self.obj()
311 .unsafe_cast_ref::<crate::BufferPool>()
312 .to_glib_none()
313 .0,
314 (*config).as_mut_ptr(),
315 );
316
317 from_glib(result)
318 } else {
319 false
320 }
321 }
322 }
323
324 fn parent_flush_start(&self) {
325 unsafe {
326 let data = Self::type_data();
327 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
328 if let Some(f) = (*parent_class).flush_start {
329 f(self
330 .obj()
331 .unsafe_cast_ref::<crate::BufferPool>()
332 .to_glib_none()
333 .0)
334 }
335 }
336 }
337
338 fn parent_flush_stop(&self) {
339 unsafe {
340 let data = Self::type_data();
341 let parent_class = data.as_ref().parent_class() as *mut ffi::GstBufferPoolClass;
342 if let Some(f) = (*parent_class).flush_stop {
343 f(self
344 .obj()
345 .unsafe_cast_ref::<crate::BufferPool>()
346 .to_glib_none()
347 .0)
348 }
349 }
350 }
351}
352
353impl<T: BufferPoolImpl> BufferPoolImplExt for T {}
354
355unsafe impl<T: BufferPoolImpl> IsSubclassable<T> for BufferPool {
356 fn class_init(klass: &mut glib::Class<Self>) {
357 Self::parent_class_init::<T>(klass);
358 let klass = klass.as_mut();
359 klass.acquire_buffer = Some(buffer_pool_acquire_buffer::<T>);
360 klass.alloc_buffer = Some(buffer_pool_alloc_buffer::<T>);
361 klass.release_buffer = Some(buffer_pool_release_buffer::<T>);
362 klass.reset_buffer = Some(buffer_pool_reset_buffer::<T>);
363 klass.start = Some(buffer_pool_start::<T>);
364 klass.stop = Some(buffer_pool_stop::<T>);
365 klass.get_options = Some(buffer_pool_get_options::<T>);
366 klass.set_config = Some(buffer_pool_set_config::<T>);
367 klass.flush_start = Some(buffer_pool_flush_start::<T>);
368 klass.flush_stop = Some(buffer_pool_flush_stop::<T>);
369 klass.free_buffer = Some(buffer_pool_free_buffer::<T>);
370 }
371
372 fn instance_init(instance: &mut InitializingObject<T>) {
373 Self::parent_instance_init(instance);
374
375 let options = T::options();
378 instance.set_instance_data(T::type_(), glib::StrV::from(options));
379 }
380}
381
382unsafe extern "C" fn buffer_pool_acquire_buffer<T: BufferPoolImpl>(
383 ptr: *mut ffi::GstBufferPool,
384 buffer: *mut *mut ffi::GstBuffer,
385 params: *mut ffi::GstBufferPoolAcquireParams,
386) -> ffi::GstFlowReturn {
387 unsafe {
388 let instance = &*(ptr as *mut T::Instance);
389 let imp = instance.imp();
390 let params: Option<BufferPoolAcquireParams> = from_glib_none(params);
391
392 match imp.acquire_buffer(params.as_ref()) {
393 Ok(b) => {
394 *buffer = b.into_glib_ptr();
395 ffi::GST_FLOW_OK
396 }
397 Err(err) => err.into_glib(),
398 }
399 }
400}
401
402unsafe extern "C" fn buffer_pool_alloc_buffer<T: BufferPoolImpl>(
403 ptr: *mut ffi::GstBufferPool,
404 buffer: *mut *mut ffi::GstBuffer,
405 params: *mut ffi::GstBufferPoolAcquireParams,
406) -> ffi::GstFlowReturn {
407 unsafe {
408 let instance = &*(ptr as *mut T::Instance);
409 let imp = instance.imp();
410 let params: Option<BufferPoolAcquireParams> = from_glib_none(params);
411
412 match imp.alloc_buffer(params.as_ref()) {
413 Ok(b) => {
414 *buffer = b.into_glib_ptr();
415 ffi::GST_FLOW_OK
416 }
417 Err(err) => err.into_glib(),
418 }
419 }
420}
421
422unsafe extern "C" fn buffer_pool_flush_start<T: BufferPoolImpl>(ptr: *mut ffi::GstBufferPool) {
423 unsafe {
424 if (*(ptr as *const glib::gobject_ffi::GObject)).ref_count == 0 {
429 return;
431 }
432
433 let instance = &*(ptr as *mut T::Instance);
434 let imp = instance.imp();
435 imp.flush_start();
436 }
437}
438
439unsafe extern "C" fn buffer_pool_flush_stop<T: BufferPoolImpl>(ptr: *mut ffi::GstBufferPool) {
440 unsafe {
441 if (*(ptr as *const glib::gobject_ffi::GObject)).ref_count == 0 {
446 return;
448 }
449
450 let instance = &*(ptr as *mut T::Instance);
451 let imp = instance.imp();
452 imp.flush_stop();
453 }
454}
455
456unsafe extern "C" fn buffer_pool_free_buffer<T: BufferPoolImpl>(
457 ptr: *mut ffi::GstBufferPool,
458 buffer: *mut ffi::GstBuffer,
459) {
460 unsafe {
461 if (*(ptr as *const glib::gobject_ffi::GObject)).ref_count == 0 {
466 let pool_class =
470 glib::Class::<crate::BufferPool>::from_type(crate::BufferPool::static_type())
471 .unwrap();
472 let pool_class = pool_class.as_ref();
473 if let Some(f) = pool_class.free_buffer {
474 f(ptr, buffer)
475 }
476 return;
477 }
478
479 let instance = &*(ptr as *mut T::Instance);
480 let imp = instance.imp();
481 imp.free_buffer(from_glib_full(buffer));
482 }
483}
484
485unsafe extern "C" fn buffer_pool_release_buffer<T: BufferPoolImpl>(
486 ptr: *mut ffi::GstBufferPool,
487 buffer: *mut ffi::GstBuffer,
488) {
489 unsafe {
490 let instance = &*(ptr as *mut T::Instance);
491 let imp = instance.imp();
492 imp.release_buffer(from_glib_full(buffer));
493 }
494}
495
496unsafe extern "C" fn buffer_pool_reset_buffer<T: BufferPoolImpl>(
497 ptr: *mut ffi::GstBufferPool,
498 buffer: *mut ffi::GstBuffer,
499) {
500 unsafe {
501 let instance = &*(ptr as *mut T::Instance);
502 let imp = instance.imp();
503 imp.reset_buffer(crate::BufferRef::from_mut_ptr(buffer));
504 }
505}
506
507unsafe extern "C" fn buffer_pool_start<T: BufferPoolImpl>(
508 ptr: *mut ffi::GstBufferPool,
509) -> glib::ffi::gboolean {
510 unsafe {
511 let instance = &*(ptr as *mut T::Instance);
512 let imp = instance.imp();
513 imp.start().into_glib()
514 }
515}
516
517unsafe extern "C" fn buffer_pool_stop<T: BufferPoolImpl>(
518 ptr: *mut ffi::GstBufferPool,
519) -> glib::ffi::gboolean {
520 unsafe {
521 if (*(ptr as *const glib::gobject_ffi::GObject)).ref_count == 0 {
526 let pool_class =
530 glib::Class::<crate::BufferPool>::from_type(crate::BufferPool::static_type())
531 .unwrap();
532 let pool_class = pool_class.as_ref();
533 let result = if let Some(f) = pool_class.stop {
534 f(ptr)
535 } else {
536 true.into_glib()
537 };
538
539 return result;
540 }
541
542 let instance = &*(ptr as *mut T::Instance);
543 let imp = instance.imp();
544 imp.stop().into_glib()
545 }
546}
547
548unsafe extern "C" fn buffer_pool_get_options<T: BufferPoolImpl>(
549 ptr: *mut ffi::GstBufferPool,
550) -> *mut *const c_char {
551 unsafe {
552 let instance = &*(ptr as *mut T::Instance);
553 let imp = instance.imp();
554 T::instance_data::<glib::StrV>(imp, T::type_())
555 .map(|p| p.as_ptr() as *mut *const _)
556 .unwrap_or(ptr::null_mut())
557 }
558}
559
560unsafe extern "C" fn buffer_pool_set_config<T: BufferPoolImpl>(
561 ptr: *mut ffi::GstBufferPool,
562 config: *mut ffi::GstStructure,
563) -> glib::ffi::gboolean {
564 unsafe {
565 let instance = &*(ptr as *mut T::Instance);
566 let imp = instance.imp();
567 imp.set_config(BufferPoolConfigRef::from_glib_borrow_mut(config))
568 .into_glib()
569 }
570}
571
572#[cfg(test)]
573mod tests {
574 use std::sync::{
575 Arc,
576 atomic::{AtomicBool, Ordering},
577 };
578
579 use super::*;
580 use crate::prelude::*;
581
582 pub mod imp {
583 use super::*;
584
585 #[derive(Default)]
586 pub struct TestBufferPool;
587
588 impl ObjectImpl for TestBufferPool {}
589 impl GstObjectImpl for TestBufferPool {}
590 impl BufferPoolImpl for TestBufferPool {
591 fn options() -> &'static [&'static str] {
592 &["TEST_OPTION"]
593 }
594
595 fn set_config(&self, config: &mut BufferPoolConfigRef) -> bool {
596 let (caps, size, min_buffers, max_buffers) = config.params().unwrap();
597 config.set_params(caps.as_ref(), size * 2, min_buffers, max_buffers);
598 self.parent_set_config(config)
599 }
600 }
601
602 #[glib::object_subclass]
603 impl ObjectSubclass for TestBufferPool {
604 const NAME: &'static str = "TestBufferPool";
605 type Type = super::TestBufferPool;
606 type ParentType = BufferPool;
607 }
608 }
609
610 glib::wrapper! {
611 pub struct TestBufferPool(ObjectSubclass<imp::TestBufferPool>) @extends BufferPool, crate::Object;
612 }
613
614 impl Default for TestBufferPool {
615 fn default() -> Self {
616 glib::Object::new()
617 }
618 }
619
620 #[test]
621 fn test_pool_options() {
622 crate::init().unwrap();
623 let pool = TestBufferPool::default();
624 assert_eq!(pool.options(), vec!["TEST_OPTION"]);
625 }
626
627 #[test]
628 fn test_pool_acquire() {
629 crate::init().unwrap();
630 let pool = TestBufferPool::default();
631 let mut config = pool.config();
632 config.set_params(None, 1024, 1, 1);
633 pool.set_config(config).expect("failed to set pool config");
634 pool.set_active(true).expect("failed to activate pool");
635 let buffer = pool
636 .acquire_buffer(None)
637 .expect("failed to acquire buffer from pool");
638 assert_eq!(buffer.size(), 2048);
639 }
640
641 #[test]
642 fn test_pool_free_on_finalize() {
643 crate::init().unwrap();
644 let pool = TestBufferPool::default();
645 let mut config = pool.config();
646 config.set_params(None, 1024, 1, 1);
647 pool.set_config(config).expect("failed to set pool config");
648 pool.set_active(true).expect("failed to activate pool");
649 let mut buffer = pool
650 .acquire_buffer(None)
651 .expect("failed to acquire buffer from pool");
652 let finalized = Arc::new(AtomicBool::new(false));
653 unsafe {
654 ffi::gst_mini_object_weak_ref(
655 buffer.make_mut().upcast_mut().as_mut_ptr(),
656 Some(buffer_finalized),
657 Arc::into_raw(finalized.clone()) as *mut _,
658 )
659 };
660 std::mem::drop(buffer);
662 std::mem::drop(pool);
664 assert!(finalized.load(Ordering::SeqCst));
665 }
666
667 #[test]
668 fn test_pool_free_on_deactivate() {
669 crate::init().unwrap();
670 let pool = TestBufferPool::default();
671 let mut config = pool.config();
672 config.set_params(None, 1024, 1, 1);
673 pool.set_config(config).expect("failed to set pool config");
674 pool.set_active(true).expect("failed to activate pool");
675 let mut buffer = pool
676 .acquire_buffer(None)
677 .expect("failed to acquire buffer from pool");
678 let finalized = Arc::new(AtomicBool::new(false));
679 unsafe {
680 ffi::gst_mini_object_weak_ref(
681 buffer.make_mut().upcast_mut().as_mut_ptr(),
682 Some(buffer_finalized),
683 Arc::into_raw(finalized.clone()) as *mut _,
684 )
685 };
686 std::mem::drop(buffer);
688 pool.set_active(false).expect("failed to de-activate pool");
690 assert!(finalized.load(Ordering::SeqCst));
691 }
692
693 unsafe extern "C" fn buffer_finalized(
694 data: *mut libc::c_void,
695 _mini_object: *mut ffi::GstMiniObject,
696 ) {
697 unsafe {
698 let finalized = Arc::from_raw(data as *const AtomicBool);
699 finalized.store(true, Ordering::SeqCst);
700 }
701 }
702}