1use std::{fmt::Debug, marker::PhantomData, mem, ptr};
4
5use crate::{GLMemoryRef, ffi};
6use glib::translate::*;
7use gst_video::{VideoFrameExt, video_frame::IsVideoFrame};
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 unsafe {
283 debug_assert!(!frame.is_null());
284
285 let frame = ptr::read(frame);
286 Borrowed::new(Self {
287 frame,
288 unmap: false,
289 phantom: PhantomData,
290 })
291 }
292 }
293
294 #[inline]
295 pub unsafe fn from_glib_full(frame: gst_video::ffi::GstVideoFrame) -> Self {
296 Self {
297 frame,
298 unmap: true,
299 phantom: PhantomData,
300 }
301 }
302
303 #[inline]
304 pub fn from_buffer_ref_readable<'b>(
305 buffer: &'a gst::BufferRef,
306 info: &'b gst_video::VideoInfo,
307 ) -> Result<GLVideoFrameRef<&'a gst::BufferRef>, glib::error::BoolError> {
308 skip_assert_initialized!();
309
310 let n_mem = match buffer_n_gl_memory(buffer) {
311 Some(n) => n,
312 None => return Err(glib::bool_error!("Memory is not a GstGLMemory")),
313 };
314
315 if n_mem != info.n_planes() {
319 return Err(glib::bool_error!(
320 "Number of planes and memories is not matching"
321 ));
322 }
323
324 unsafe {
325 let mut frame = mem::MaybeUninit::uninit();
326 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
327 frame.as_mut_ptr(),
328 info.to_glib_none().0 as *mut _,
329 buffer.as_mut_ptr(),
330 gst_video::ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
331 | gst::ffi::GST_MAP_READ
332 | ffi::GST_MAP_GL as u32,
333 ));
334
335 if !res {
336 Err(glib::bool_error!(
337 "Failed to fill in the values of GstVideoFrame"
338 ))
339 } else {
340 let mut frame = frame.assume_init();
341 frame.info.size = 0;
345 frame.info.stride.fill(0);
346 frame.info.offset.fill(0);
347 Ok(Self {
348 frame,
349 unmap: true,
350 phantom: PhantomData,
351 })
352 }
353 }
354 }
355}
356
357impl<'a> GLVideoFrameRef<&'a mut gst::BufferRef> {
358 #[inline]
359 pub unsafe fn from_glib_borrow_mut(frame: *mut gst_video::ffi::GstVideoFrame) -> Self {
360 unsafe {
361 debug_assert!(!frame.is_null());
362
363 let frame = ptr::read(frame);
364 Self {
365 frame,
366 unmap: false,
367 phantom: PhantomData,
368 }
369 }
370 }
371
372 #[inline]
373 pub unsafe fn from_glib_full_mut(frame: gst_video::ffi::GstVideoFrame) -> Self {
374 Self {
375 frame,
376 unmap: true,
377 phantom: PhantomData,
378 }
379 }
380
381 #[inline]
382 pub fn from_buffer_ref_writable<'b>(
383 buffer: &'a mut gst::BufferRef,
384 info: &'b gst_video::VideoInfo,
385 ) -> Result<GLVideoFrameRef<&'a mut gst::BufferRef>, glib::error::BoolError> {
386 skip_assert_initialized!();
387
388 let n_mem = match buffer_n_gl_memory(buffer) {
389 Some(n) => n,
390 None => return Err(glib::bool_error!("Memory is not a GstGLMemory")),
391 };
392
393 if n_mem != info.n_planes() {
397 return Err(glib::bool_error!(
398 "Number of planes and memories is not matching"
399 ));
400 }
401
402 unsafe {
403 let mut frame = mem::MaybeUninit::uninit();
404 let res: bool = from_glib(gst_video::ffi::gst_video_frame_map(
405 frame.as_mut_ptr(),
406 info.to_glib_none().0 as *mut _,
407 buffer.as_mut_ptr(),
408 gst_video::ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
409 | gst::ffi::GST_MAP_READ
410 | gst::ffi::GST_MAP_WRITE
411 | ffi::GST_MAP_GL as u32,
412 ));
413
414 if !res {
415 Err(glib::bool_error!(
416 "Failed to fill in the values of GstVideoFrame"
417 ))
418 } else {
419 let mut frame = frame.assume_init();
420 frame.info.size = 0;
424 frame.info.stride.fill(0);
425 frame.info.offset.fill(0);
426 Ok(Self {
427 frame,
428 unmap: true,
429 phantom: PhantomData,
430 })
431 }
432 }
433 }
434
435 #[inline]
436 pub fn buffer_mut(&mut self) -> &mut gst::BufferRef {
437 unsafe { gst::BufferRef::from_mut_ptr(self.frame.buffer) }
438 }
439
440 #[inline]
441 pub fn as_mut_ptr(&mut self) -> *mut gst_video::ffi::GstVideoFrame {
442 &mut self.frame
443 }
444
445 #[inline]
446 pub fn memory_mut(&mut self, idx: u32) -> Result<&mut GLMemoryRef, glib::BoolError> {
447 unsafe { Ok(GLMemoryRef::from_mut_ptr(self.memory(idx)?.as_ptr() as _)) }
448 }
449}
450
451impl<'a> std::ops::Deref for GLVideoFrameRef<&'a mut gst::BufferRef> {
452 type Target = GLVideoFrameRef<&'a gst::BufferRef>;
453
454 #[inline]
455 fn deref(&self) -> &Self::Target {
456 unsafe { &*(self as *const Self as *const Self::Target) }
457 }
458}
459
460impl<T> Drop for GLVideoFrameRef<T> {
461 #[inline]
462 fn drop(&mut self) {
463 unsafe {
464 if self.unmap {
465 gst_video::ffi::gst_video_frame_unmap(&mut self.frame);
466 }
467 }
468 }
469}
470
471fn buffer_n_gl_memory(buffer: &gst::BufferRef) -> Option<u32> {
472 skip_assert_initialized!();
473 unsafe {
474 let buf = buffer.as_mut_ptr();
475 let num = gst::ffi::gst_buffer_n_memory(buf);
476 for i in 0..num - 1 {
477 let mem = gst::ffi::gst_buffer_peek_memory(buf, i);
478 if ffi::gst_is_gl_memory(mem) != glib::ffi::GTRUE {
479 return None;
480 }
481 }
482 Some(num)
483 }
484}