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