From f1c88694479448c9f6f99faecb3039c14baff542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elie=20G=C3=A9nard?= Date: Tue, 8 Nov 2022 19:28:42 +0000 Subject: [PATCH] gstreamer: Add `gst::Allocator` subclassing support --- gstreamer/src/allocation_params.rs | 7 +- gstreamer/src/subclass/allocator.rs | 187 ++++++++++++++++++++++++++++ gstreamer/src/subclass/mod.rs | 2 + 3 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 gstreamer/src/subclass/allocator.rs diff --git a/gstreamer/src/allocation_params.rs b/gstreamer/src/allocation_params.rs index 256c23f87..2be8a3398 100644 --- a/gstreamer/src/allocation_params.rs +++ b/gstreamer/src/allocation_params.rs @@ -8,6 +8,7 @@ use crate::MemoryFlags; #[derive(Debug, Clone)] #[doc(alias = "GstAllocationParams")] +#[repr(transparent)] pub struct AllocationParams(ffi::GstAllocationParams); unsafe impl Send for AllocationParams {} @@ -36,7 +37,7 @@ impl AllocationParams { pub fn new(flags: MemoryFlags, align: usize, prefix: usize, padding: usize) -> Self { assert_initialized_main_thread!(); - let allocationparams = unsafe { + let params = unsafe { ffi::GstAllocationParams { flags: flags.into_glib(), align, @@ -46,7 +47,7 @@ impl AllocationParams { } }; - AllocationParams(allocationparams) + params.into() } pub fn as_ptr(&self) -> *const ffi::GstAllocationParams { @@ -74,6 +75,6 @@ impl FromGlib for AllocationParams { #[allow(unused_unsafe)] unsafe fn from_glib(value: ffi::GstAllocationParams) -> Self { assert_initialized_main_thread!(); - AllocationParams(value) + Self::from(value) } } diff --git a/gstreamer/src/subclass/allocator.rs b/gstreamer/src/subclass/allocator.rs new file mode 100644 index 000000000..c7671e26a --- /dev/null +++ b/gstreamer/src/subclass/allocator.rs @@ -0,0 +1,187 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use super::prelude::*; +use crate::{AllocationParams, Allocator, Memory}; +use glib::{bool_error, prelude::*, subclass::prelude::*, translate::*, BoolError}; +use std::ptr; + +pub trait AllocatorImpl: AllocatorImplExt + GstObjectImpl + Send + Sync { + fn alloc(&self, size: usize, params: Option<&AllocationParams>) -> Result { + self.parent_alloc(size, params) + } + + fn free(&self, memory: Memory) { + self.parent_free(memory) + } +} + +pub trait AllocatorImplExt: ObjectSubclass { + fn parent_alloc( + &self, + size: usize, + params: Option<&AllocationParams>, + ) -> Result; + + fn parent_free(&self, memory: Memory); +} + +impl AllocatorImplExt for T { + fn parent_alloc( + &self, + size: usize, + params: Option<&AllocationParams>, + ) -> Result { + unsafe { + let data = Self::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GstAllocatorClass; + + if let Some(f) = (*parent_class).alloc { + from_glib_full::<*mut ffi::GstMemory, Option<_>>(f( + self.instance() + .unsafe_cast_ref::() + .to_glib_none() + .0, + size, + mut_override(params.to_glib_none().0), + )) + .ok_or_else(|| bool_error!("Allocation failed")) + } else { + Err(bool_error!("No allocation method on parent class")) + } + } + } + + fn parent_free(&self, memory: Memory) { + unsafe { + let data = Self::type_data(); + let parent_class = data.as_ref().parent_class() as *mut ffi::GstAllocatorClass; + + if let Some(f) = (*parent_class).free { + f( + self.instance() + .unsafe_cast_ref::() + .to_glib_none() + .0, + memory.into_glib_ptr(), + ) + } + } + } +} + +unsafe impl IsSubclassable for Allocator { + fn class_init(klass: &mut glib::Class) { + Self::parent_class_init::(klass); + let klass = klass.as_mut(); + klass.alloc = Some(alloc::); + klass.free = Some(free::); + } +} + +unsafe extern "C" fn alloc( + ptr: *mut ffi::GstAllocator, + size: usize, + params: *mut ffi::GstAllocationParams, +) -> *mut ffi::GstMemory { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + let instance = imp.obj(); + + let params = if params.is_null() { + None + } else { + Some(&*(params as *mut AllocationParams)) + }; + + imp.alloc(size, params) + .map(|memory| memory.into_glib_ptr()) + .unwrap_or_else(|error| { + error!(crate::CAT_RUST, obj: instance, "{:?}", error); + + ptr::null_mut() + }) +} + +unsafe extern "C" fn free( + ptr: *mut ffi::GstAllocator, + memory: *mut ffi::GstMemory, +) { + let instance = &*(ptr as *mut T::Instance); + let imp = instance.imp(); + let memory = from_glib_full(memory); + + imp.free(memory); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::prelude::*; + + pub mod imp { + use super::*; + + #[derive(Default)] + pub struct TestAllocator; + + impl ObjectImpl for TestAllocator {} + impl GstObjectImpl for TestAllocator {} + impl AllocatorImpl for TestAllocator { + fn alloc( + &self, + size: usize, + _params: Option<&AllocationParams>, + ) -> Result { + Ok(Memory::from_slice(vec![0; size])) + } + + fn free(&self, memory: Memory) { + self.parent_free(memory) + } + } + + #[glib::object_subclass] + impl ObjectSubclass for TestAllocator { + const NAME: &'static str = "TestAllocator"; + type Type = super::TestAllocator; + type ParentType = Allocator; + } + } + + glib::wrapper! { + pub struct TestAllocator(ObjectSubclass) @extends Allocator, crate::Object; + } + + impl Default for TestAllocator { + fn default() -> Self { + glib::Object::new(&[]) + } + } + + #[test] + fn test_allocator_registration() { + crate::init().unwrap(); + + const TEST_ALLOCATOR_NAME: &str = "TestAllocator"; + + let allocator = TestAllocator::default(); + Allocator::register(TEST_ALLOCATOR_NAME, &allocator); + + let allocator = Allocator::find(Some(TEST_ALLOCATOR_NAME)); + + assert!(allocator.is_some()); + } + + #[test] + fn test_allocator_alloc() { + crate::init().unwrap(); + + const SIZE: usize = 1024; + + let allocator = TestAllocator::default(); + + let memory = allocator.alloc(SIZE, None).unwrap(); + + assert_eq!(memory.size(), SIZE); + } +} diff --git a/gstreamer/src/subclass/mod.rs b/gstreamer/src/subclass/mod.rs index c441ca443..6b6561a08 100644 --- a/gstreamer/src/subclass/mod.rs +++ b/gstreamer/src/subclass/mod.rs @@ -8,6 +8,7 @@ mod error; #[macro_use] mod plugin; +mod allocator; mod bin; mod buffer_pool; mod child_proxy; @@ -42,6 +43,7 @@ pub mod prelude { #[doc(hidden)] pub use glib::subclass::prelude::*; + pub use super::allocator::{AllocatorImpl, AllocatorImplExt}; pub use super::bin::{BinImpl, BinImplExt}; pub use super::buffer_pool::{BufferPoolImpl, BufferPoolImplExt}; pub use super::child_proxy::{ChildProxyImpl, ChildProxyImplExt};