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