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