1use std::{fmt, marker::PhantomData, mem, ops, ptr, slice};
4
5use crate::ffi;
6use glib::translate::{Borrowed, ToGlibPtr, from_glib, from_glib_none};
7
8pub enum Readable {}
9pub enum Writable {}
10
11pub unsafe trait IsVideoFrame {
12 fn as_raw(&self) -> &ffi::GstVideoFrame;
13}
14
15unsafe impl<T> IsVideoFrame for VideoFrame<T> {
16 #[inline]
17 fn as_raw(&self) -> &ffi::GstVideoFrame {
18 &self.frame
19 }
20}
21
22fn plane_buffer_info<T: IsVideoFrame>(
23 frame: &T,
24 plane: u32,
25) -> Result<(usize, usize), glib::BoolError> {
26 skip_assert_initialized!();
27
28 if plane >= frame.n_planes() {
29 return Err(glib::bool_error!(
30 "Plane index higher than number of planes"
31 ));
32 }
33
34 let format_info = frame.format_info();
35
36 if format_info.has_palette() && plane == 1 {
38 return Ok((1, 256 * 4));
39 }
40
41 let w = frame.plane_stride()[plane as usize] as u32;
42 let h = frame.plane_height(plane);
43
44 if w == 0 || h == 0 {
45 return Ok((0, 0));
46 }
47
48 Ok((plane as usize, (w * h) as usize))
49}
50
51pub struct VideoFrame<T> {
52 frame: ffi::GstVideoFrame,
53 phantom: PhantomData<T>,
54}
55
56unsafe impl<T> Send for VideoFrame<T> {}
57unsafe impl<T> Sync for VideoFrame<T> {}
58
59impl<T> fmt::Debug for VideoFrame<T> {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 f.debug_struct("VideoFrame")
62 .field("flags", &self.flags())
63 .field("id", &self.id())
64 .field("buffer", &self.buffer())
65 .field("info", &self.info())
66 .finish()
67 }
68}
69
70pub trait VideoFrameExt: IsVideoFrame {
71 #[inline]
72 fn as_ptr(&self) -> *const ffi::GstVideoFrame {
73 self.as_raw() as _
74 }
75
76 #[inline]
77 fn info(&self) -> &crate::VideoInfo {
78 unsafe {
79 let frame = self.as_raw();
80 let info = &frame.info as *const ffi::GstVideoInfo as *const crate::VideoInfo;
81 &*info
82 }
83 }
84
85 #[inline]
86 fn flags(&self) -> crate::VideoFrameFlags {
87 unsafe { from_glib(self.as_raw().flags) }
88 }
89
90 #[inline]
91 fn id(&self) -> i32 {
92 self.as_raw().id
93 }
94
95 #[inline]
96 fn buffer(&self) -> &gst::BufferRef {
97 unsafe { gst::BufferRef::from_ptr(self.as_raw().buffer) }
98 }
99
100 #[inline]
101 fn format(&self) -> crate::VideoFormat {
102 self.info().format()
103 }
104
105 #[inline]
106 fn format_info(&self) -> crate::VideoFormatInfo {
107 self.info().format_info()
108 }
109
110 #[inline]
111 fn width(&self) -> u32 {
112 self.info().width()
113 }
114
115 #[inline]
116 fn height(&self) -> u32 {
117 self.info().height()
118 }
119
120 #[inline]
121 fn size(&self) -> usize {
122 self.info().size()
123 }
124
125 #[inline]
126 fn is_interlaced(&self) -> bool {
127 self.flags().contains(crate::VideoFrameFlags::INTERLACED)
128 }
129
130 #[inline]
131 fn is_tff(&self) -> bool {
132 self.flags().contains(crate::VideoFrameFlags::TFF)
133 }
134
135 #[inline]
136 fn is_rff(&self) -> bool {
137 self.flags().contains(crate::VideoFrameFlags::RFF)
138 }
139
140 #[inline]
141 fn is_onefield(&self) -> bool {
142 self.flags().contains(crate::VideoFrameFlags::ONEFIELD)
143 }
144
145 #[inline]
146 fn is_bottom_field(&self) -> bool {
147 self.flags().contains(crate::VideoFrameFlags::ONEFIELD)
148 && !self.flags().contains(crate::VideoFrameFlags::TFF)
149 }
150
151 #[inline]
152 fn is_top_field(&self) -> bool {
153 self.flags().contains(crate::VideoFrameFlags::ONEFIELD)
154 && self.flags().contains(crate::VideoFrameFlags::TFF)
155 }
156
157 #[inline]
158 fn n_planes(&self) -> u32 {
159 self.info().n_planes()
160 }
161
162 #[inline]
163 fn n_components(&self) -> u32 {
164 self.info().n_components()
165 }
166
167 #[inline]
168 fn plane_stride(&self) -> &[i32] {
169 self.info().stride()
170 }
171
172 #[inline]
173 fn plane_offset(&self) -> &[usize] {
174 self.info().offset()
175 }
176
177 #[inline]
178 fn plane_height(&self, plane: u32) -> u32 {
179 cfg_if::cfg_if! {
180 if #[cfg(feature = "v1_18")] {
181 let comp = self.format_info().component(plane)[0];
182 if comp == -1 {
183 0
184 } else {
185 self.comp_height(comp as u32)
186 }
187 } else {
188 self.format_info().scale_height(plane as u8, self.height())
195 }
196 }
197 }
198
199 #[inline]
200 fn comp_depth(&self, component: u32) -> u32 {
201 self.info().comp_depth(component as u8)
202 }
203
204 #[inline]
205 fn comp_height(&self, component: u32) -> u32 {
206 self.info().comp_height(component as u8)
207 }
208
209 #[inline]
210 fn comp_width(&self, component: u32) -> u32 {
211 self.info().comp_width(component as u8)
212 }
213
214 #[inline]
215 fn comp_offset(&self, component: u32) -> usize {
216 self.info().comp_offset(component as u8)
217 }
218
219 #[inline]
220 fn comp_poffset(&self, component: u32) -> u32 {
221 self.info().comp_poffset(component as u8)
222 }
223
224 #[inline]
225 fn comp_pstride(&self, component: u32) -> i32 {
226 self.info().comp_pstride(component as u8)
227 }
228
229 #[inline]
230 fn comp_stride(&self, component: u32) -> i32 {
231 self.info().comp_stride(component as u8)
232 }
233
234 #[inline]
235 fn comp_plane(&self, component: u32) -> u32 {
236 self.info().comp_plane(component as u8)
237 }
238}
239
240impl<O: IsVideoFrame> VideoFrameExt for O {}
241
242impl<T> VideoFrame<T> {
243 #[inline]
244 pub fn into_buffer(self) -> gst::Buffer {
245 unsafe {
246 let mut s = mem::ManuallyDrop::new(self);
247 let buffer = from_glib_none(s.frame.buffer);
248 ffi::gst_video_frame_unmap(&mut s.frame);
249 buffer
250 }
251 }
252
253 #[doc(alias = "gst_video_frame_copy")]
254 pub fn copy(&self, dest: &mut VideoFrame<Writable>) -> Result<(), glib::BoolError> {
255 unsafe {
256 let res: bool = from_glib(ffi::gst_video_frame_copy(&mut dest.frame, &self.frame));
257 if res {
258 Ok(())
259 } else {
260 Err(glib::bool_error!("Failed to copy video frame"))
261 }
262 }
263 }
264
265 #[doc(alias = "gst_video_frame_copy_plane")]
266 pub fn copy_plane(
267 &self,
268 dest: &mut VideoFrame<Writable>,
269 plane: u32,
270 ) -> Result<(), glib::BoolError> {
271 skip_assert_initialized!();
272
273 unsafe {
274 let res: bool = from_glib(ffi::gst_video_frame_copy_plane(
275 &mut dest.frame,
276 &self.frame,
277 plane,
278 ));
279 if res {
280 Ok(())
281 } else {
282 Err(glib::bool_error!("Failed to copy video frame plane"))
283 }
284 }
285 }
286
287 #[inline]
288 pub fn comp_data(&self, component: u32) -> Result<&[u8], glib::BoolError> {
289 let poffset = self.info().comp_poffset(component as u8) as usize;
290 Ok(&self.plane_data(self.format_info().plane()[component as usize])?[poffset..])
291 }
292
293 #[inline]
294 pub fn buffer(&self) -> &gst::BufferRef {
295 unsafe { gst::BufferRef::from_ptr(self.frame.buffer) }
296 }
297
298 pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> {
299 match plane_buffer_info(self, plane) {
300 Ok((plane, size)) => {
301 if size == 0 {
302 return Ok(&[]);
303 }
304
305 unsafe {
306 Ok(slice::from_raw_parts(
307 self.frame.data[plane] as *const u8,
308 size,
309 ))
310 }
311 }
312 Err(err) => Err(err),
313 }
314 }
315
316 pub fn planes_data(&self) -> [&[u8]; 4] {
317 let mut planes = [[].as_slice(); 4];
318
319 for plane in 0..self.n_planes() {
320 planes[plane as usize] = self.plane_data(plane).unwrap();
321 }
322
323 planes
324 }
325
326 #[inline]
327 pub unsafe fn from_glib_full(frame: ffi::GstVideoFrame) -> Self {
328 Self {
329 frame,
330 phantom: PhantomData,
331 }
332 }
333
334 #[inline]
335 pub fn as_video_frame_ref(&self) -> VideoFrameRef<&gst::BufferRef> {
336 let frame = unsafe { ptr::read(&self.frame) };
337 VideoFrameRef {
338 frame,
339 unmap: false,
340 phantom: PhantomData,
341 }
342 }
343
344 #[inline]
345 pub fn into_raw(self) -> ffi::GstVideoFrame {
346 let s = mem::ManuallyDrop::new(self);
347 s.frame
348 }
349}
350
351impl<T> Drop for VideoFrame<T> {
352 #[inline]
353 fn drop(&mut self) {
354 unsafe {
355 ffi::gst_video_frame_unmap(&mut self.frame);
356 }
357 }
358}
359
360impl VideoFrame<Readable> {
361 #[inline]
362 pub fn from_buffer_readable(
363 buffer: gst::Buffer,
364 info: &crate::VideoInfo,
365 ) -> Result<Self, gst::Buffer> {
366 skip_assert_initialized!();
367
368 assert!(info.is_valid());
369
370 unsafe {
371 let mut frame = mem::MaybeUninit::uninit();
372 let res: bool = from_glib(ffi::gst_video_frame_map(
377 frame.as_mut_ptr(),
378 info.to_glib_none().0 as *mut _,
379 buffer.to_glib_none().0,
380 gst::ffi::GST_MAP_READ,
381 ));
382
383 if !res {
384 Err(buffer)
385 } else {
386 let frame = frame.assume_init();
387 Ok(Self {
388 frame,
389 phantom: PhantomData,
390 })
391 }
392 }
393 }
394
395 #[inline]
396 pub fn from_buffer_id_readable(
397 buffer: gst::Buffer,
398 id: i32,
399 info: &crate::VideoInfo,
400 ) -> Result<Self, gst::Buffer> {
401 skip_assert_initialized!();
402
403 assert!(info.is_valid());
404
405 unsafe {
406 let mut frame = mem::MaybeUninit::uninit();
407 let res: bool = from_glib(ffi::gst_video_frame_map_id(
412 frame.as_mut_ptr(),
413 info.to_glib_none().0 as *mut _,
414 buffer.to_glib_none().0,
415 id,
416 gst::ffi::GST_MAP_READ,
417 ));
418
419 if !res {
420 Err(buffer)
421 } else {
422 let frame = frame.assume_init();
423 Ok(Self {
424 frame,
425 phantom: PhantomData,
426 })
427 }
428 }
429 }
430
431 #[inline]
432 pub fn buffer_owned(&self) -> gst::Buffer {
433 unsafe { from_glib_none(self.frame.buffer) }
434 }
435}
436
437impl VideoFrame<Writable> {
438 #[inline]
439 pub fn from_buffer_writable(
440 buffer: gst::Buffer,
441 info: &crate::VideoInfo,
442 ) -> Result<Self, gst::Buffer> {
443 skip_assert_initialized!();
444
445 assert!(info.is_valid());
446
447 unsafe {
448 let mut frame = mem::MaybeUninit::uninit();
449 let res: bool = from_glib(ffi::gst_video_frame_map(
454 frame.as_mut_ptr(),
455 info.to_glib_none().0 as *mut _,
456 buffer.to_glib_none().0,
457 gst::ffi::GST_MAP_READ | gst::ffi::GST_MAP_WRITE,
458 ));
459
460 if !res {
461 Err(buffer)
462 } else {
463 let frame = frame.assume_init();
464 Ok(Self {
465 frame,
466 phantom: PhantomData,
467 })
468 }
469 }
470 }
471
472 #[inline]
473 pub fn from_buffer_id_writable(
474 buffer: gst::Buffer,
475 id: i32,
476 info: &crate::VideoInfo,
477 ) -> Result<Self, gst::Buffer> {
478 skip_assert_initialized!();
479
480 assert!(info.is_valid());
481
482 unsafe {
483 let mut frame = mem::MaybeUninit::uninit();
484 let res: bool = from_glib(ffi::gst_video_frame_map_id(
489 frame.as_mut_ptr(),
490 info.to_glib_none().0 as *mut _,
491 buffer.to_glib_none().0,
492 id,
493 gst::ffi::GST_MAP_READ | gst::ffi::GST_MAP_WRITE,
494 ));
495
496 if !res {
497 Err(buffer)
498 } else {
499 let frame = frame.assume_init();
500 Ok(Self {
501 frame,
502 phantom: PhantomData,
503 })
504 }
505 }
506 }
507
508 pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> {
509 let poffset = self.info().comp_poffset(component as u8) as usize;
510 Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..])
511 }
512
513 pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
514 match plane_buffer_info(self, plane) {
515 Ok((plane, size)) => {
516 if size == 0 {
517 return Ok(&mut []);
518 }
519
520 unsafe {
521 Ok(slice::from_raw_parts_mut(
522 self.frame.data[plane] as *mut u8,
523 size,
524 ))
525 }
526 }
527 Err(err) => Err(err),
528 }
529 }
530
531 pub fn planes_data_mut(&mut self) -> [&mut [u8]; 4] {
532 unsafe {
533 let mut planes = [
534 [].as_mut_slice(),
535 [].as_mut_slice(),
536 [].as_mut_slice(),
537 [].as_mut_slice(),
538 ];
539
540 for plane in 0..self.n_planes() {
541 let slice = self.plane_data_mut(plane).unwrap();
542 planes[plane as usize] = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len());
543 }
544
545 planes
546 }
547 }
548
549 #[inline]
550 pub fn as_mut_video_frame_ref(&mut self) -> VideoFrameRef<&mut gst::BufferRef> {
551 let frame = unsafe { ptr::read(&self.frame) };
552 VideoFrameRef {
553 frame,
554 unmap: false,
555 phantom: PhantomData,
556 }
557 }
558
559 #[inline]
560 pub fn as_mut_ptr(&mut self) -> *mut ffi::GstVideoFrame {
561 &mut self.frame
562 }
563}
564
565pub struct VideoFrameRef<T> {
566 frame: ffi::GstVideoFrame,
567 unmap: bool,
568 phantom: PhantomData<T>,
569}
570
571unsafe impl<T> IsVideoFrame for VideoFrameRef<T> {
572 #[inline]
573 fn as_raw(&self) -> &ffi::GstVideoFrame {
574 &self.frame
575 }
576}
577
578impl<T> fmt::Debug for VideoFrameRef<T> {
579 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
580 f.debug_struct("VideoFrameRef")
581 .field("flags", &self.flags())
582 .field("id", &self.id())
583 .field("buffer", &unsafe {
584 gst::BufferRef::from_ptr(self.frame.buffer)
585 })
586 .field("info", &self.info())
587 .finish()
588 }
589}
590
591impl<T> VideoFrameRef<T> {
592 #[doc(alias = "gst_video_frame_copy")]
593 pub fn copy(
594 &self,
595 dest: &mut VideoFrameRef<&mut gst::BufferRef>,
596 ) -> Result<(), glib::BoolError> {
597 unsafe {
598 let res: bool = from_glib(ffi::gst_video_frame_copy(&mut dest.frame, &self.frame));
599 if res {
600 Ok(())
601 } else {
602 Err(glib::bool_error!("Failed to copy video frame"))
603 }
604 }
605 }
606
607 #[doc(alias = "gst_video_frame_copy_plane")]
608 pub fn copy_plane(
609 &self,
610 dest: &mut VideoFrameRef<&mut gst::BufferRef>,
611 plane: u32,
612 ) -> Result<(), glib::BoolError> {
613 skip_assert_initialized!();
614
615 unsafe {
616 let res: bool = from_glib(ffi::gst_video_frame_copy_plane(
617 &mut dest.frame,
618 &self.frame,
619 plane,
620 ));
621 if res {
622 Ok(())
623 } else {
624 Err(glib::bool_error!("Failed to copy video frame plane"))
625 }
626 }
627 }
628
629 pub fn comp_data(&self, component: u32) -> Result<&[u8], glib::BoolError> {
630 let poffset = self.info().comp_poffset(component as u8) as usize;
631 Ok(&self.plane_data(self.format_info().plane()[component as usize])?[poffset..])
632 }
633
634 pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> {
635 match plane_buffer_info(self, plane) {
636 Ok((plane, size)) => {
637 if size == 0 {
638 return Ok(&[]);
639 }
640
641 unsafe {
642 Ok(slice::from_raw_parts(
643 self.frame.data[plane] as *const u8,
644 size,
645 ))
646 }
647 }
648 Err(err) => Err(err),
649 }
650 }
651
652 pub fn planes_data(&self) -> [&[u8]; 4] {
653 let mut planes = [[].as_slice(); 4];
654
655 for plane in 0..self.n_planes() {
656 planes[plane as usize] = self.plane_data(plane).unwrap();
657 }
658
659 planes
660 }
661}
662
663impl<'a> VideoFrameRef<&'a gst::BufferRef> {
664 #[inline]
665 pub unsafe fn from_glib_borrow(frame: *const ffi::GstVideoFrame) -> Borrowed<Self> {
666 unsafe {
667 debug_assert!(!frame.is_null());
668
669 let frame = ptr::read(frame);
670 Borrowed::new(Self {
671 frame,
672 unmap: false,
673 phantom: PhantomData,
674 })
675 }
676 }
677
678 #[inline]
679 pub unsafe fn from_glib_full(frame: ffi::GstVideoFrame) -> Self {
680 Self {
681 frame,
682 unmap: true,
683 phantom: PhantomData,
684 }
685 }
686
687 #[inline]
688 pub fn from_buffer_ref_readable<'b>(
689 buffer: &'a gst::BufferRef,
690 info: &'b crate::VideoInfo,
691 ) -> Result<Self, glib::BoolError> {
692 skip_assert_initialized!();
693
694 assert!(info.is_valid());
695
696 unsafe {
697 let mut frame = mem::MaybeUninit::uninit();
698 let res: bool = from_glib(ffi::gst_video_frame_map(
699 frame.as_mut_ptr(),
700 info.to_glib_none().0 as *mut _,
701 buffer.as_mut_ptr(),
702 ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
703 ));
704
705 if !res {
706 Err(glib::bool_error!("Failed to map VideoFrame"))
707 } else {
708 let frame = frame.assume_init();
709 Ok(Self {
710 frame,
711 unmap: true,
712 phantom: PhantomData,
713 })
714 }
715 }
716 }
717
718 #[inline]
719 pub fn from_buffer_ref_id_readable<'b>(
720 buffer: &'a gst::BufferRef,
721 id: i32,
722 info: &'b crate::VideoInfo,
723 ) -> Result<Self, glib::BoolError> {
724 skip_assert_initialized!();
725
726 assert!(info.is_valid());
727
728 unsafe {
729 let mut frame = mem::MaybeUninit::uninit();
730 let res: bool = from_glib(ffi::gst_video_frame_map_id(
731 frame.as_mut_ptr(),
732 info.to_glib_none().0 as *mut _,
733 buffer.as_mut_ptr(),
734 id,
735 ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
736 ));
737
738 if !res {
739 Err(glib::bool_error!("Failed to map VideoFrame"))
740 } else {
741 let frame = frame.assume_init();
742 Ok(Self {
743 frame,
744 unmap: true,
745 phantom: PhantomData,
746 })
747 }
748 }
749 }
750}
751
752impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
753 #[inline]
754 pub unsafe fn from_glib_borrow_mut(frame: *mut ffi::GstVideoFrame) -> Self {
755 unsafe {
756 debug_assert!(!frame.is_null());
757
758 let frame = ptr::read(frame);
759 Self {
760 frame,
761 unmap: false,
762 phantom: PhantomData,
763 }
764 }
765 }
766
767 #[inline]
768 pub unsafe fn from_glib_full_mut(frame: ffi::GstVideoFrame) -> Self {
769 Self {
770 frame,
771 unmap: true,
772 phantom: PhantomData,
773 }
774 }
775
776 #[inline]
777 pub fn from_buffer_ref_writable<'b>(
778 buffer: &'a mut gst::BufferRef,
779 info: &'b crate::VideoInfo,
780 ) -> Result<Self, glib::BoolError> {
781 skip_assert_initialized!();
782
783 assert!(info.is_valid());
784
785 unsafe {
786 let mut frame = mem::MaybeUninit::uninit();
787 let res: bool = from_glib(ffi::gst_video_frame_map(
788 frame.as_mut_ptr(),
789 info.to_glib_none().0 as *mut _,
790 buffer.as_mut_ptr(),
791 ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
792 | gst::ffi::GST_MAP_READ
793 | gst::ffi::GST_MAP_WRITE,
794 ));
795
796 if !res {
797 Err(glib::bool_error!("Failed to map VideoFrame"))
798 } else {
799 let frame = frame.assume_init();
800 Ok(Self {
801 frame,
802 unmap: true,
803 phantom: PhantomData,
804 })
805 }
806 }
807 }
808
809 #[inline]
810 pub fn from_buffer_ref_id_writable<'b>(
811 buffer: &'a mut gst::BufferRef,
812 id: i32,
813 info: &'b crate::VideoInfo,
814 ) -> Result<Self, glib::BoolError> {
815 skip_assert_initialized!();
816
817 assert!(info.is_valid());
818
819 unsafe {
820 let mut frame = mem::MaybeUninit::uninit();
821 let res: bool = from_glib(ffi::gst_video_frame_map_id(
822 frame.as_mut_ptr(),
823 info.to_glib_none().0 as *mut _,
824 buffer.as_mut_ptr(),
825 id,
826 ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
827 | gst::ffi::GST_MAP_READ
828 | gst::ffi::GST_MAP_WRITE,
829 ));
830
831 if !res {
832 Err(glib::bool_error!("Failed to map VideoFrame"))
833 } else {
834 let frame = frame.assume_init();
835 Ok(Self {
836 frame,
837 unmap: true,
838 phantom: PhantomData,
839 })
840 }
841 }
842 }
843
844 pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> {
845 let poffset = self.info().comp_poffset(component as u8) as usize;
846 Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..])
847 }
848
849 pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
850 match plane_buffer_info(self, plane) {
851 Ok((plane, size)) => {
852 if size == 0 {
853 return Ok(&mut []);
854 }
855
856 unsafe {
857 Ok(slice::from_raw_parts_mut(
858 self.frame.data[plane] as *mut u8,
859 size,
860 ))
861 }
862 }
863 Err(err) => Err(err),
864 }
865 }
866
867 pub fn planes_data_mut(&mut self) -> [&mut [u8]; 4] {
868 unsafe {
869 let mut planes = [
870 [].as_mut_slice(),
871 [].as_mut_slice(),
872 [].as_mut_slice(),
873 [].as_mut_slice(),
874 ];
875
876 for plane in 0..self.n_planes() {
877 let slice = self.plane_data_mut(plane).unwrap();
878 planes[plane as usize] = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len());
879 }
880
881 planes
882 }
883 }
884
885 #[inline]
886 pub fn as_mut_ptr(&mut self) -> *mut ffi::GstVideoFrame {
887 &mut self.frame
888 }
889}
890
891impl<'a> ops::Deref for VideoFrameRef<&'a mut gst::BufferRef> {
892 type Target = VideoFrameRef<&'a gst::BufferRef>;
893
894 #[inline]
895 fn deref(&self) -> &Self::Target {
896 unsafe { &*(self as *const Self as *const Self::Target) }
897 }
898}
899
900unsafe impl<T> Send for VideoFrameRef<T> {}
901unsafe impl<T> Sync for VideoFrameRef<T> {}
902
903impl<T> Drop for VideoFrameRef<T> {
904 #[inline]
905 fn drop(&mut self) {
906 unsafe {
907 if self.unmap {
908 ffi::gst_video_frame_unmap(&mut self.frame);
909 }
910 }
911 }
912}
913
914pub trait VideoBufferExt {
915 #[doc(alias = "get_video_flags")]
916 fn video_flags(&self) -> crate::VideoBufferFlags;
917 fn set_video_flags(&mut self, flags: crate::VideoBufferFlags);
918 fn unset_video_flags(&mut self, flags: crate::VideoBufferFlags);
919}
920
921impl VideoBufferExt for gst::BufferRef {
922 #[inline]
923 fn video_flags(&self) -> crate::VideoBufferFlags {
924 unsafe {
925 let ptr = self.as_mut_ptr();
926 crate::VideoBufferFlags::from_bits_truncate((*ptr).mini_object.flags)
927 }
928 }
929
930 #[inline]
931 fn set_video_flags(&mut self, flags: crate::VideoBufferFlags) {
932 unsafe {
933 let ptr = self.as_mut_ptr();
934 (*ptr).mini_object.flags |= flags.bits();
935 }
936 }
937
938 #[inline]
939 fn unset_video_flags(&mut self, flags: crate::VideoBufferFlags) {
940 unsafe {
941 let ptr = self.as_mut_ptr();
942 (*ptr).mini_object.flags &= !flags.bits();
943 }
944 }
945}
946
947#[cfg(test)]
948mod tests {
949 use super::*;
950
951 #[test]
952 fn test_map_read() {
953 gst::init().unwrap();
954
955 let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
956 .build()
957 .unwrap();
958 let buffer = gst::Buffer::with_size(info.size()).unwrap();
959 let frame = VideoFrame::from_buffer_readable(buffer, &info).unwrap();
960
961 assert!(frame.plane_data(0).is_ok());
962 assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
963 assert!(frame.plane_data(1).is_err());
964 assert!(frame.info() == &info);
965
966 {
967 let frame = frame.as_video_frame_ref();
968
969 assert!(frame.plane_data(0).is_ok());
970 assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
971 assert!(frame.plane_data(1).is_err());
972 assert!(frame.info() == &info);
973 }
974
975 assert!(frame.plane_data(0).is_ok());
976 assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
977 assert!(frame.plane_data(1).is_err());
978 assert!(frame.info() == &info);
979 }
980
981 #[test]
982 fn test_map_write() {
983 gst::init().unwrap();
984
985 let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
986 .build()
987 .unwrap();
988 let buffer = gst::Buffer::with_size(info.size()).unwrap();
989 let mut frame = VideoFrame::from_buffer_writable(buffer, &info).unwrap();
990
991 assert!(frame.plane_data_mut(0).is_ok());
992 assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
993 assert!(frame.plane_data_mut(1).is_err());
994 assert!(frame.info() == &info);
995
996 {
997 let mut frame = frame.as_mut_video_frame_ref();
998
999 assert!(frame.plane_data_mut(0).is_ok());
1000 assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1001 assert!(frame.plane_data_mut(1).is_err());
1002 assert!(frame.info() == &info);
1003 }
1004
1005 assert!(frame.plane_data_mut(0).is_ok());
1006 assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1007 assert!(frame.plane_data_mut(1).is_err());
1008 assert!(frame.info() == &info);
1009 }
1010
1011 #[test]
1012 fn test_map_ref_read() {
1013 gst::init().unwrap();
1014
1015 let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
1016 .build()
1017 .unwrap();
1018 let buffer = gst::Buffer::with_size(info.size()).unwrap();
1019 let frame = VideoFrameRef::from_buffer_ref_readable(&buffer, &info).unwrap();
1020
1021 assert!(frame.plane_data(0).is_ok());
1022 assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
1023 assert!(frame.plane_data(1).is_err());
1024 assert!(frame.info() == &info);
1025 }
1026
1027 #[test]
1028 fn test_map_ref_write() {
1029 gst::init().unwrap();
1030
1031 let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
1032 .build()
1033 .unwrap();
1034 let mut buffer = gst::Buffer::with_size(info.size()).unwrap();
1035 {
1036 let buffer = buffer.get_mut().unwrap();
1037 let mut frame = VideoFrameRef::from_buffer_ref_writable(buffer, &info).unwrap();
1038
1039 assert!(frame.plane_data_mut(0).is_ok());
1040 assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1041 assert!(frame.plane_data_mut(1).is_err());
1042 assert!(frame.info() == &info);
1043 }
1044 }
1045
1046 #[cfg(feature = "v1_20")]
1047 #[test]
1048 fn test_plane_data() {
1049 gst::init().unwrap();
1050
1051 let info = crate::VideoInfo::builder(crate::VideoFormat::Av12, 320, 240)
1052 .build()
1053 .unwrap();
1054 let buffer = gst::Buffer::with_size(info.size()).unwrap();
1055 let mut frame = VideoFrame::from_buffer_writable(buffer, &info).unwrap();
1056
1057 {
1059 let mut frame = frame.as_mut_video_frame_ref();
1060 let data = frame.plane_data_mut(2).unwrap();
1061 assert_eq!(data.len(), 320 * 240);
1062 data[0] = 42;
1063 }
1064
1065 {
1067 let mut frame = frame.as_mut_video_frame_ref();
1068 let data = frame.plane_data_mut(1).unwrap();
1069 assert_eq!(data.len(), 320 * 120);
1070 data[0] = 42;
1071 }
1072
1073 let frame = frame.into_buffer();
1074 let frame = VideoFrame::from_buffer_readable(frame, &info).unwrap();
1075
1076 let alpha_data = frame.plane_data(2).unwrap();
1077 assert_eq!(alpha_data.len(), 320 * 240);
1078 assert_eq!(alpha_data[0], 42);
1079
1080 let uv_data = frame.plane_data(1).unwrap();
1081 assert_eq!(uv_data.len(), 320 * 120);
1082 assert_eq!(uv_data[0], 42);
1083 }
1084}