Skip to main content

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