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