1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::{fmt, marker::PhantomData, mem, ops, ptr, slice}; |
4 | |
5 | use glib::translate::{from_glib, from_glib_none, Borrowed, ToGlibPtr}; |
6 | |
7 | pub enum Readable {} |
8 | pub enum Writable {} |
9 | |
10 | pub struct VideoFrame<T> { |
11 | frame: ffi::GstVideoFrame, |
12 | buffer: gst::Buffer, |
13 | phantom: PhantomData<T>, |
14 | } |
15 | |
16 | unsafe impl<T> Send for VideoFrame<T> {} |
17 | unsafe impl<T> Sync for VideoFrame<T> {} |
18 | |
19 | impl<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 | |
30 | impl<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 | |
289 | impl<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 | |
298 | impl 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 | |
369 | impl 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 | |
500 | pub struct VideoFrameRef<T> { |
501 | frame: ffi::GstVideoFrame, |
502 | unmap: bool, |
503 | phantom: PhantomData<T>, |
504 | } |
505 | |
506 | impl<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 | |
519 | impl<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 | |
736 | impl<'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 | |
828 | impl<'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 | |
970 | impl<'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 | |
979 | unsafe impl<T> Send for VideoFrameRef<T> {} |
980 | unsafe impl<T> Sync for VideoFrameRef<T> {} |
981 | |
982 | impl<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 | |
993 | pub 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 | |
1000 | impl 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)] |
1027 | mod 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 | |