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