gstreamer/
memory_wrapped.rs
1use glib::{prelude::*, translate::*};
4
5use std::{alloc, mem, ptr};
6
7use crate::{ffi, Memory};
8
9#[repr(C)]
10struct WrappedMemory<T> {
11 mem: ffi::GstMemory,
12
13 data: *mut u8,
15
16 layout: alloc::Layout,
18
19 wrap_offset: usize,
21 wrap_drop_in_place: unsafe fn(*mut T),
23 wrap: T,
24}
25
26unsafe extern "C" fn free(_allocator: *mut ffi::GstAllocator, mem: *mut ffi::GstMemory) {
27 let mem = mem as *mut WrappedMemory<()>;
28
29 if (*mem).wrap_offset > 0 {
30 let wrap = (mem as *mut u8).add((*mem).wrap_offset) as *mut ();
31 ((*mem).wrap_drop_in_place)(wrap);
32 }
33
34 alloc::dealloc(mem as *mut u8, (*mem).layout);
35}
36
37unsafe extern "C" fn mem_map(
38 mem: *mut ffi::GstMemory,
39 _maxsize: usize,
40 _flags: ffi::GstMapFlags,
41) -> glib::ffi::gpointer {
42 let mem = mem as *mut WrappedMemory<()>;
43
44 (*mem).data as glib::ffi::gpointer
45}
46
47unsafe extern "C" fn mem_unmap(_mem: *mut ffi::GstMemory) {}
48
49unsafe extern "C" fn mem_share(
50 mem: *mut ffi::GstMemory,
51 offset: isize,
52 size: isize,
53) -> *mut ffi::GstMemory {
54 let mem = mem as *mut WrappedMemory<()>;
55
56 let parent = if (*mem).mem.parent.is_null() {
59 mem
60 } else {
61 (*mem).mem.parent as *mut WrappedMemory<()>
62 };
63
64 let offset = offset as usize;
67 let mut size = size as usize;
68
69 let new_offset = (*mem).mem.offset.wrapping_add(offset);
70 debug_assert!(new_offset < (*mem).mem.maxsize);
71
72 if size == usize::MAX {
73 size = (*mem).mem.size.wrapping_sub(offset);
74 }
75 debug_assert!(new_offset <= usize::MAX - size);
76 debug_assert!(new_offset + size <= (*mem).mem.maxsize);
77
78 let layout = alloc::Layout::new::<WrappedMemory<()>>();
79 let sub = alloc::alloc(layout) as *mut WrappedMemory<()>;
80
81 ffi::gst_memory_init(
82 sub as *mut ffi::GstMemory,
83 (*mem).mem.mini_object.flags | ffi::GST_MINI_OBJECT_FLAG_LOCK_READONLY,
84 (*mem).mem.allocator,
85 parent as *mut ffi::GstMemory,
86 (*mem).mem.maxsize,
87 (*mem).mem.align,
88 new_offset,
89 size,
90 );
91 ptr::write(ptr::addr_of_mut!((*sub).data), (*mem).data);
92 ptr::write(ptr::addr_of_mut!((*sub).layout), layout);
93 ptr::write(ptr::addr_of_mut!((*sub).wrap_offset), 0);
94 ptr::write(ptr::addr_of_mut!((*sub).wrap_drop_in_place), |_| ());
95
96 sub as *mut ffi::GstMemory
97}
98
99unsafe extern "C" fn mem_is_span(
100 mem1: *mut ffi::GstMemory,
101 mem2: *mut ffi::GstMemory,
102 offset: *mut usize,
103) -> glib::ffi::gboolean {
104 let mem1 = mem1 as *mut WrappedMemory<()>;
105 let mem2 = mem2 as *mut WrappedMemory<()>;
106
107 if !offset.is_null() {
109 let parent = (*mem1).mem.parent as *mut WrappedMemory<()>;
110 *offset = (*mem1).mem.offset - (*parent).mem.offset;
111 }
112
113 let is_span = (*mem1).data.add((*mem1).mem.offset).add((*mem1).mem.size)
114 == (*mem2).data.add((*mem2).mem.offset);
115
116 is_span.into_glib()
117}
118
119unsafe extern "C" fn class_init(class: glib::ffi::gpointer, _class_data: glib::ffi::gpointer) {
120 let class = class as *mut ffi::GstAllocatorClass;
121
122 (*class).free = Some(free);
123}
124
125unsafe extern "C" fn instance_init(
126 obj: *mut glib::gobject_ffi::GTypeInstance,
127 _class: glib::ffi::gpointer,
128) {
129 static ALLOCATOR_TYPE: &[u8] = b"RustGlobalAllocatorMemory\0";
130
131 let allocator = obj as *mut ffi::GstAllocator;
132
133 (*allocator).mem_type = ALLOCATOR_TYPE.as_ptr() as *const _;
134 (*allocator).mem_map = Some(mem_map);
135 (*allocator).mem_unmap = Some(mem_unmap);
136 (*allocator).mem_share = Some(mem_share);
138 (*allocator).mem_is_span = Some(mem_is_span);
139
140 (*allocator).object.flags |= ffi::GST_ALLOCATOR_FLAG_CUSTOM_ALLOC;
142}
143
144fn rust_allocator() -> &'static crate::Allocator {
145 static RUST_ALLOCATOR: std::sync::OnceLock<crate::Allocator> = std::sync::OnceLock::new();
146
147 RUST_ALLOCATOR.get_or_init(|| unsafe {
148 struct TypeInfoWrap(glib::gobject_ffi::GTypeInfo);
149 unsafe impl Send for TypeInfoWrap {}
150 unsafe impl Sync for TypeInfoWrap {}
151
152 static TYPE_INFO: TypeInfoWrap = TypeInfoWrap(glib::gobject_ffi::GTypeInfo {
153 class_size: mem::size_of::<ffi::GstAllocatorClass>() as u16,
154 base_init: None,
155 base_finalize: None,
156 class_init: Some(class_init),
157 class_finalize: None,
158 class_data: ptr::null_mut(),
159 instance_size: mem::size_of::<ffi::GstAllocator>() as u16,
160 n_preallocs: 0,
161 instance_init: Some(instance_init),
162 value_table: ptr::null(),
163 });
164
165 let type_name = {
166 let mut idx = 0;
167
168 loop {
169 let type_name = glib::gformat!("GstRsAllocator-{}", idx);
170 if glib::gobject_ffi::g_type_from_name(type_name.as_ptr())
171 == glib::gobject_ffi::G_TYPE_INVALID
172 {
173 break type_name;
174 }
175 idx += 1;
176 }
177 };
178
179 let t = glib::gobject_ffi::g_type_register_static(
180 crate::Allocator::static_type().into_glib(),
181 type_name.as_ptr(),
182 &TYPE_INFO.0,
183 0,
184 );
185
186 assert!(t != glib::gobject_ffi::G_TYPE_INVALID);
187
188 from_glib_none(
189 glib::gobject_ffi::g_object_newv(t, 0, ptr::null_mut()) as *mut ffi::GstAllocator
190 )
191 })
192}
193
194impl Memory {
195 #[doc(alias = "gst_memory_new_wrapped")]
196 #[doc(alias = "gst_memory_new_wrapped_full")]
197 #[inline]
198 pub fn from_slice<T: AsRef<[u8]> + Send + 'static>(slice: T) -> Self {
199 assert_initialized_main_thread!();
200
201 let len = slice.as_ref().len();
202 unsafe {
203 let layout = alloc::Layout::new::<WrappedMemory<T>>();
204 let mem = alloc::alloc(layout) as *mut WrappedMemory<T>;
205
206 ffi::gst_memory_init(
207 mem as *mut ffi::GstMemory,
208 ffi::GST_MINI_OBJECT_FLAG_LOCK_READONLY,
209 rust_allocator().to_glib_none().0,
210 ptr::null_mut(),
211 len,
212 0,
213 0,
214 len,
215 );
216
217 ptr::write(ptr::addr_of_mut!((*mem).wrap), slice);
218
219 assert_eq!(len, (*mem).wrap.as_ref().len());
220 let data = (*mem).wrap.as_ref().as_ptr();
221 ptr::write(ptr::addr_of_mut!((*mem).data), mut_override(data));
222
223 ptr::write(ptr::addr_of_mut!((*mem).layout), layout);
224
225 let wrap_offset = ptr::addr_of!((*mem).wrap) as usize - mem as usize;
226 ptr::write(ptr::addr_of_mut!((*mem).wrap_offset), wrap_offset);
227
228 ptr::write(
229 ptr::addr_of_mut!((*mem).wrap_drop_in_place),
230 ptr::drop_in_place::<T>,
231 );
232
233 from_glib_full(mem as *mut ffi::GstMemory)
234 }
235 }
236
237 #[doc(alias = "gst_memory_new_wrapped")]
238 #[doc(alias = "gst_memory_new_wrapped_full")]
239 #[inline]
240 pub fn from_mut_slice<T: AsMut<[u8]> + Send + 'static>(mut slice: T) -> Self {
241 assert_initialized_main_thread!();
242
243 let len = slice.as_mut().len();
244 unsafe {
245 let layout = alloc::Layout::new::<WrappedMemory<T>>();
246 let mem = alloc::alloc(layout) as *mut WrappedMemory<T>;
247
248 ffi::gst_memory_init(
249 mem as *mut ffi::GstMemory,
250 0,
251 rust_allocator().to_glib_none().0,
252 ptr::null_mut(),
253 len,
254 0,
255 0,
256 len,
257 );
258
259 ptr::write(ptr::addr_of_mut!((*mem).wrap), slice);
260
261 assert_eq!(len, (*mem).wrap.as_mut().len());
262 let data = (*mem).wrap.as_mut().as_mut_ptr();
263 ptr::write(ptr::addr_of_mut!((*mem).data), data);
264
265 ptr::write(ptr::addr_of_mut!((*mem).layout), layout);
266
267 let wrap_offset = ptr::addr_of!((*mem).wrap) as usize - mem as usize;
268 ptr::write(ptr::addr_of_mut!((*mem).wrap_offset), wrap_offset);
269
270 ptr::write(
271 ptr::addr_of_mut!((*mem).wrap_drop_in_place),
272 ptr::drop_in_place::<T>,
273 );
274
275 from_glib_full(mem as *mut ffi::GstMemory)
276 }
277 }
278}