gstreamer_video/
video_frame.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use 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    // Just get the palette
37    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
51/// A video frame obtained from [`from_buffer_readable()`][Self::from_buffer_readable()]
52pub struct VideoFrame<T> {
53    frame: ffi::GstVideoFrame,
54    buffer: gst::Buffer,
55    phantom: PhantomData<T>,
56}
57
58unsafe impl<T> Send for VideoFrame<T> {}
59unsafe impl<T> Sync for VideoFrame<T> {}
60
61impl<T> fmt::Debug for VideoFrame<T> {
62    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63        f.debug_struct("VideoFrame")
64            .field("flags", &self.flags())
65            .field("id", &self.id())
66            .field("buffer", &self.buffer())
67            .field("info", &self.info())
68            .finish()
69    }
70}
71
72mod sealed {
73    pub trait Sealed {}
74    impl<T: super::IsVideoFrame> Sealed for T {}
75}
76
77pub trait VideoFrameExt: sealed::Sealed + IsVideoFrame {
78    #[inline]
79    fn as_ptr(&self) -> *const ffi::GstVideoFrame {
80        self.as_raw() as _
81    }
82
83    #[inline]
84    fn info(&self) -> &crate::VideoInfo {
85        unsafe {
86            let frame = self.as_raw();
87            let info = &frame.info as *const ffi::GstVideoInfo as *const crate::VideoInfo;
88            &*info
89        }
90    }
91
92    #[inline]
93    fn flags(&self) -> crate::VideoFrameFlags {
94        unsafe { from_glib(self.as_raw().flags) }
95    }
96
97    #[inline]
98    fn id(&self) -> i32 {
99        self.as_raw().id
100    }
101
102    #[inline]
103    fn buffer(&self) -> &gst::BufferRef {
104        unsafe { gst::BufferRef::from_ptr(self.as_raw().buffer) }
105    }
106
107    #[inline]
108    fn format(&self) -> crate::VideoFormat {
109        self.info().format()
110    }
111
112    #[inline]
113    fn format_info(&self) -> crate::VideoFormatInfo {
114        self.info().format_info()
115    }
116
117    #[inline]
118    fn width(&self) -> u32 {
119        self.info().width()
120    }
121
122    #[inline]
123    fn height(&self) -> u32 {
124        self.info().height()
125    }
126
127    #[inline]
128    fn size(&self) -> usize {
129        self.info().size()
130    }
131
132    #[inline]
133    fn is_interlaced(&self) -> bool {
134        self.flags().contains(crate::VideoFrameFlags::INTERLACED)
135    }
136
137    #[inline]
138    fn is_tff(&self) -> bool {
139        self.flags().contains(crate::VideoFrameFlags::TFF)
140    }
141
142    #[inline]
143    fn is_rff(&self) -> bool {
144        self.flags().contains(crate::VideoFrameFlags::RFF)
145    }
146
147    #[inline]
148    fn is_onefield(&self) -> bool {
149        self.flags().contains(crate::VideoFrameFlags::ONEFIELD)
150    }
151
152    #[inline]
153    fn is_bottom_field(&self) -> bool {
154        self.flags().contains(crate::VideoFrameFlags::ONEFIELD)
155            && !self.flags().contains(crate::VideoFrameFlags::TFF)
156    }
157
158    #[inline]
159    fn is_top_field(&self) -> bool {
160        self.flags().contains(crate::VideoFrameFlags::ONEFIELD)
161            && self.flags().contains(crate::VideoFrameFlags::TFF)
162    }
163
164    #[inline]
165    fn n_planes(&self) -> u32 {
166        self.info().n_planes()
167    }
168
169    #[inline]
170    fn n_components(&self) -> u32 {
171        self.info().n_components()
172    }
173
174    #[inline]
175    fn plane_stride(&self) -> &[i32] {
176        self.info().stride()
177    }
178
179    #[inline]
180    fn plane_offset(&self) -> &[usize] {
181        self.info().offset()
182    }
183
184    #[inline]
185    fn plane_height(&self, plane: u32) -> u32 {
186        cfg_if::cfg_if! {
187            if #[cfg(feature = "v1_18")] {
188                let comp = self.format_info().component(plane)[0];
189                if comp == -1 {
190                    0
191                } else {
192                    self.comp_height(comp as u32)
193                }
194            } else {
195                // FIXME: This assumes that the horizontal subsampling of all
196                // components in the plane is the same, which is probably safe
197
198                // Legacy implementation that does not support video formats
199                // where plane index and component index are not the same.
200                // See #536
201                self.format_info().scale_height(plane as u8, self.height())
202            }
203        }
204    }
205
206    #[inline]
207    fn comp_depth(&self, component: u32) -> u32 {
208        self.info().comp_depth(component as u8)
209    }
210
211    #[inline]
212    fn comp_height(&self, component: u32) -> u32 {
213        self.info().comp_height(component as u8)
214    }
215
216    #[inline]
217    fn comp_width(&self, component: u32) -> u32 {
218        self.info().comp_width(component as u8)
219    }
220
221    #[inline]
222    fn comp_offset(&self, component: u32) -> usize {
223        self.info().comp_offset(component as u8)
224    }
225
226    #[inline]
227    fn comp_poffset(&self, component: u32) -> u32 {
228        self.info().comp_poffset(component as u8)
229    }
230
231    #[inline]
232    fn comp_pstride(&self, component: u32) -> i32 {
233        self.info().comp_pstride(component as u8)
234    }
235
236    #[inline]
237    fn comp_stride(&self, component: u32) -> i32 {
238        self.info().comp_stride(component as u8)
239    }
240
241    #[inline]
242    fn comp_plane(&self, component: u32) -> u32 {
243        self.info().comp_plane(component as u8)
244    }
245}
246
247impl<O: IsVideoFrame> VideoFrameExt for O {}
248
249impl<T> VideoFrame<T> {
250    #[inline]
251    pub fn into_buffer(self) -> gst::Buffer {
252        unsafe {
253            let mut s = mem::ManuallyDrop::new(self);
254            let buffer = ptr::read(&s.buffer);
255            ffi::gst_video_frame_unmap(&mut s.frame);
256            buffer
257        }
258    }
259
260    #[doc(alias = "gst_video_frame_copy")]
261    pub fn copy(&self, dest: &mut VideoFrame<Writable>) -> Result<(), glib::BoolError> {
262        unsafe {
263            let res: bool = from_glib(ffi::gst_video_frame_copy(&mut dest.frame, &self.frame));
264            if res {
265                Ok(())
266            } else {
267                Err(glib::bool_error!("Failed to copy video frame"))
268            }
269        }
270    }
271
272    #[doc(alias = "gst_video_frame_copy_plane")]
273    pub fn copy_plane(
274        &self,
275        dest: &mut VideoFrame<Writable>,
276        plane: u32,
277    ) -> Result<(), glib::BoolError> {
278        skip_assert_initialized!();
279
280        unsafe {
281            let res: bool = from_glib(ffi::gst_video_frame_copy_plane(
282                &mut dest.frame,
283                &self.frame,
284                plane,
285            ));
286            if res {
287                Ok(())
288            } else {
289                Err(glib::bool_error!("Failed to copy video frame plane"))
290            }
291        }
292    }
293
294    #[inline]
295    pub fn comp_data(&self, component: u32) -> Result<&[u8], glib::BoolError> {
296        let poffset = self.info().comp_poffset(component as u8) as usize;
297        Ok(&self.plane_data(self.format_info().plane()[component as usize])?[poffset..])
298    }
299
300    #[inline]
301    pub fn buffer(&self) -> &gst::BufferRef {
302        unsafe { gst::BufferRef::from_ptr(self.frame.buffer) }
303    }
304
305    pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> {
306        match plane_buffer_info(self, plane) {
307            Ok((plane, size)) => {
308                if size == 0 {
309                    return Ok(&[]);
310                }
311
312                unsafe {
313                    Ok(slice::from_raw_parts(
314                        self.frame.data[plane] as *const u8,
315                        size,
316                    ))
317                }
318            }
319            Err(err) => Err(err),
320        }
321    }
322
323    pub fn planes_data(&self) -> [&[u8]; 4] {
324        let mut planes = [[].as_slice(); 4];
325
326        for plane in 0..self.n_planes() {
327            planes[plane as usize] = self.plane_data(plane).unwrap();
328        }
329
330        planes
331    }
332
333    #[inline]
334    pub unsafe fn from_glib_full(frame: ffi::GstVideoFrame) -> Self {
335        let buffer = gst::Buffer::from_glib_none(frame.buffer);
336        Self {
337            frame,
338            buffer,
339            phantom: PhantomData,
340        }
341    }
342
343    #[inline]
344    pub fn as_video_frame_ref(&self) -> VideoFrameRef<&gst::BufferRef> {
345        let frame = unsafe { ptr::read(&self.frame) };
346        VideoFrameRef {
347            frame,
348            unmap: false,
349            phantom: PhantomData,
350        }
351    }
352
353    #[inline]
354    pub fn into_raw(self) -> ffi::GstVideoFrame {
355        unsafe {
356            let mut s = mem::ManuallyDrop::new(self);
357            ptr::drop_in_place(&mut s.buffer);
358            s.frame
359        }
360    }
361}
362
363impl<T> Drop for VideoFrame<T> {
364    #[inline]
365    fn drop(&mut self) {
366        unsafe {
367            ffi::gst_video_frame_unmap(&mut self.frame);
368        }
369    }
370}
371
372impl VideoFrame<Readable> {
373    #[inline]
374    pub fn from_buffer_readable(
375        buffer: gst::Buffer,
376        info: &crate::VideoInfo,
377    ) -> Result<Self, gst::Buffer> {
378        skip_assert_initialized!();
379
380        assert!(info.is_valid());
381
382        unsafe {
383            let mut frame = mem::MaybeUninit::uninit();
384            let res: bool = from_glib(ffi::gst_video_frame_map(
385                frame.as_mut_ptr(),
386                info.to_glib_none().0 as *mut _,
387                buffer.to_glib_none().0,
388                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
389            ));
390
391            if !res {
392                Err(buffer)
393            } else {
394                let frame = frame.assume_init();
395                Ok(Self {
396                    frame,
397                    buffer,
398                    phantom: PhantomData,
399                })
400            }
401        }
402    }
403
404    #[inline]
405    pub fn from_buffer_id_readable(
406        buffer: gst::Buffer,
407        id: i32,
408        info: &crate::VideoInfo,
409    ) -> Result<Self, gst::Buffer> {
410        skip_assert_initialized!();
411
412        assert!(info.is_valid());
413
414        unsafe {
415            let mut frame = mem::MaybeUninit::uninit();
416            let res: bool = from_glib(ffi::gst_video_frame_map_id(
417                frame.as_mut_ptr(),
418                info.to_glib_none().0 as *mut _,
419                buffer.to_glib_none().0,
420                id,
421                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
422            ));
423
424            if !res {
425                Err(buffer)
426            } else {
427                let frame = frame.assume_init();
428                Ok(Self {
429                    frame,
430                    buffer,
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(
456                frame.as_mut_ptr(),
457                info.to_glib_none().0 as *mut _,
458                buffer.to_glib_none().0,
459                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
460                    | gst::ffi::GST_MAP_READ
461                    | gst::ffi::GST_MAP_WRITE,
462            ));
463
464            if !res {
465                Err(buffer)
466            } else {
467                let frame = frame.assume_init();
468                Ok(Self {
469                    frame,
470                    buffer,
471                    phantom: PhantomData,
472                })
473            }
474        }
475    }
476
477    #[inline]
478    pub fn from_buffer_id_writable(
479        buffer: gst::Buffer,
480        id: i32,
481        info: &crate::VideoInfo,
482    ) -> Result<Self, gst::Buffer> {
483        skip_assert_initialized!();
484
485        assert!(info.is_valid());
486
487        unsafe {
488            let mut frame = mem::MaybeUninit::uninit();
489            let res: bool = from_glib(ffi::gst_video_frame_map_id(
490                frame.as_mut_ptr(),
491                info.to_glib_none().0 as *mut _,
492                buffer.to_glib_none().0,
493                id,
494                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
495                    | gst::ffi::GST_MAP_READ
496                    | gst::ffi::GST_MAP_WRITE,
497            ));
498
499            if !res {
500                Err(buffer)
501            } else {
502                let frame = frame.assume_init();
503                Ok(Self {
504                    frame,
505                    buffer,
506                    phantom: PhantomData,
507                })
508            }
509        }
510    }
511
512    pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> {
513        let poffset = self.info().comp_poffset(component as u8) as usize;
514        Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..])
515    }
516
517    pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
518        match plane_buffer_info(self, plane) {
519            Ok((plane, size)) => {
520                if size == 0 {
521                    return Ok(&mut []);
522                }
523
524                unsafe {
525                    Ok(slice::from_raw_parts_mut(
526                        self.frame.data[plane] as *mut u8,
527                        size,
528                    ))
529                }
530            }
531            Err(err) => Err(err),
532        }
533    }
534
535    pub fn planes_data_mut(&mut self) -> [&mut [u8]; 4] {
536        unsafe {
537            let mut planes = [
538                [].as_mut_slice(),
539                [].as_mut_slice(),
540                [].as_mut_slice(),
541                [].as_mut_slice(),
542            ];
543
544            for plane in 0..self.n_planes() {
545                let slice = self.plane_data_mut(plane).unwrap();
546                planes[plane as usize] = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len());
547            }
548
549            planes
550        }
551    }
552
553    #[inline]
554    pub fn as_mut_video_frame_ref(&mut self) -> VideoFrameRef<&mut gst::BufferRef> {
555        let frame = unsafe { ptr::read(&self.frame) };
556        VideoFrameRef {
557            frame,
558            unmap: false,
559            phantom: PhantomData,
560        }
561    }
562
563    #[inline]
564    pub fn as_mut_ptr(&mut self) -> *mut ffi::GstVideoFrame {
565        &mut self.frame
566    }
567}
568
569pub struct VideoFrameRef<T> {
570    frame: ffi::GstVideoFrame,
571    unmap: bool,
572    phantom: PhantomData<T>,
573}
574
575impl<T> IsVideoFrame for VideoFrameRef<T> {
576    #[inline]
577    fn as_raw(&self) -> &ffi::GstVideoFrame {
578        &self.frame
579    }
580}
581
582impl<T> fmt::Debug for VideoFrameRef<T> {
583    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
584        f.debug_struct("VideoFrameRef")
585            .field("flags", &self.flags())
586            .field("id", &self.id())
587            .field("buffer", &unsafe {
588                gst::BufferRef::from_ptr(self.frame.buffer)
589            })
590            .field("info", &self.info())
591            .finish()
592    }
593}
594
595impl<T> VideoFrameRef<T> {
596    #[doc(alias = "gst_video_frame_copy")]
597    pub fn copy(
598        &self,
599        dest: &mut VideoFrameRef<&mut gst::BufferRef>,
600    ) -> Result<(), glib::BoolError> {
601        unsafe {
602            let res: bool = from_glib(ffi::gst_video_frame_copy(&mut dest.frame, &self.frame));
603            if res {
604                Ok(())
605            } else {
606                Err(glib::bool_error!("Failed to copy video frame"))
607            }
608        }
609    }
610
611    #[doc(alias = "gst_video_frame_copy_plane")]
612    pub fn copy_plane(
613        &self,
614        dest: &mut VideoFrameRef<&mut gst::BufferRef>,
615        plane: u32,
616    ) -> Result<(), glib::BoolError> {
617        skip_assert_initialized!();
618
619        unsafe {
620            let res: bool = from_glib(ffi::gst_video_frame_copy_plane(
621                &mut dest.frame,
622                &self.frame,
623                plane,
624            ));
625            if res {
626                Ok(())
627            } else {
628                Err(glib::bool_error!("Failed to copy video frame plane"))
629            }
630        }
631    }
632
633    pub fn comp_data(&self, component: u32) -> Result<&[u8], glib::BoolError> {
634        let poffset = self.info().comp_poffset(component as u8) as usize;
635        Ok(&self.plane_data(self.format_info().plane()[component as usize])?[poffset..])
636    }
637
638    pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> {
639        match plane_buffer_info(self, plane) {
640            Ok((plane, size)) => {
641                if size == 0 {
642                    return Ok(&[]);
643                }
644
645                unsafe {
646                    Ok(slice::from_raw_parts(
647                        self.frame.data[plane] as *const u8,
648                        size,
649                    ))
650                }
651            }
652            Err(err) => Err(err),
653        }
654    }
655
656    pub fn planes_data(&self) -> [&[u8]; 4] {
657        let mut planes = [[].as_slice(); 4];
658
659        for plane in 0..self.n_planes() {
660            planes[plane as usize] = self.plane_data(plane).unwrap();
661        }
662
663        planes
664    }
665}
666
667impl<'a> VideoFrameRef<&'a gst::BufferRef> {
668    #[inline]
669    pub unsafe fn from_glib_borrow(frame: *const ffi::GstVideoFrame) -> Borrowed<Self> {
670        debug_assert!(!frame.is_null());
671
672        let frame = ptr::read(frame);
673        Borrowed::new(Self {
674            frame,
675            unmap: false,
676            phantom: PhantomData,
677        })
678    }
679
680    #[inline]
681    pub unsafe fn from_glib_full(frame: ffi::GstVideoFrame) -> Self {
682        Self {
683            frame,
684            unmap: true,
685            phantom: PhantomData,
686        }
687    }
688
689    #[inline]
690    pub fn from_buffer_ref_readable<'b>(
691        buffer: &'a gst::BufferRef,
692        info: &'b crate::VideoInfo,
693    ) -> Result<Self, glib::BoolError> {
694        skip_assert_initialized!();
695
696        assert!(info.is_valid());
697
698        unsafe {
699            let mut frame = mem::MaybeUninit::uninit();
700            let res: bool = from_glib(ffi::gst_video_frame_map(
701                frame.as_mut_ptr(),
702                info.to_glib_none().0 as *mut _,
703                buffer.as_mut_ptr(),
704                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
705            ));
706
707            if !res {
708                Err(glib::bool_error!("Failed to map VideoFrame"))
709            } else {
710                let frame = frame.assume_init();
711                Ok(Self {
712                    frame,
713                    unmap: true,
714                    phantom: PhantomData,
715                })
716            }
717        }
718    }
719
720    #[inline]
721    pub fn from_buffer_ref_id_readable<'b>(
722        buffer: &'a gst::BufferRef,
723        id: i32,
724        info: &'b crate::VideoInfo,
725    ) -> Result<Self, glib::BoolError> {
726        skip_assert_initialized!();
727
728        assert!(info.is_valid());
729
730        unsafe {
731            let mut frame = mem::MaybeUninit::uninit();
732            let res: bool = from_glib(ffi::gst_video_frame_map_id(
733                frame.as_mut_ptr(),
734                info.to_glib_none().0 as *mut _,
735                buffer.as_mut_ptr(),
736                id,
737                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
738            ));
739
740            if !res {
741                Err(glib::bool_error!("Failed to map VideoFrame"))
742            } else {
743                let frame = frame.assume_init();
744                Ok(Self {
745                    frame,
746                    unmap: true,
747                    phantom: PhantomData,
748                })
749            }
750        }
751    }
752}
753
754impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
755    #[inline]
756    pub unsafe fn from_glib_borrow_mut(frame: *mut ffi::GstVideoFrame) -> Self {
757        debug_assert!(!frame.is_null());
758
759        let frame = ptr::read(frame);
760        Self {
761            frame,
762            unmap: false,
763            phantom: PhantomData,
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        // Alpha plane
1058        {
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        // UV plane
1066        {
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}