Skip to main content

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