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 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 phantom: PhantomData<T>,
77}
78
79unsafe impl<T> Send for GLVideoFrame<T> {}
80unsafe impl<T> Sync for GLVideoFrame<T> {}
81
82impl<T> IsVideoFrame for GLVideoFrame<T> {
83 #[inline]
84 fn as_raw(&self) -> &gst_video::ffi::GstVideoFrame {
85 &self.frame
86 }
87}
88
89impl<T> IsGLVideoFrame for GLVideoFrame<T> {}
90
91impl<T> Debug for GLVideoFrame<T> {
92 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
93 f.debug_struct("GLVideoFrame")
94 .field("flags", &self.flags())
95 .field("id", &self.id())
96 .field("buffer", &self.buffer())
97 .field("info", &self.info())
98 .finish()
99 }
100}
101
102impl<T> GLVideoFrame<T> {
103 #[inline]
104 pub fn into_buffer(self) -> gst::Buffer {
105 unsafe {
106 let mut s = mem::ManuallyDrop::new(self);
107 let buffer = from_glib_none(s.frame.buffer);
108 gst_video::ffi::gst_video_frame_unmap(&mut s.frame);
109 buffer
110 }
111 }
112
113 #[inline]
114 pub unsafe fn from_glib_full(frame: gst_video::ffi::GstVideoFrame) -> Self {
115 Self {
116 frame,
117 phantom: PhantomData,
118 }
119 }
120
121 #[inline]
122 pub fn into_raw(self) -> gst_video::ffi::GstVideoFrame {
123 let s = mem::ManuallyDrop::new(self);
124 s.frame
125 }
126
127 #[inline]
128 pub fn as_video_frame_gl_ref(&self) -> GLVideoFrameRef<&gst::BufferRef> {
129 let frame = unsafe { ptr::read(&self.frame) };
130 GLVideoFrameRef {
131 frame,
132 unmap: false,
133 phantom: PhantomData,
134 }
135 }
136}
137
138impl<T> Drop for GLVideoFrame<T> {
139 #[inline]
140 fn drop(&mut self) {
141 unsafe {
142 gst_video::ffi::gst_video_frame_unmap(&mut self.frame);
143 }
144 }
145}
146
147impl GLVideoFrame<Readable> {
148 #[inline]
149 pub fn from_buffer_readable(
150 buffer: gst::Buffer,
151 info: &gst_video::VideoInfo,
152 ) -> Result<Self, gst::Buffer> {
153 skip_assert_initialized!();
154
155 let n_mem = match buffer_n_gl_memory(buffer.as_ref()) {
156 Some(n) => n,
157 None => return Err(buffer),
158 };
159
160 if n_mem != info.n_planes() {
164 return Err(buffer);
165 }
166
167 unsafe {
168 let mut frame = mem::MaybeUninit::uninit();
169 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
170 frame.as_mut_ptr(),
171 info.to_glib_none().0 as *mut _,
172 buffer.to_glib_none().0,
173 gst::ffi::GST_MAP_READ | ffi::GST_MAP_GL as u32,
174 ));
175
176 if !res {
177 Err(buffer)
178 } else {
179 let mut frame = frame.assume_init();
180 frame.info.size = 0;
184 frame.info.stride.fill(0);
185 frame.info.offset.fill(0);
186 Ok(Self {
187 frame,
188 phantom: PhantomData,
189 })
190 }
191 }
192 }
193}
194
195impl GLVideoFrame<Writable> {
196 #[inline]
197 pub fn from_buffer_writable(
198 buffer: gst::Buffer,
199 info: &gst_video::VideoInfo,
200 ) -> Result<Self, gst::Buffer> {
201 skip_assert_initialized!();
202
203 let n_mem = match buffer_n_gl_memory(buffer.as_ref()) {
204 Some(n) => n,
205 None => return Err(buffer),
206 };
207
208 if n_mem != info.n_planes() {
212 return Err(buffer);
213 }
214
215 unsafe {
216 let mut frame = mem::MaybeUninit::uninit();
217 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
218 frame.as_mut_ptr(),
219 info.to_glib_none().0 as *mut _,
220 buffer.to_glib_none().0,
221 gst::ffi::GST_MAP_READ | gst::ffi::GST_MAP_WRITE | ffi::GST_MAP_GL as u32,
222 ));
223
224 if !res {
225 Err(buffer)
226 } else {
227 let mut frame = frame.assume_init();
228 frame.info.size = 0;
232 frame.info.stride.fill(0);
233 frame.info.offset.fill(0);
234 Ok(Self {
235 frame,
236 phantom: PhantomData,
237 })
238 }
239 }
240 }
241
242 #[inline]
243 pub fn memory_mut(&self, idx: u32) -> Result<&mut GLMemoryRef, glib::BoolError> {
244 unsafe { Ok(GLMemoryRef::from_mut_ptr(self.memory(idx)?.as_ptr() as _)) }
245 }
246
247 #[inline]
248 pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
249 unsafe { gst::BufferRef::from_mut_ptr(self.frame.buffer) }
250 }
251}
252
253pub struct GLVideoFrameRef<T> {
254 frame: gst_video::ffi::GstVideoFrame,
255 unmap: bool,
256 phantom: PhantomData<T>,
257}
258
259unsafe impl<T> Send for GLVideoFrameRef<T> {}
260unsafe impl<T> Sync for GLVideoFrameRef<T> {}
261
262impl<T> IsVideoFrame for GLVideoFrameRef<T> {
263 #[inline]
264 fn as_raw(&self) -> &gst_video::ffi::GstVideoFrame {
265 &self.frame
266 }
267}
268
269impl<T> IsGLVideoFrame for GLVideoFrameRef<T> {}
270
271impl<T> Debug for GLVideoFrameRef<T> {
272 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
273 f.debug_struct("GLVideoFrameRef")
274 .field("flags", &self.flags())
275 .field("id", &self.id())
276 .field("buffer", &unsafe {
277 gst::BufferRef::from_ptr(self.frame.buffer)
278 })
279 .field("info", &self.info())
280 .finish()
281 }
282}
283
284impl<'a> GLVideoFrameRef<&'a gst::BufferRef> {
285 #[inline]
286 pub unsafe fn from_glib_borrow(frame: *const gst_video::ffi::GstVideoFrame) -> Borrowed<Self> {
287 debug_assert!(!frame.is_null());
288
289 let frame = ptr::read(frame);
290 Borrowed::new(Self {
291 frame,
292 unmap: false,
293 phantom: PhantomData,
294 })
295 }
296
297 #[inline]
298 pub unsafe fn from_glib_full(frame: gst_video::ffi::GstVideoFrame) -> Self {
299 Self {
300 frame,
301 unmap: true,
302 phantom: PhantomData,
303 }
304 }
305
306 #[inline]
307 pub fn from_buffer_ref_readable<'b>(
308 buffer: &'a gst::BufferRef,
309 info: &'b gst_video::VideoInfo,
310 ) -> Result<GLVideoFrameRef<&'a gst::BufferRef>, glib::error::BoolError> {
311 skip_assert_initialized!();
312
313 let n_mem = match buffer_n_gl_memory(buffer) {
314 Some(n) => n,
315 None => return Err(glib::bool_error!("Memory is not a GstGLMemory")),
316 };
317
318 if n_mem != info.n_planes() {
322 return Err(glib::bool_error!(
323 "Number of planes and memories is not matching"
324 ));
325 }
326
327 unsafe {
328 let mut frame = mem::MaybeUninit::uninit();
329 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
330 frame.as_mut_ptr(),
331 info.to_glib_none().0 as *mut _,
332 buffer.as_mut_ptr(),
333 gst_video::ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
334 | gst::ffi::GST_MAP_READ
335 | ffi::GST_MAP_GL as u32,
336 ));
337
338 if !res {
339 Err(glib::bool_error!(
340 "Failed to fill in the values of GstVideoFrame"
341 ))
342 } else {
343 let mut frame = frame.assume_init();
344 frame.info.size = 0;
348 frame.info.stride.fill(0);
349 frame.info.offset.fill(0);
350 Ok(Self {
351 frame,
352 unmap: true,
353 phantom: PhantomData,
354 })
355 }
356 }
357 }
358}
359
360impl<'a> GLVideoFrameRef<&'a mut gst::BufferRef> {
361 #[inline]
362 pub unsafe fn from_glib_borrow_mut(frame: *mut gst_video::ffi::GstVideoFrame) -> Self {
363 debug_assert!(!frame.is_null());
364
365 let frame = ptr::read(frame);
366 Self {
367 frame,
368 unmap: false,
369 phantom: PhantomData,
370 }
371 }
372
373 #[inline]
374 pub unsafe fn from_glib_full_mut(frame: gst_video::ffi::GstVideoFrame) -> Self {
375 Self {
376 frame,
377 unmap: true,
378 phantom: PhantomData,
379 }
380 }
381
382 #[inline]
383 pub fn from_buffer_ref_writable<'b>(
384 buffer: &'a mut gst::BufferRef,
385 info: &'b gst_video::VideoInfo,
386 ) -> Result<GLVideoFrameRef<&'a mut gst::BufferRef>, glib::error::BoolError> {
387 skip_assert_initialized!();
388
389 let n_mem = match buffer_n_gl_memory(buffer) {
390 Some(n) => n,
391 None => return Err(glib::bool_error!("Memory is not a GstGLMemory")),
392 };
393
394 if n_mem != info.n_planes() {
398 return Err(glib::bool_error!(
399 "Number of planes and memories is not matching"
400 ));
401 }
402
403 unsafe {
404 let mut frame = mem::MaybeUninit::uninit();
405 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
406 frame.as_mut_ptr(),
407 info.to_glib_none().0 as *mut _,
408 buffer.as_mut_ptr(),
409 gst_video::ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
410 | gst::ffi::GST_MAP_READ
411 | gst::ffi::GST_MAP_WRITE
412 | ffi::GST_MAP_GL as u32,
413 ));
414
415 if !res {
416 Err(glib::bool_error!(
417 "Failed to fill in the values of GstVideoFrame"
418 ))
419 } else {
420 let mut frame = frame.assume_init();
421 frame.info.size = 0;
425 frame.info.stride.fill(0);
426 frame.info.offset.fill(0);
427 Ok(Self {
428 frame,
429 unmap: true,
430 phantom: PhantomData,
431 })
432 }
433 }
434 }
435
436 #[inline]
437 pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
438 unsafe { gst::BufferRef::from_mut_ptr(self.frame.buffer) }
439 }
440
441 #[inline]
442 pub fn as_mut_ptr(&mut self) -> *mut gst_video::ffi::GstVideoFrame {
443 &mut self.frame
444 }
445
446 #[inline]
447 pub fn memory_mut(&self, idx: u32) -> Result<&mut GLMemoryRef, glib::BoolError> {
448 unsafe { Ok(GLMemoryRef::from_mut_ptr(self.memory(idx)?.as_ptr() as _)) }
449 }
450}
451
452impl<'a> std::ops::Deref for GLVideoFrameRef<&'a mut gst::BufferRef> {
453 type Target = GLVideoFrameRef<&'a gst::BufferRef>;
454
455 #[inline]
456 fn deref(&self) -> &Self::Target {
457 unsafe { &*(self as *const Self as *const Self::Target) }
458 }
459}
460
461impl<T> Drop for GLVideoFrameRef<T> {
462 #[inline]
463 fn drop(&mut self) {
464 unsafe {
465 if self.unmap {
466 gst_video::ffi::gst_video_frame_unmap(&mut self.frame);
467 }
468 }
469 }
470}
471
472fn buffer_n_gl_memory(buffer: &gst::BufferRef) -> Option<u32> {
473 skip_assert_initialized!();
474 unsafe {
475 let buf = buffer.as_mut_ptr();
476 let num = gst::ffi::gst_buffer_n_memory(buf);
477 for i in 0..num - 1 {
478 let mem = gst::ffi::gst_buffer_peek_memory(buf, i);
479 if ffi::gst_is_gl_memory(mem) != glib::ffi::GTRUE {
480 return None;
481 }
482 }
483 Some(num)
484 }
485}