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