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