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