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