gstreamer_video/
video_frame.rs

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