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 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        debug_assert!(!frame.is_null());
667
668        let frame = ptr::read(frame);
669        Borrowed::new(Self {
670            frame,
671            unmap: false,
672            phantom: PhantomData,
673        })
674    }
675
676    #[inline]
677    pub unsafe fn from_glib_full(frame: ffi::GstVideoFrame) -> Self {
678        Self {
679            frame,
680            unmap: true,
681            phantom: PhantomData,
682        }
683    }
684
685    #[inline]
686    pub fn from_buffer_ref_readable<'b>(
687        buffer: &'a gst::BufferRef,
688        info: &'b crate::VideoInfo,
689    ) -> Result<Self, glib::BoolError> {
690        skip_assert_initialized!();
691
692        assert!(info.is_valid());
693
694        unsafe {
695            let mut frame = mem::MaybeUninit::uninit();
696            let res: bool = from_glib(ffi::gst_video_frame_map(
697                frame.as_mut_ptr(),
698                info.to_glib_none().0 as *mut _,
699                buffer.as_mut_ptr(),
700                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
701            ));
702
703            if !res {
704                Err(glib::bool_error!("Failed to map VideoFrame"))
705            } else {
706                let frame = frame.assume_init();
707                Ok(Self {
708                    frame,
709                    unmap: true,
710                    phantom: PhantomData,
711                })
712            }
713        }
714    }
715
716    #[inline]
717    pub fn from_buffer_ref_id_readable<'b>(
718        buffer: &'a gst::BufferRef,
719        id: i32,
720        info: &'b crate::VideoInfo,
721    ) -> Result<Self, glib::BoolError> {
722        skip_assert_initialized!();
723
724        assert!(info.is_valid());
725
726        unsafe {
727            let mut frame = mem::MaybeUninit::uninit();
728            let res: bool = from_glib(ffi::gst_video_frame_map_id(
729                frame.as_mut_ptr(),
730                info.to_glib_none().0 as *mut _,
731                buffer.as_mut_ptr(),
732                id,
733                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
734            ));
735
736            if !res {
737                Err(glib::bool_error!("Failed to map VideoFrame"))
738            } else {
739                let frame = frame.assume_init();
740                Ok(Self {
741                    frame,
742                    unmap: true,
743                    phantom: PhantomData,
744                })
745            }
746        }
747    }
748}
749
750impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
751    #[inline]
752    pub unsafe fn from_glib_borrow_mut(frame: *mut ffi::GstVideoFrame) -> Self {
753        debug_assert!(!frame.is_null());
754
755        let frame = ptr::read(frame);
756        Self {
757            frame,
758            unmap: false,
759            phantom: PhantomData,
760        }
761    }
762
763    #[inline]
764    pub unsafe fn from_glib_full_mut(frame: ffi::GstVideoFrame) -> Self {
765        Self {
766            frame,
767            unmap: true,
768            phantom: PhantomData,
769        }
770    }
771
772    #[inline]
773    pub fn from_buffer_ref_writable<'b>(
774        buffer: &'a mut gst::BufferRef,
775        info: &'b crate::VideoInfo,
776    ) -> Result<Self, glib::BoolError> {
777        skip_assert_initialized!();
778
779        assert!(info.is_valid());
780
781        unsafe {
782            let mut frame = mem::MaybeUninit::uninit();
783            let res: bool = from_glib(ffi::gst_video_frame_map(
784                frame.as_mut_ptr(),
785                info.to_glib_none().0 as *mut _,
786                buffer.as_mut_ptr(),
787                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
788                    | gst::ffi::GST_MAP_READ
789                    | gst::ffi::GST_MAP_WRITE,
790            ));
791
792            if !res {
793                Err(glib::bool_error!("Failed to map VideoFrame"))
794            } else {
795                let frame = frame.assume_init();
796                Ok(Self {
797                    frame,
798                    unmap: true,
799                    phantom: PhantomData,
800                })
801            }
802        }
803    }
804
805    #[inline]
806    pub fn from_buffer_ref_id_writable<'b>(
807        buffer: &'a mut gst::BufferRef,
808        id: i32,
809        info: &'b crate::VideoInfo,
810    ) -> Result<Self, glib::BoolError> {
811        skip_assert_initialized!();
812
813        assert!(info.is_valid());
814
815        unsafe {
816            let mut frame = mem::MaybeUninit::uninit();
817            let res: bool = from_glib(ffi::gst_video_frame_map_id(
818                frame.as_mut_ptr(),
819                info.to_glib_none().0 as *mut _,
820                buffer.as_mut_ptr(),
821                id,
822                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
823                    | gst::ffi::GST_MAP_READ
824                    | gst::ffi::GST_MAP_WRITE,
825            ));
826
827            if !res {
828                Err(glib::bool_error!("Failed to map VideoFrame"))
829            } else {
830                let frame = frame.assume_init();
831                Ok(Self {
832                    frame,
833                    unmap: true,
834                    phantom: PhantomData,
835                })
836            }
837        }
838    }
839
840    pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> {
841        let poffset = self.info().comp_poffset(component as u8) as usize;
842        Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..])
843    }
844
845    pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
846        match plane_buffer_info(self, plane) {
847            Ok((plane, size)) => {
848                if size == 0 {
849                    return Ok(&mut []);
850                }
851
852                unsafe {
853                    Ok(slice::from_raw_parts_mut(
854                        self.frame.data[plane] as *mut u8,
855                        size,
856                    ))
857                }
858            }
859            Err(err) => Err(err),
860        }
861    }
862
863    pub fn planes_data_mut(&mut self) -> [&mut [u8]; 4] {
864        unsafe {
865            let mut planes = [
866                [].as_mut_slice(),
867                [].as_mut_slice(),
868                [].as_mut_slice(),
869                [].as_mut_slice(),
870            ];
871
872            for plane in 0..self.n_planes() {
873                let slice = self.plane_data_mut(plane).unwrap();
874                planes[plane as usize] = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len());
875            }
876
877            planes
878        }
879    }
880
881    #[inline]
882    pub fn as_mut_ptr(&mut self) -> *mut ffi::GstVideoFrame {
883        &mut self.frame
884    }
885}
886
887impl<'a> ops::Deref for VideoFrameRef<&'a mut gst::BufferRef> {
888    type Target = VideoFrameRef<&'a gst::BufferRef>;
889
890    #[inline]
891    fn deref(&self) -> &Self::Target {
892        unsafe { &*(self as *const Self as *const Self::Target) }
893    }
894}
895
896unsafe impl<T> Send for VideoFrameRef<T> {}
897unsafe impl<T> Sync for VideoFrameRef<T> {}
898
899impl<T> Drop for VideoFrameRef<T> {
900    #[inline]
901    fn drop(&mut self) {
902        unsafe {
903            if self.unmap {
904                ffi::gst_video_frame_unmap(&mut self.frame);
905            }
906        }
907    }
908}
909
910pub trait VideoBufferExt {
911    #[doc(alias = "get_video_flags")]
912    fn video_flags(&self) -> crate::VideoBufferFlags;
913    fn set_video_flags(&mut self, flags: crate::VideoBufferFlags);
914    fn unset_video_flags(&mut self, flags: crate::VideoBufferFlags);
915}
916
917impl VideoBufferExt for gst::BufferRef {
918    #[inline]
919    fn video_flags(&self) -> crate::VideoBufferFlags {
920        unsafe {
921            let ptr = self.as_mut_ptr();
922            crate::VideoBufferFlags::from_bits_truncate((*ptr).mini_object.flags)
923        }
924    }
925
926    #[inline]
927    fn set_video_flags(&mut self, flags: crate::VideoBufferFlags) {
928        unsafe {
929            let ptr = self.as_mut_ptr();
930            (*ptr).mini_object.flags |= flags.bits();
931        }
932    }
933
934    #[inline]
935    fn unset_video_flags(&mut self, flags: crate::VideoBufferFlags) {
936        unsafe {
937            let ptr = self.as_mut_ptr();
938            (*ptr).mini_object.flags &= !flags.bits();
939        }
940    }
941}
942
943#[cfg(test)]
944mod tests {
945    use super::*;
946
947    #[test]
948    fn test_map_read() {
949        gst::init().unwrap();
950
951        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
952            .build()
953            .unwrap();
954        let buffer = gst::Buffer::with_size(info.size()).unwrap();
955        let frame = VideoFrame::from_buffer_readable(buffer, &info).unwrap();
956
957        assert!(frame.plane_data(0).is_ok());
958        assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
959        assert!(frame.plane_data(1).is_err());
960        assert!(frame.info() == &info);
961
962        {
963            let frame = frame.as_video_frame_ref();
964
965            assert!(frame.plane_data(0).is_ok());
966            assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
967            assert!(frame.plane_data(1).is_err());
968            assert!(frame.info() == &info);
969        }
970
971        assert!(frame.plane_data(0).is_ok());
972        assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
973        assert!(frame.plane_data(1).is_err());
974        assert!(frame.info() == &info);
975    }
976
977    #[test]
978    fn test_map_write() {
979        gst::init().unwrap();
980
981        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
982            .build()
983            .unwrap();
984        let buffer = gst::Buffer::with_size(info.size()).unwrap();
985        let mut frame = VideoFrame::from_buffer_writable(buffer, &info).unwrap();
986
987        assert!(frame.plane_data_mut(0).is_ok());
988        assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
989        assert!(frame.plane_data_mut(1).is_err());
990        assert!(frame.info() == &info);
991
992        {
993            let mut frame = frame.as_mut_video_frame_ref();
994
995            assert!(frame.plane_data_mut(0).is_ok());
996            assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
997            assert!(frame.plane_data_mut(1).is_err());
998            assert!(frame.info() == &info);
999        }
1000
1001        assert!(frame.plane_data_mut(0).is_ok());
1002        assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1003        assert!(frame.plane_data_mut(1).is_err());
1004        assert!(frame.info() == &info);
1005    }
1006
1007    #[test]
1008    fn test_map_ref_read() {
1009        gst::init().unwrap();
1010
1011        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
1012            .build()
1013            .unwrap();
1014        let buffer = gst::Buffer::with_size(info.size()).unwrap();
1015        let frame = VideoFrameRef::from_buffer_ref_readable(&buffer, &info).unwrap();
1016
1017        assert!(frame.plane_data(0).is_ok());
1018        assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
1019        assert!(frame.plane_data(1).is_err());
1020        assert!(frame.info() == &info);
1021    }
1022
1023    #[test]
1024    fn test_map_ref_write() {
1025        gst::init().unwrap();
1026
1027        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
1028            .build()
1029            .unwrap();
1030        let mut buffer = gst::Buffer::with_size(info.size()).unwrap();
1031        {
1032            let buffer = buffer.get_mut().unwrap();
1033            let mut frame = VideoFrameRef::from_buffer_ref_writable(buffer, &info).unwrap();
1034
1035            assert!(frame.plane_data_mut(0).is_ok());
1036            assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1037            assert!(frame.plane_data_mut(1).is_err());
1038            assert!(frame.info() == &info);
1039        }
1040    }
1041
1042    #[cfg(feature = "v1_20")]
1043    #[test]
1044    fn test_plane_data() {
1045        gst::init().unwrap();
1046
1047        let info = crate::VideoInfo::builder(crate::VideoFormat::Av12, 320, 240)
1048            .build()
1049            .unwrap();
1050        let buffer = gst::Buffer::with_size(info.size()).unwrap();
1051        let mut frame = VideoFrame::from_buffer_writable(buffer, &info).unwrap();
1052
1053        // Alpha plane
1054        {
1055            let mut frame = frame.as_mut_video_frame_ref();
1056            let data = frame.plane_data_mut(2).unwrap();
1057            assert_eq!(data.len(), 320 * 240);
1058            data[0] = 42;
1059        }
1060
1061        // UV plane
1062        {
1063            let mut frame = frame.as_mut_video_frame_ref();
1064            let data = frame.plane_data_mut(1).unwrap();
1065            assert_eq!(data.len(), 320 * 120);
1066            data[0] = 42;
1067        }
1068
1069        let frame = frame.into_buffer();
1070        let frame = VideoFrame::from_buffer_readable(frame, &info).unwrap();
1071
1072        let alpha_data = frame.plane_data(2).unwrap();
1073        assert_eq!(alpha_data.len(), 320 * 240);
1074        assert_eq!(alpha_data[0], 42);
1075
1076        let uv_data = frame.plane_data(1).unwrap();
1077        assert_eq!(uv_data.len(), 320 * 120);
1078        assert_eq!(uv_data[0], 42);
1079    }
1080}