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