gstreamer_video/
video_frame.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem, ops, ptr, slice};
4
5use crate::ffi;
6use glib::translate::{from_glib, from_glib_none, Borrowed, ToGlibPtr};
7
8pub enum Readable {}
9pub enum Writable {}
10
11pub trait IsVideoFrame {
12    fn as_raw(&self) -> &ffi::GstVideoFrame;
13}
14
15impl<T> IsVideoFrame for VideoFrame<T> {
16    #[inline]
17    fn as_raw(&self) -> &ffi::GstVideoFrame {
18        &self.frame
19    }
20}
21
22fn plane_buffer_info<T: IsVideoFrame>(
23    frame: &T,
24    plane: u32,
25) -> Result<(usize, usize), glib::BoolError> {
26    skip_assert_initialized!();
27
28    if plane >= frame.n_planes() {
29        return Err(glib::bool_error!(
30            "Plane index higher than number of planes"
31        ));
32    }
33
34    let format_info = frame.format_info();
35
36    // Just get the palette
37    if format_info.has_palette() && plane == 1 {
38        return Ok((1, 256 * 4));
39    }
40
41    let w = frame.plane_stride()[plane as usize] as u32;
42    let h = frame.plane_height(plane);
43
44    if w == 0 || h == 0 {
45        return Ok((0, 0));
46    }
47
48    Ok((plane as usize, (w * h) as usize))
49}
50
51pub struct VideoFrame<T> {
52    frame: ffi::GstVideoFrame,
53    buffer: gst::Buffer,
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 = ptr::read(&s.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        let buffer = gst::Buffer::from_glib_none(frame.buffer);
335        Self {
336            frame,
337            buffer,
338            phantom: PhantomData,
339        }
340    }
341
342    #[inline]
343    pub fn as_video_frame_ref(&self) -> VideoFrameRef<&gst::BufferRef> {
344        let frame = unsafe { ptr::read(&self.frame) };
345        VideoFrameRef {
346            frame,
347            unmap: false,
348            phantom: PhantomData,
349        }
350    }
351
352    #[inline]
353    pub fn into_raw(self) -> ffi::GstVideoFrame {
354        unsafe {
355            let mut s = mem::ManuallyDrop::new(self);
356            ptr::drop_in_place(&mut s.buffer);
357            s.frame
358        }
359    }
360}
361
362impl<T> Drop for VideoFrame<T> {
363    #[inline]
364    fn drop(&mut self) {
365        unsafe {
366            ffi::gst_video_frame_unmap(&mut self.frame);
367        }
368    }
369}
370
371impl VideoFrame<Readable> {
372    #[inline]
373    pub fn from_buffer_readable(
374        buffer: gst::Buffer,
375        info: &crate::VideoInfo,
376    ) -> Result<Self, gst::Buffer> {
377        skip_assert_initialized!();
378
379        assert!(info.is_valid());
380
381        unsafe {
382            let mut frame = mem::MaybeUninit::uninit();
383            let res: bool = from_glib(ffi::gst_video_frame_map(
384                frame.as_mut_ptr(),
385                info.to_glib_none().0 as *mut _,
386                buffer.to_glib_none().0,
387                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
388            ));
389
390            if !res {
391                Err(buffer)
392            } else {
393                let frame = frame.assume_init();
394                Ok(Self {
395                    frame,
396                    buffer,
397                    phantom: PhantomData,
398                })
399            }
400        }
401    }
402
403    #[inline]
404    pub fn from_buffer_id_readable(
405        buffer: gst::Buffer,
406        id: i32,
407        info: &crate::VideoInfo,
408    ) -> Result<Self, gst::Buffer> {
409        skip_assert_initialized!();
410
411        assert!(info.is_valid());
412
413        unsafe {
414            let mut frame = mem::MaybeUninit::uninit();
415            let res: bool = from_glib(ffi::gst_video_frame_map_id(
416                frame.as_mut_ptr(),
417                info.to_glib_none().0 as *mut _,
418                buffer.to_glib_none().0,
419                id,
420                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
421            ));
422
423            if !res {
424                Err(buffer)
425            } else {
426                let frame = frame.assume_init();
427                Ok(Self {
428                    frame,
429                    buffer,
430                    phantom: PhantomData,
431                })
432            }
433        }
434    }
435
436    #[inline]
437    pub fn buffer_owned(&self) -> gst::Buffer {
438        unsafe { from_glib_none(self.frame.buffer) }
439    }
440}
441
442impl VideoFrame<Writable> {
443    #[inline]
444    pub fn from_buffer_writable(
445        buffer: gst::Buffer,
446        info: &crate::VideoInfo,
447    ) -> Result<Self, gst::Buffer> {
448        skip_assert_initialized!();
449
450        assert!(info.is_valid());
451
452        unsafe {
453            let mut frame = mem::MaybeUninit::uninit();
454            let res: bool = from_glib(ffi::gst_video_frame_map(
455                frame.as_mut_ptr(),
456                info.to_glib_none().0 as *mut _,
457                buffer.to_glib_none().0,
458                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
459                    | gst::ffi::GST_MAP_READ
460                    | gst::ffi::GST_MAP_WRITE,
461            ));
462
463            if !res {
464                Err(buffer)
465            } else {
466                let frame = frame.assume_init();
467                Ok(Self {
468                    frame,
469                    buffer,
470                    phantom: PhantomData,
471                })
472            }
473        }
474    }
475
476    #[inline]
477    pub fn from_buffer_id_writable(
478        buffer: gst::Buffer,
479        id: i32,
480        info: &crate::VideoInfo,
481    ) -> Result<Self, gst::Buffer> {
482        skip_assert_initialized!();
483
484        assert!(info.is_valid());
485
486        unsafe {
487            let mut frame = mem::MaybeUninit::uninit();
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                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
494                    | gst::ffi::GST_MAP_READ
495                    | gst::ffi::GST_MAP_WRITE,
496            ));
497
498            if !res {
499                Err(buffer)
500            } else {
501                let frame = frame.assume_init();
502                Ok(Self {
503                    frame,
504                    buffer,
505                    phantom: PhantomData,
506                })
507            }
508        }
509    }
510
511    pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> {
512        let poffset = self.info().comp_poffset(component as u8) as usize;
513        Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..])
514    }
515
516    pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
517        match plane_buffer_info(self, plane) {
518            Ok((plane, size)) => {
519                if size == 0 {
520                    return Ok(&mut []);
521                }
522
523                unsafe {
524                    Ok(slice::from_raw_parts_mut(
525                        self.frame.data[plane] as *mut u8,
526                        size,
527                    ))
528                }
529            }
530            Err(err) => Err(err),
531        }
532    }
533
534    pub fn planes_data_mut(&mut self) -> [&mut [u8]; 4] {
535        unsafe {
536            let mut planes = [
537                [].as_mut_slice(),
538                [].as_mut_slice(),
539                [].as_mut_slice(),
540                [].as_mut_slice(),
541            ];
542
543            for plane in 0..self.n_planes() {
544                let slice = self.plane_data_mut(plane).unwrap();
545                planes[plane as usize] = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len());
546            }
547
548            planes
549        }
550    }
551
552    #[inline]
553    pub fn as_mut_video_frame_ref(&mut self) -> VideoFrameRef<&mut gst::BufferRef> {
554        let frame = unsafe { ptr::read(&self.frame) };
555        VideoFrameRef {
556            frame,
557            unmap: false,
558            phantom: PhantomData,
559        }
560    }
561
562    #[inline]
563    pub fn as_mut_ptr(&mut self) -> *mut ffi::GstVideoFrame {
564        &mut self.frame
565    }
566}
567
568pub struct VideoFrameRef<T> {
569    frame: ffi::GstVideoFrame,
570    unmap: bool,
571    phantom: PhantomData<T>,
572}
573
574impl<T> IsVideoFrame for VideoFrameRef<T> {
575    #[inline]
576    fn as_raw(&self) -> &ffi::GstVideoFrame {
577        &self.frame
578    }
579}
580
581impl<T> fmt::Debug for VideoFrameRef<T> {
582    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
583        f.debug_struct("VideoFrameRef")
584            .field("flags", &self.flags())
585            .field("id", &self.id())
586            .field("buffer", &unsafe {
587                gst::BufferRef::from_ptr(self.frame.buffer)
588            })
589            .field("info", &self.info())
590            .finish()
591    }
592}
593
594impl<T> VideoFrameRef<T> {
595    #[doc(alias = "gst_video_frame_copy")]
596    pub fn copy(
597        &self,
598        dest: &mut VideoFrameRef<&mut gst::BufferRef>,
599    ) -> Result<(), glib::BoolError> {
600        unsafe {
601            let res: bool = from_glib(ffi::gst_video_frame_copy(&mut dest.frame, &self.frame));
602            if res {
603                Ok(())
604            } else {
605                Err(glib::bool_error!("Failed to copy video frame"))
606            }
607        }
608    }
609
610    #[doc(alias = "gst_video_frame_copy_plane")]
611    pub fn copy_plane(
612        &self,
613        dest: &mut VideoFrameRef<&mut gst::BufferRef>,
614        plane: u32,
615    ) -> Result<(), glib::BoolError> {
616        skip_assert_initialized!();
617
618        unsafe {
619            let res: bool = from_glib(ffi::gst_video_frame_copy_plane(
620                &mut dest.frame,
621                &self.frame,
622                plane,
623            ));
624            if res {
625                Ok(())
626            } else {
627                Err(glib::bool_error!("Failed to copy video frame plane"))
628            }
629        }
630    }
631
632    pub fn comp_data(&self, component: u32) -> Result<&[u8], glib::BoolError> {
633        let poffset = self.info().comp_poffset(component as u8) as usize;
634        Ok(&self.plane_data(self.format_info().plane()[component as usize])?[poffset..])
635    }
636
637    pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> {
638        match plane_buffer_info(self, plane) {
639            Ok((plane, size)) => {
640                if size == 0 {
641                    return Ok(&[]);
642                }
643
644                unsafe {
645                    Ok(slice::from_raw_parts(
646                        self.frame.data[plane] as *const u8,
647                        size,
648                    ))
649                }
650            }
651            Err(err) => Err(err),
652        }
653    }
654
655    pub fn planes_data(&self) -> [&[u8]; 4] {
656        let mut planes = [[].as_slice(); 4];
657
658        for plane in 0..self.n_planes() {
659            planes[plane as usize] = self.plane_data(plane).unwrap();
660        }
661
662        planes
663    }
664}
665
666impl<'a> VideoFrameRef<&'a gst::BufferRef> {
667    #[inline]
668    pub unsafe fn from_glib_borrow(frame: *const ffi::GstVideoFrame) -> Borrowed<Self> {
669        debug_assert!(!frame.is_null());
670
671        let frame = ptr::read(frame);
672        Borrowed::new(Self {
673            frame,
674            unmap: false,
675            phantom: PhantomData,
676        })
677    }
678
679    #[inline]
680    pub unsafe fn from_glib_full(frame: ffi::GstVideoFrame) -> Self {
681        Self {
682            frame,
683            unmap: true,
684            phantom: PhantomData,
685        }
686    }
687
688    #[inline]
689    pub fn from_buffer_ref_readable<'b>(
690        buffer: &'a gst::BufferRef,
691        info: &'b crate::VideoInfo,
692    ) -> Result<Self, glib::BoolError> {
693        skip_assert_initialized!();
694
695        assert!(info.is_valid());
696
697        unsafe {
698            let mut frame = mem::MaybeUninit::uninit();
699            let res: bool = from_glib(ffi::gst_video_frame_map(
700                frame.as_mut_ptr(),
701                info.to_glib_none().0 as *mut _,
702                buffer.as_mut_ptr(),
703                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
704            ));
705
706            if !res {
707                Err(glib::bool_error!("Failed to map VideoFrame"))
708            } else {
709                let frame = frame.assume_init();
710                Ok(Self {
711                    frame,
712                    unmap: true,
713                    phantom: PhantomData,
714                })
715            }
716        }
717    }
718
719    #[inline]
720    pub fn from_buffer_ref_id_readable<'b>(
721        buffer: &'a gst::BufferRef,
722        id: i32,
723        info: &'b crate::VideoInfo,
724    ) -> Result<Self, glib::BoolError> {
725        skip_assert_initialized!();
726
727        assert!(info.is_valid());
728
729        unsafe {
730            let mut frame = mem::MaybeUninit::uninit();
731            let res: bool = from_glib(ffi::gst_video_frame_map_id(
732                frame.as_mut_ptr(),
733                info.to_glib_none().0 as *mut _,
734                buffer.as_mut_ptr(),
735                id,
736                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF | gst::ffi::GST_MAP_READ,
737            ));
738
739            if !res {
740                Err(glib::bool_error!("Failed to map VideoFrame"))
741            } else {
742                let frame = frame.assume_init();
743                Ok(Self {
744                    frame,
745                    unmap: true,
746                    phantom: PhantomData,
747                })
748            }
749        }
750    }
751}
752
753impl<'a> VideoFrameRef<&'a mut gst::BufferRef> {
754    #[inline]
755    pub unsafe fn from_glib_borrow_mut(frame: *mut ffi::GstVideoFrame) -> Self {
756        debug_assert!(!frame.is_null());
757
758        let frame = ptr::read(frame);
759        Self {
760            frame,
761            unmap: false,
762            phantom: PhantomData,
763        }
764    }
765
766    #[inline]
767    pub unsafe fn from_glib_full_mut(frame: ffi::GstVideoFrame) -> Self {
768        Self {
769            frame,
770            unmap: true,
771            phantom: PhantomData,
772        }
773    }
774
775    #[inline]
776    pub fn from_buffer_ref_writable<'b>(
777        buffer: &'a mut gst::BufferRef,
778        info: &'b crate::VideoInfo,
779    ) -> Result<Self, glib::BoolError> {
780        skip_assert_initialized!();
781
782        assert!(info.is_valid());
783
784        unsafe {
785            let mut frame = mem::MaybeUninit::uninit();
786            let res: bool = from_glib(ffi::gst_video_frame_map(
787                frame.as_mut_ptr(),
788                info.to_glib_none().0 as *mut _,
789                buffer.as_mut_ptr(),
790                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
791                    | gst::ffi::GST_MAP_READ
792                    | gst::ffi::GST_MAP_WRITE,
793            ));
794
795            if !res {
796                Err(glib::bool_error!("Failed to map VideoFrame"))
797            } else {
798                let frame = frame.assume_init();
799                Ok(Self {
800                    frame,
801                    unmap: true,
802                    phantom: PhantomData,
803                })
804            }
805        }
806    }
807
808    #[inline]
809    pub fn from_buffer_ref_id_writable<'b>(
810        buffer: &'a mut gst::BufferRef,
811        id: i32,
812        info: &'b crate::VideoInfo,
813    ) -> Result<Self, glib::BoolError> {
814        skip_assert_initialized!();
815
816        assert!(info.is_valid());
817
818        unsafe {
819            let mut frame = mem::MaybeUninit::uninit();
820            let res: bool = from_glib(ffi::gst_video_frame_map_id(
821                frame.as_mut_ptr(),
822                info.to_glib_none().0 as *mut _,
823                buffer.as_mut_ptr(),
824                id,
825                ffi::GST_VIDEO_FRAME_MAP_FLAG_NO_REF
826                    | gst::ffi::GST_MAP_READ
827                    | gst::ffi::GST_MAP_WRITE,
828            ));
829
830            if !res {
831                Err(glib::bool_error!("Failed to map VideoFrame"))
832            } else {
833                let frame = frame.assume_init();
834                Ok(Self {
835                    frame,
836                    unmap: true,
837                    phantom: PhantomData,
838                })
839            }
840        }
841    }
842
843    pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> {
844        let poffset = self.info().comp_poffset(component as u8) as usize;
845        Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..])
846    }
847
848    pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> {
849        match plane_buffer_info(self, plane) {
850            Ok((plane, size)) => {
851                if size == 0 {
852                    return Ok(&mut []);
853                }
854
855                unsafe {
856                    Ok(slice::from_raw_parts_mut(
857                        self.frame.data[plane] as *mut u8,
858                        size,
859                    ))
860                }
861            }
862            Err(err) => Err(err),
863        }
864    }
865
866    pub fn planes_data_mut(&mut self) -> [&mut [u8]; 4] {
867        unsafe {
868            let mut planes = [
869                [].as_mut_slice(),
870                [].as_mut_slice(),
871                [].as_mut_slice(),
872                [].as_mut_slice(),
873            ];
874
875            for plane in 0..self.n_planes() {
876                let slice = self.plane_data_mut(plane).unwrap();
877                planes[plane as usize] = slice::from_raw_parts_mut(slice.as_mut_ptr(), slice.len());
878            }
879
880            planes
881        }
882    }
883
884    #[inline]
885    pub fn as_mut_ptr(&mut self) -> *mut ffi::GstVideoFrame {
886        &mut self.frame
887    }
888}
889
890impl<'a> ops::Deref for VideoFrameRef<&'a mut gst::BufferRef> {
891    type Target = VideoFrameRef<&'a gst::BufferRef>;
892
893    #[inline]
894    fn deref(&self) -> &Self::Target {
895        unsafe { &*(self as *const Self as *const Self::Target) }
896    }
897}
898
899unsafe impl<T> Send for VideoFrameRef<T> {}
900unsafe impl<T> Sync for VideoFrameRef<T> {}
901
902impl<T> Drop for VideoFrameRef<T> {
903    #[inline]
904    fn drop(&mut self) {
905        unsafe {
906            if self.unmap {
907                ffi::gst_video_frame_unmap(&mut self.frame);
908            }
909        }
910    }
911}
912
913pub trait VideoBufferExt {
914    #[doc(alias = "get_video_flags")]
915    fn video_flags(&self) -> crate::VideoBufferFlags;
916    fn set_video_flags(&mut self, flags: crate::VideoBufferFlags);
917    fn unset_video_flags(&mut self, flags: crate::VideoBufferFlags);
918}
919
920impl VideoBufferExt for gst::BufferRef {
921    #[inline]
922    fn video_flags(&self) -> crate::VideoBufferFlags {
923        unsafe {
924            let ptr = self.as_mut_ptr();
925            crate::VideoBufferFlags::from_bits_truncate((*ptr).mini_object.flags)
926        }
927    }
928
929    #[inline]
930    fn set_video_flags(&mut self, flags: crate::VideoBufferFlags) {
931        unsafe {
932            let ptr = self.as_mut_ptr();
933            (*ptr).mini_object.flags |= flags.bits();
934        }
935    }
936
937    #[inline]
938    fn unset_video_flags(&mut self, flags: crate::VideoBufferFlags) {
939        unsafe {
940            let ptr = self.as_mut_ptr();
941            (*ptr).mini_object.flags &= !flags.bits();
942        }
943    }
944}
945
946#[cfg(test)]
947mod tests {
948    use super::*;
949
950    #[test]
951    fn test_map_read() {
952        gst::init().unwrap();
953
954        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
955            .build()
956            .unwrap();
957        let buffer = gst::Buffer::with_size(info.size()).unwrap();
958        let frame = VideoFrame::from_buffer_readable(buffer, &info).unwrap();
959
960        assert!(frame.plane_data(0).is_ok());
961        assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
962        assert!(frame.plane_data(1).is_err());
963        assert!(frame.info() == &info);
964
965        {
966            let frame = frame.as_video_frame_ref();
967
968            assert!(frame.plane_data(0).is_ok());
969            assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
970            assert!(frame.plane_data(1).is_err());
971            assert!(frame.info() == &info);
972        }
973
974        assert!(frame.plane_data(0).is_ok());
975        assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
976        assert!(frame.plane_data(1).is_err());
977        assert!(frame.info() == &info);
978    }
979
980    #[test]
981    fn test_map_write() {
982        gst::init().unwrap();
983
984        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
985            .build()
986            .unwrap();
987        let buffer = gst::Buffer::with_size(info.size()).unwrap();
988        let mut frame = VideoFrame::from_buffer_writable(buffer, &info).unwrap();
989
990        assert!(frame.plane_data_mut(0).is_ok());
991        assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
992        assert!(frame.plane_data_mut(1).is_err());
993        assert!(frame.info() == &info);
994
995        {
996            let mut frame = frame.as_mut_video_frame_ref();
997
998            assert!(frame.plane_data_mut(0).is_ok());
999            assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1000            assert!(frame.plane_data_mut(1).is_err());
1001            assert!(frame.info() == &info);
1002        }
1003
1004        assert!(frame.plane_data_mut(0).is_ok());
1005        assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1006        assert!(frame.plane_data_mut(1).is_err());
1007        assert!(frame.info() == &info);
1008    }
1009
1010    #[test]
1011    fn test_map_ref_read() {
1012        gst::init().unwrap();
1013
1014        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
1015            .build()
1016            .unwrap();
1017        let buffer = gst::Buffer::with_size(info.size()).unwrap();
1018        let frame = VideoFrameRef::from_buffer_ref_readable(&buffer, &info).unwrap();
1019
1020        assert!(frame.plane_data(0).is_ok());
1021        assert_eq!(frame.plane_data(0).unwrap().len(), 320 * 240);
1022        assert!(frame.plane_data(1).is_err());
1023        assert!(frame.info() == &info);
1024    }
1025
1026    #[test]
1027    fn test_map_ref_write() {
1028        gst::init().unwrap();
1029
1030        let info = crate::VideoInfo::builder(crate::VideoFormat::Gray8, 320, 240)
1031            .build()
1032            .unwrap();
1033        let mut buffer = gst::Buffer::with_size(info.size()).unwrap();
1034        {
1035            let buffer = buffer.get_mut().unwrap();
1036            let mut frame = VideoFrameRef::from_buffer_ref_writable(buffer, &info).unwrap();
1037
1038            assert!(frame.plane_data_mut(0).is_ok());
1039            assert_eq!(frame.plane_data_mut(0).unwrap().len(), 320 * 240);
1040            assert!(frame.plane_data_mut(1).is_err());
1041            assert!(frame.info() == &info);
1042        }
1043    }
1044
1045    #[cfg(feature = "v1_20")]
1046    #[test]
1047    fn test_plane_data() {
1048        gst::init().unwrap();
1049
1050        let info = crate::VideoInfo::builder(crate::VideoFormat::Av12, 320, 240)
1051            .build()
1052            .unwrap();
1053        let buffer = gst::Buffer::with_size(info.size()).unwrap();
1054        let mut frame = VideoFrame::from_buffer_writable(buffer, &info).unwrap();
1055
1056        // Alpha plane
1057        {
1058            let mut frame = frame.as_mut_video_frame_ref();
1059            let data = frame.plane_data_mut(2).unwrap();
1060            assert_eq!(data.len(), 320 * 240);
1061            data[0] = 42;
1062        }
1063
1064        // UV plane
1065        {
1066            let mut frame = frame.as_mut_video_frame_ref();
1067            let data = frame.plane_data_mut(1).unwrap();
1068            assert_eq!(data.len(), 320 * 120);
1069            data[0] = 42;
1070        }
1071
1072        let frame = frame.into_buffer();
1073        let frame = VideoFrame::from_buffer_readable(frame, &info).unwrap();
1074
1075        let alpha_data = frame.plane_data(2).unwrap();
1076        assert_eq!(alpha_data.len(), 320 * 240);
1077        assert_eq!(alpha_data[0], 42);
1078
1079        let uv_data = frame.plane_data(1).unwrap();
1080        assert_eq!(uv_data.len(), 320 * 120);
1081        assert_eq!(uv_data[0], 42);
1082    }
1083}