1use std::{fmt::Debug, marker::PhantomData, mem, ptr};
4
5use crate::{ffi, GLMemoryRef};
6use glib::translate::*;
7use gst_video::{video_frame::IsVideoFrame, VideoFrameExt};
8
9pub enum Readable {}
10pub enum Writable {}
11
12pub unsafe trait IsGLVideoFrame: IsVideoFrame {}
16
17pub trait GLVideoFrameExt: IsGLVideoFrame + VideoFrameExt {
18 #[inline]
19 fn memory(&self, idx: u32) -> Result<&GLMemoryRef, glib::BoolError> {
20 if idx >= self.info().n_planes() {
21 return Err(glib::bool_error!(
22 "Memory index higher than number of memories"
23 ));
24 }
25
26 unsafe {
27 let ptr = self.as_raw().map[idx as usize].memory;
28 if ffi::gst_is_gl_memory(ptr) == glib::ffi::GTRUE {
29 Ok(GLMemoryRef::from_ptr(ptr as _))
30 } else {
31 Err(glib::bool_error!("Memory is not a GLMemory"))
32 }
33 }
34 }
35
36 #[inline]
37 #[doc(alias = "get_texture_id")]
38 fn texture_id(&self, idx: u32) -> Result<u32, glib::BoolError> {
39 Ok(self.memory(idx)?.texture_id())
40 }
41
42 #[inline]
43 #[doc(alias = "get_texture_format")]
44 fn texture_format(&self, idx: u32) -> Result<crate::GLFormat, glib::BoolError> {
45 Ok(self.memory(idx)?.texture_format())
46 }
47
48 #[inline]
49 #[doc(alias = "get_texture_height")]
50 fn texture_height(&self, idx: u32) -> Result<i32, glib::BoolError> {
51 Ok(self.memory(idx)?.texture_height())
52 }
53
54 #[inline]
55 #[doc(alias = "get_texture_target")]
56 fn texture_target(&self, idx: u32) -> Result<crate::GLTextureTarget, glib::BoolError> {
57 Ok(self.memory(idx)?.texture_target())
58 }
59
60 #[inline]
61 #[doc(alias = "get_texture_width")]
62 fn texture_width(&self, idx: u32) -> Result<i32, glib::BoolError> {
63 Ok(self.memory(idx)?.texture_width())
64 }
65}
66
67impl<O: IsGLVideoFrame> GLVideoFrameExt for O {}
68
69pub struct GLVideoFrame<T> {
70 frame: gst_video::ffi::GstVideoFrame,
71 phantom: PhantomData<T>,
72}
73
74unsafe impl<T> Send for GLVideoFrame<T> {}
75unsafe impl<T> Sync for GLVideoFrame<T> {}
76
77unsafe impl<T> IsVideoFrame for GLVideoFrame<T> {
78 #[inline]
79 fn as_raw(&self) -> &gst_video::ffi::GstVideoFrame {
80 &self.frame
81 }
82}
83
84unsafe impl<T> IsGLVideoFrame for GLVideoFrame<T> {}
85
86impl<T> Debug for GLVideoFrame<T> {
87 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
88 f.debug_struct("GLVideoFrame")
89 .field("flags", &self.flags())
90 .field("id", &self.id())
91 .field("buffer", &self.buffer())
92 .field("info", &self.info())
93 .finish()
94 }
95}
96
97impl<T> GLVideoFrame<T> {
98 #[inline]
99 pub fn into_buffer(self) -> gst::Buffer {
100 unsafe {
101 let mut s = mem::ManuallyDrop::new(self);
102 let buffer = from_glib_none(s.frame.buffer);
103 gst_video::ffi::gst_video_frame_unmap(&mut s.frame);
104 buffer
105 }
106 }
107
108 #[inline]
109 pub unsafe fn from_glib_full(frame: gst_video::ffi::GstVideoFrame) -> Self {
110 Self {
111 frame,
112 phantom: PhantomData,
113 }
114 }
115
116 #[inline]
117 pub fn into_raw(self) -> gst_video::ffi::GstVideoFrame {
118 let s = mem::ManuallyDrop::new(self);
119 s.frame
120 }
121
122 #[inline]
123 pub fn as_video_frame_gl_ref(&self) -> GLVideoFrameRef<&gst::BufferRef> {
124 let frame = unsafe { ptr::read(&self.frame) };
125 GLVideoFrameRef {
126 frame,
127 unmap: false,
128 phantom: PhantomData,
129 }
130 }
131}
132
133impl<T> Drop for GLVideoFrame<T> {
134 #[inline]
135 fn drop(&mut self) {
136 unsafe {
137 gst_video::ffi::gst_video_frame_unmap(&mut self.frame);
138 }
139 }
140}
141
142impl GLVideoFrame<Readable> {
143 #[inline]
144 pub fn from_buffer_readable(
145 buffer: gst::Buffer,
146 info: &gst_video::VideoInfo,
147 ) -> Result<Self, gst::Buffer> {
148 skip_assert_initialized!();
149
150 let n_mem = match buffer_n_gl_memory(buffer.as_ref()) {
151 Some(n) => n,
152 None => return Err(buffer),
153 };
154
155 if n_mem != info.n_planes() {
159 return Err(buffer);
160 }
161
162 unsafe {
163 let mut frame = mem::MaybeUninit::uninit();
164 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
165 frame.as_mut_ptr(),
166 info.to_glib_none().0 as *mut _,
167 buffer.to_glib_none().0,
168 gst::ffi::GST_MAP_READ | ffi::GST_MAP_GL as u32,
169 ));
170
171 if !res {
172 Err(buffer)
173 } else {
174 let mut frame = frame.assume_init();
175 frame.info.size = 0;
179 frame.info.stride.fill(0);
180 frame.info.offset.fill(0);
181 Ok(Self {
182 frame,
183 phantom: PhantomData,
184 })
185 }
186 }
187 }
188}
189
190impl GLVideoFrame<Writable> {
191 #[inline]
192 pub fn from_buffer_writable(
193 buffer: gst::Buffer,
194 info: &gst_video::VideoInfo,
195 ) -> Result<Self, gst::Buffer> {
196 skip_assert_initialized!();
197
198 let n_mem = match buffer_n_gl_memory(buffer.as_ref()) {
199 Some(n) => n,
200 None => return Err(buffer),
201 };
202
203 if n_mem != info.n_planes() {
207 return Err(buffer);
208 }
209
210 unsafe {
211 let mut frame = mem::MaybeUninit::uninit();
212 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
213 frame.as_mut_ptr(),
214 info.to_glib_none().0 as *mut _,
215 buffer.to_glib_none().0,
216 gst::ffi::GST_MAP_READ | gst::ffi::GST_MAP_WRITE | ffi::GST_MAP_GL as u32,
217 ));
218
219 if !res {
220 Err(buffer)
221 } else {
222 let mut frame = frame.assume_init();
223 frame.info.size = 0;
227 frame.info.stride.fill(0);
228 frame.info.offset.fill(0);
229 Ok(Self {
230 frame,
231 phantom: PhantomData,
232 })
233 }
234 }
235 }
236
237 #[inline]
238 pub fn memory_mut(&mut self, idx: u32) -> Result<&mut GLMemoryRef, glib::BoolError> {
239 unsafe { Ok(GLMemoryRef::from_mut_ptr(self.memory(idx)?.as_ptr() as _)) }
240 }
241
242 #[inline]
243 pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
244 unsafe { gst::BufferRef::from_mut_ptr(self.frame.buffer) }
245 }
246}
247
248pub struct GLVideoFrameRef<T> {
249 frame: gst_video::ffi::GstVideoFrame,
250 unmap: bool,
251 phantom: PhantomData<T>,
252}
253
254unsafe impl<T> Send for GLVideoFrameRef<T> {}
255unsafe impl<T> Sync for GLVideoFrameRef<T> {}
256
257unsafe impl<T> IsVideoFrame for GLVideoFrameRef<T> {
258 #[inline]
259 fn as_raw(&self) -> &gst_video::ffi::GstVideoFrame {
260 &self.frame
261 }
262}
263
264unsafe impl<T> IsGLVideoFrame for GLVideoFrameRef<T> {}
265
266impl<T> Debug for GLVideoFrameRef<T> {
267 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
268 f.debug_struct("GLVideoFrameRef")
269 .field("flags", &self.flags())
270 .field("id", &self.id())
271 .field("buffer", &unsafe {
272 gst::BufferRef::from_ptr(self.frame.buffer)
273 })
274 .field("info", &self.info())
275 .finish()
276 }
277}
278
279impl<'a> GLVideoFrameRef<&'a gst::BufferRef> {
280 #[inline]
281 pub unsafe fn from_glib_borrow(frame: *const gst_video::ffi::GstVideoFrame) -> Borrowed<Self> {
282 debug_assert!(!frame.is_null());
283
284 let frame = ptr::read(frame);
285 Borrowed::new(Self {
286 frame,
287 unmap: false,
288 phantom: PhantomData,
289 })
290 }
291
292 #[inline]
293 pub unsafe fn from_glib_full(frame: gst_video::ffi::GstVideoFrame) -> Self {
294 Self {
295 frame,
296 unmap: true,
297 phantom: PhantomData,
298 }
299 }
300
301 #[inline]
302 pub fn from_buffer_ref_readable<'b>(
303 buffer: &'a gst::BufferRef,
304 info: &'b gst_video::VideoInfo,
305 ) -> Result<GLVideoFrameRef<&'a gst::BufferRef>, glib::error::BoolError> {
306 skip_assert_initialized!();
307
308 let n_mem = match buffer_n_gl_memory(buffer) {
309 Some(n) => n,
310 None => return Err(glib::bool_error!("Memory is not a GstGLMemory")),
311 };
312
313 if n_mem != info.n_planes() {
317 return Err(glib::bool_error!(
318 "Number of planes and memories is not matching"
319 ));
320 }
321
322 unsafe {
323 let mut frame = mem::MaybeUninit::uninit();
324 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
325 frame.as_mut_ptr(),
326 info.to_glib_none().0 as *mut _,
327 buffer.as_mut_ptr(),
328 gst_video::ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
329 | gst::ffi::GST_MAP_READ
330 | ffi::GST_MAP_GL as u32,
331 ));
332
333 if !res {
334 Err(glib::bool_error!(
335 "Failed to fill in the values of GstVideoFrame"
336 ))
337 } else {
338 let mut frame = frame.assume_init();
339 frame.info.size = 0;
343 frame.info.stride.fill(0);
344 frame.info.offset.fill(0);
345 Ok(Self {
346 frame,
347 unmap: true,
348 phantom: PhantomData,
349 })
350 }
351 }
352 }
353}
354
355impl<'a> GLVideoFrameRef<&'a mut gst::BufferRef> {
356 #[inline]
357 pub unsafe fn from_glib_borrow_mut(frame: *mut gst_video::ffi::GstVideoFrame) -> Self {
358 debug_assert!(!frame.is_null());
359
360 let frame = ptr::read(frame);
361 Self {
362 frame,
363 unmap: false,
364 phantom: PhantomData,
365 }
366 }
367
368 #[inline]
369 pub unsafe fn from_glib_full_mut(frame: gst_video::ffi::GstVideoFrame) -> Self {
370 Self {
371 frame,
372 unmap: true,
373 phantom: PhantomData,
374 }
375 }
376
377 #[inline]
378 pub fn from_buffer_ref_writable<'b>(
379 buffer: &'a mut gst::BufferRef,
380 info: &'b gst_video::VideoInfo,
381 ) -> Result<GLVideoFrameRef<&'a mut gst::BufferRef>, glib::error::BoolError> {
382 skip_assert_initialized!();
383
384 let n_mem = match buffer_n_gl_memory(buffer) {
385 Some(n) => n,
386 None => return Err(glib::bool_error!("Memory is not a GstGLMemory")),
387 };
388
389 if n_mem != info.n_planes() {
393 return Err(glib::bool_error!(
394 "Number of planes and memories is not matching"
395 ));
396 }
397
398 unsafe {
399 let mut frame = mem::MaybeUninit::uninit();
400 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
401 frame.as_mut_ptr(),
402 info.to_glib_none().0 as *mut _,
403 buffer.as_mut_ptr(),
404 gst_video::ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
405 | gst::ffi::GST_MAP_READ
406 | gst::ffi::GST_MAP_WRITE
407 | ffi::GST_MAP_GL as u32,
408 ));
409
410 if !res {
411 Err(glib::bool_error!(
412 "Failed to fill in the values of GstVideoFrame"
413 ))
414 } else {
415 let mut frame = frame.assume_init();
416 frame.info.size = 0;
420 frame.info.stride.fill(0);
421 frame.info.offset.fill(0);
422 Ok(Self {
423 frame,
424 unmap: true,
425 phantom: PhantomData,
426 })
427 }
428 }
429 }
430
431 #[inline]
432 pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
433 unsafe { gst::BufferRef::from_mut_ptr(self.frame.buffer) }
434 }
435
436 #[inline]
437 pub fn as_mut_ptr(&mut self) -> *mut gst_video::ffi::GstVideoFrame {
438 &mut self.frame
439 }
440
441 #[inline]
442 pub fn memory_mut(&mut self, idx: u32) -> Result<&mut GLMemoryRef, glib::BoolError> {
443 unsafe { Ok(GLMemoryRef::from_mut_ptr(self.memory(idx)?.as_ptr() as _)) }
444 }
445}
446
447impl<'a> std::ops::Deref for GLVideoFrameRef<&'a mut gst::BufferRef> {
448 type Target = GLVideoFrameRef<&'a gst::BufferRef>;
449
450 #[inline]
451 fn deref(&self) -> &Self::Target {
452 unsafe { &*(self as *const Self as *const Self::Target) }
453 }
454}
455
456impl<T> Drop for GLVideoFrameRef<T> {
457 #[inline]
458 fn drop(&mut self) {
459 unsafe {
460 if self.unmap {
461 gst_video::ffi::gst_video_frame_unmap(&mut self.frame);
462 }
463 }
464 }
465}
466
467fn buffer_n_gl_memory(buffer: &gst::BufferRef) -> Option<u32> {
468 skip_assert_initialized!();
469 unsafe {
470 let buf = buffer.as_mut_ptr();
471 let num = gst::ffi::gst_buffer_n_memory(buf);
472 for i in 0..num - 1 {
473 let mem = gst::ffi::gst_buffer_peek_memory(buf, i);
474 if ffi::gst_is_gl_memory(mem) != glib::ffi::GTRUE {
475 return None;
476 }
477 }
478 Some(num)
479 }
480}