1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, ptr};
4
5use crate::ffi;
6use glib::translate::*;
7use gst::prelude::*;
8
9#[repr(transparent)]
10#[doc(alias = "GstVideoMeta")]
11pub struct VideoMeta(ffi::GstVideoMeta);
12
13unsafe impl Send for VideoMeta {}
14unsafe impl Sync for VideoMeta {}
15
16impl VideoMeta {
17 #[doc(alias = "gst_buffer_add_video_meta")]
18 pub fn add(
19 buffer: &mut gst::BufferRef,
20 video_frame_flags: crate::VideoFrameFlags,
21 format: crate::VideoFormat,
22 width: u32,
23 height: u32,
24 ) -> Result<gst::MetaRefMut<Self, gst::meta::Standalone>, glib::BoolError> {
25 skip_assert_initialized!();
26
27 if format == crate::VideoFormat::Unknown || format == crate::VideoFormat::Encoded {
28 return Err(glib::bool_error!("Unsupported video format {}", format));
29 }
30
31 let info = crate::VideoInfo::builder(format, width, height).build()?;
32
33 if !info.is_valid() {
34 return Err(glib::bool_error!("Invalid video info"));
35 }
36
37 if buffer.size() < info.size() {
38 return Err(glib::bool_error!(
39 "Buffer smaller than required frame size ({} < {})",
40 buffer.size(),
41 info.size()
42 ));
43 }
44
45 unsafe {
46 let meta = ffi::gst_buffer_add_video_meta(
47 buffer.as_mut_ptr(),
48 video_frame_flags.into_glib(),
49 format.into_glib(),
50 width,
51 height,
52 );
53
54 if meta.is_null() {
55 return Err(glib::bool_error!("Failed to add video meta"));
56 }
57
58 Ok(Self::from_mut_ptr(buffer, meta))
59 }
60 }
61
62 pub fn add_full<'a>(
63 buffer: &'a mut gst::BufferRef,
64 video_frame_flags: crate::VideoFrameFlags,
65 format: crate::VideoFormat,
66 width: u32,
67 height: u32,
68 offset: &[usize],
69 stride: &[i32],
70 ) -> Result<gst::MetaRefMut<'a, Self, gst::meta::Standalone>, glib::BoolError> {
71 skip_assert_initialized!();
72
73 if format == crate::VideoFormat::Unknown || format == crate::VideoFormat::Encoded {
74 return Err(glib::bool_error!("Unsupported video format {}", format));
75 }
76
77 let n_planes = offset.len() as u32;
78 let info_builder = crate::VideoInfo::builder(format, width, height)
79 .offset(offset)
80 .stride(stride);
81
82 #[cfg(feature = "v1_16")]
83 let info_builder = info_builder.interlace_mode_if(
84 crate::VideoInterlaceMode::Alternate,
85 video_frame_flags.contains(crate::VideoFrameFlags::ONEFIELD),
86 );
87
88 let info = info_builder.build()?;
89
90 if !info.is_valid() {
91 return Err(glib::bool_error!("Invalid video info"));
92 }
93
94 if buffer.size() < info.size() {
95 return Err(glib::bool_error!(
96 "Buffer smaller than required frame size ({} < {})",
97 buffer.size(),
98 info.size()
99 ));
100 }
101
102 unsafe {
103 let meta = ffi::gst_buffer_add_video_meta_full(
104 buffer.as_mut_ptr(),
105 video_frame_flags.into_glib(),
106 format.into_glib(),
107 width,
108 height,
109 n_planes,
110 offset.as_ptr() as *mut _,
111 stride.as_ptr() as *mut _,
112 );
113
114 if meta.is_null() {
115 return Err(glib::bool_error!("Failed to add video meta"));
116 }
117
118 Ok(Self::from_mut_ptr(buffer, meta))
119 }
120 }
121
122 #[doc(alias = "get_flags")]
123 #[inline]
124 pub fn video_frame_flags(&self) -> crate::VideoFrameFlags {
125 unsafe { from_glib(self.0.flags) }
126 }
127
128 #[doc(alias = "get_format")]
129 #[inline]
130 pub fn format(&self) -> crate::VideoFormat {
131 unsafe { from_glib(self.0.format) }
132 }
133
134 #[doc(alias = "get_id")]
135 #[inline]
136 pub fn id(&self) -> i32 {
137 self.0.id
138 }
139
140 #[doc(alias = "get_width")]
141 #[inline]
142 pub fn width(&self) -> u32 {
143 self.0.width
144 }
145
146 #[doc(alias = "get_height")]
147 #[inline]
148 pub fn height(&self) -> u32 {
149 self.0.height
150 }
151
152 #[doc(alias = "get_n_planes")]
153 #[inline]
154 pub fn n_planes(&self) -> u32 {
155 self.0.n_planes
156 }
157
158 #[doc(alias = "get_offset")]
159 #[inline]
160 pub fn offset(&self) -> &[usize] {
161 &self.0.offset[0..(self.0.n_planes as usize)]
162 }
163
164 #[doc(alias = "get_stride")]
165 #[inline]
166 pub fn stride(&self) -> &[i32] {
167 &self.0.stride[0..(self.0.n_planes as usize)]
168 }
169
170 #[cfg(feature = "v1_18")]
171 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
172 #[doc(alias = "get_alignment")]
173 #[inline]
174 pub fn alignment(&self) -> crate::VideoAlignment {
175 crate::VideoAlignment::new(
176 self.0.alignment.padding_top,
177 self.0.alignment.padding_bottom,
178 self.0.alignment.padding_left,
179 self.0.alignment.padding_right,
180 &self.0.alignment.stride_align,
181 )
182 }
183
184 #[cfg(feature = "v1_18")]
185 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
186 #[doc(alias = "get_plane_size")]
187 #[doc(alias = "gst_video_meta_get_plane_size")]
188 pub fn plane_size(&self) -> Result<[usize; crate::VIDEO_MAX_PLANES], glib::BoolError> {
189 let mut plane_size = [0; crate::VIDEO_MAX_PLANES];
190
191 unsafe {
192 glib::result_from_gboolean!(
193 ffi::gst_video_meta_get_plane_size(mut_override(&self.0), &mut plane_size,),
194 "Failed to get plane size"
195 )?;
196 }
197
198 Ok(plane_size)
199 }
200
201 #[cfg(feature = "v1_18")]
202 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
203 #[doc(alias = "get_plane_height")]
204 #[doc(alias = "gst_video_meta_get_plane_height")]
205 pub fn plane_height(&self) -> Result<[u32; crate::VIDEO_MAX_PLANES], glib::BoolError> {
206 let mut plane_height = [0; crate::VIDEO_MAX_PLANES];
207
208 unsafe {
209 glib::result_from_gboolean!(
210 ffi::gst_video_meta_get_plane_height(mut_override(&self.0), &mut plane_height,),
211 "Failed to get plane height"
212 )?;
213 }
214
215 Ok(plane_height)
216 }
217
218 #[cfg(feature = "v1_18")]
219 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
220 #[doc(alias = "gst_video_meta_set_alignment")]
221 pub fn set_alignment(
222 &mut self,
223 alignment: &crate::VideoAlignment,
224 ) -> Result<(), glib::BoolError> {
225 unsafe {
226 glib::result_from_gboolean!(
227 ffi::gst_video_meta_set_alignment(&mut self.0, alignment.0),
228 "Failed to set alignment on VideoMeta"
229 )
230 }
231 }
232}
233
234unsafe impl MetaAPI for VideoMeta {
235 type GstType = ffi::GstVideoMeta;
236
237 #[doc(alias = "gst_video_meta_api_get_type")]
238 #[inline]
239 fn meta_api() -> glib::Type {
240 unsafe { from_glib(val:ffi::gst_video_meta_api_get_type()) }
241 }
242}
243
244impl fmt::Debug for VideoMeta {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 f&mut DebugStruct<'_, '_>.debug_struct("VideoMeta")
247 .field("id", &self.id())
248 .field("video_frame_flags", &self.video_frame_flags())
249 .field("format", &self.format())
250 .field("width", &self.width())
251 .field("height", &self.height())
252 .field("n_planes", &self.n_planes())
253 .field("offset", &self.offset())
254 .field(name:"stride", &self.stride())
255 .finish()
256 }
257}
258
259#[repr(transparent)]
260#[doc(alias = "GstVideoCropMeta")]
261pub struct VideoCropMeta(ffi::GstVideoCropMeta);
262
263unsafe impl Send for VideoCropMeta {}
264unsafe impl Sync for VideoCropMeta {}
265
266impl VideoCropMeta {
267 #[doc(alias = "gst_buffer_add_meta")]
268 pub fn add(
269 buffer: &mut gst::BufferRef,
270 rect: (u32, u32, u32, u32),
271 ) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
272 skip_assert_initialized!();
273 unsafe {
274 let meta = gst::ffi::gst_buffer_add_meta(
275 buffer.as_mut_ptr(),
276 ffi::gst_video_crop_meta_get_info(),
277 ptr::null_mut(),
278 ) as *mut ffi::GstVideoCropMeta;
279
280 {
281 let meta = &mut *meta;
282 meta.x = rect.0;
283 meta.y = rect.1;
284 meta.width = rect.2;
285 meta.height = rect.3;
286 }
287
288 Self::from_mut_ptr(buffer, meta)
289 }
290 }
291
292 #[doc(alias = "get_rect")]
293 #[inline]
294 pub fn rect(&self) -> (u32, u32, u32, u32) {
295 (self.0.x, self.0.y, self.0.width, self.0.height)
296 }
297
298 #[inline]
299 pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
300 self.0.x = rect.0;
301 self.0.y = rect.1;
302 self.0.width = rect.2;
303 self.0.height = rect.3;
304 }
305}
306
307unsafe impl MetaAPI for VideoCropMeta {
308 type GstType = ffi::GstVideoCropMeta;
309
310 #[doc(alias = "gst_video_crop_meta_api_get_type")]
311 #[inline]
312 fn meta_api() -> glib::Type {
313 unsafe { from_glib(val:ffi::gst_video_crop_meta_api_get_type()) }
314 }
315}
316
317impl fmt::Debug for VideoCropMeta {
318 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319 f&mut DebugStruct<'_, '_>.debug_struct("VideoCropMeta")
320 .field(name:"rect", &self.rect())
321 .finish()
322 }
323}
324
325#[repr(transparent)]
326#[doc(alias = "GstVideoRegionOfInterestMeta")]
327pub struct VideoRegionOfInterestMeta(ffi::GstVideoRegionOfInterestMeta);
328
329unsafe impl Send for VideoRegionOfInterestMeta {}
330unsafe impl Sync for VideoRegionOfInterestMeta {}
331
332impl VideoRegionOfInterestMeta {
333 #[doc(alias = "gst_buffer_add_video_region_of_interest_meta")]
334 pub fn add<'a>(
335 buffer: &'a mut gst::BufferRef,
336 roi_type: &str,
337 rect: (u32, u32, u32, u32),
338 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
339 skip_assert_initialized!();
340 unsafe {
341 let meta = ffi::gst_buffer_add_video_region_of_interest_meta(
342 buffer.as_mut_ptr(),
343 roi_type.to_glib_none().0,
344 rect.0,
345 rect.1,
346 rect.2,
347 rect.3,
348 );
349
350 Self::from_mut_ptr(buffer, meta)
351 }
352 }
353
354 #[doc(alias = "get_rect")]
355 #[inline]
356 pub fn rect(&self) -> (u32, u32, u32, u32) {
357 (self.0.x, self.0.y, self.0.w, self.0.h)
358 }
359
360 #[doc(alias = "get_id")]
361 #[inline]
362 pub fn id(&self) -> i32 {
363 self.0.id
364 }
365
366 #[doc(alias = "get_parent_id")]
367 #[inline]
368 pub fn parent_id(&self) -> i32 {
369 self.0.parent_id
370 }
371
372 #[doc(alias = "get_roi_type")]
373 #[inline]
374 pub fn roi_type<'a>(&self) -> &'a str {
375 unsafe { glib::Quark::from_glib(self.0.roi_type).as_str() }
376 }
377
378 #[doc(alias = "get_params")]
379 pub fn params(&self) -> ParamsIter {
380 ParamsIter {
381 _meta: self,
382 list: ptr::NonNull::new(self.0.params),
383 }
384 }
385
386 #[doc(alias = "get_param")]
387 #[inline]
388 pub fn param<'b>(&'b self, name: &str) -> Option<&'b gst::StructureRef> {
389 self.params().find(|s| s.name() == name)
390 }
391
392 #[inline]
393 pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
394 self.0.x = rect.0;
395 self.0.y = rect.1;
396 self.0.w = rect.2;
397 self.0.h = rect.3;
398 }
399
400 #[inline]
401 pub fn set_id(&mut self, id: i32) {
402 self.0.id = id
403 }
404
405 #[inline]
406 pub fn set_parent_id(&mut self, id: i32) {
407 self.0.parent_id = id
408 }
409
410 #[doc(alias = "gst_video_region_of_interest_meta_add_param")]
411 pub fn add_param(&mut self, s: gst::Structure) {
412 unsafe {
413 ffi::gst_video_region_of_interest_meta_add_param(&mut self.0, s.into_glib_ptr());
414 }
415 }
416}
417
418pub struct ParamsIter<'a> {
419 _meta: &'a VideoRegionOfInterestMeta,
420 list: Option<ptr::NonNull<glib::ffi::GList>>,
421}
422
423impl<'a> Iterator for ParamsIter<'a> {
424 type Item = &'a gst::StructureRef;
425
426 fn next(&mut self) -> Option<&'a gst::StructureRef> {
427 match self.list {
428 None => None,
429 Some(list: NonNull) => unsafe {
430 self.list = ptr::NonNull::new(ptr:list.as_ref().next);
431 let data: *mut c_void = list.as_ref().data;
432
433 let s: &StructureRef = gst::StructureRef::from_glib_borrow(ptr:data as *const gst::ffi::GstStructure);
434
435 Some(s)
436 },
437 }
438 }
439}
440
441impl std::iter::FusedIterator for ParamsIter<'_> {}
442
443unsafe impl MetaAPI for VideoRegionOfInterestMeta {
444 type GstType = ffi::GstVideoRegionOfInterestMeta;
445
446 #[doc(alias = "gst_video_region_of_interest_meta_api_get_type")]
447 #[inline]
448 fn meta_api() -> glib::Type {
449 unsafe { from_glib(val:ffi::gst_video_region_of_interest_meta_api_get_type()) }
450 }
451}
452
453impl fmt::Debug for VideoRegionOfInterestMeta {
454 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
455 f&mut DebugStruct<'_, '_>.debug_struct("VideoRegionOfInterestMeta")
456 .field("roi_type", &self.roi_type())
457 .field("rect", &self.rect())
458 .field("id", &self.id())
459 .field("parent_id", &self.parent_id())
460 .field(name:"params", &self.params().collect::<Vec<_>>())
461 .finish()
462 }
463}
464
465#[repr(transparent)]
466#[doc(alias = "GstVideoAffineTransformationMeta")]
467pub struct VideoAffineTransformationMeta(ffi::GstVideoAffineTransformationMeta);
468
469unsafe impl Send for VideoAffineTransformationMeta {}
470unsafe impl Sync for VideoAffineTransformationMeta {}
471
472impl VideoAffineTransformationMeta {
473 #[doc(alias = "gst_buffer_add_meta")]
474 pub fn add<'a>(
475 buffer: &'a mut gst::BufferRef,
476 matrix: Option<&[[f32; 4]; 4]>,
477 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
478 skip_assert_initialized!();
479 unsafe {
480 let meta = gst::ffi::gst_buffer_add_meta(
481 buffer.as_mut_ptr(),
482 ffi::gst_video_affine_transformation_meta_get_info(),
483 ptr::null_mut(),
484 ) as *mut ffi::GstVideoAffineTransformationMeta;
485
486 if let Some(matrix) = matrix {
487 let meta = &mut *meta;
488 for (i, o) in Iterator::zip(matrix.iter().flatten(), meta.matrix.iter_mut()) {
489 *o = *i;
490 }
491 }
492
493 Self::from_mut_ptr(buffer, meta)
494 }
495 }
496
497 #[doc(alias = "get_matrix")]
498 #[inline]
499 pub fn matrix(&self) -> &[[f32; 4]; 4] {
500 unsafe { &*(&self.0.matrix as *const [f32; 16] as *const [[f32; 4]; 4]) }
501 }
502
503 #[inline]
504 pub fn set_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
505 for (i, o) in Iterator::zip(matrix.iter().flatten(), self.0.matrix.iter_mut()) {
506 *o = *i;
507 }
508 }
509
510 #[doc(alias = "gst_video_affine_transformation_meta_apply_matrix")]
511 pub fn apply_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
512 unsafe {
513 ffi::gst_video_affine_transformation_meta_apply_matrix(
514 &mut self.0,
515 matrix as *const [[f32; 4]; 4] as *const [f32; 16],
516 );
517 }
518 }
519}
520
521unsafe impl MetaAPI for VideoAffineTransformationMeta {
522 type GstType = ffi::GstVideoAffineTransformationMeta;
523
524 #[doc(alias = "gst_video_affine_transformation_meta_api_get_type")]
525 #[inline]
526 fn meta_api() -> glib::Type {
527 unsafe { from_glib(val:ffi::gst_video_affine_transformation_meta_api_get_type()) }
528 }
529}
530
531impl fmt::Debug for VideoAffineTransformationMeta {
532 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
533 f&mut DebugStruct<'_, '_>.debug_struct("VideoAffineTransformationMeta")
534 .field(name:"matrix", &self.matrix())
535 .finish()
536 }
537}
538
539#[repr(transparent)]
540#[doc(alias = "GstVideoOverlayCompositionMeta")]
541pub struct VideoOverlayCompositionMeta(ffi::GstVideoOverlayCompositionMeta);
542
543unsafe impl Send for VideoOverlayCompositionMeta {}
544unsafe impl Sync for VideoOverlayCompositionMeta {}
545
546impl VideoOverlayCompositionMeta {
547 #[doc(alias = "gst_buffer_add_video_overlay_composition_meta")]
548 pub fn add<'a>(
549 buffer: &'a mut gst::BufferRef,
550 overlay: &crate::VideoOverlayComposition,
551 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
552 skip_assert_initialized!();
553 unsafe {
554 let meta = ffi::gst_buffer_add_video_overlay_composition_meta(
555 buffer.as_mut_ptr(),
556 overlay.as_mut_ptr(),
557 );
558
559 Self::from_mut_ptr(buffer, meta)
560 }
561 }
562
563 #[doc(alias = "get_overlay")]
564 #[inline]
565 pub fn overlay(&self) -> &crate::VideoOverlayCompositionRef {
566 unsafe { crate::VideoOverlayCompositionRef::from_ptr(self.0.overlay) }
567 }
568
569 #[doc(alias = "get_overlay_owned")]
570 #[inline]
571 pub fn overlay_owned(&self) -> crate::VideoOverlayComposition {
572 unsafe { from_glib_none(self.overlay().as_ptr()) }
573 }
574
575 #[inline]
576 pub fn set_overlay(&mut self, overlay: &crate::VideoOverlayComposition) {
577 #![allow(clippy::cast_ptr_alignment)]
578 unsafe {
579 gst::ffi::gst_mini_object_unref(self.0.overlay as *mut _);
580 self.0.overlay =
581 gst::ffi::gst_mini_object_ref(overlay.as_mut_ptr() as *mut _) as *mut _;
582 }
583 }
584}
585
586unsafe impl MetaAPI for VideoOverlayCompositionMeta {
587 type GstType = ffi::GstVideoOverlayCompositionMeta;
588
589 #[doc(alias = "gst_video_overlay_composition_meta_api_get_type")]
590 #[inline]
591 fn meta_api() -> glib::Type {
592 unsafe { from_glib(val:ffi::gst_video_overlay_composition_meta_api_get_type()) }
593 }
594}
595
596impl fmt::Debug for VideoOverlayCompositionMeta {
597 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
598 f&mut DebugStruct<'_, '_>.debug_struct("VideoOverlayCompositionMeta")
599 .field(name:"overlay", &self.overlay())
600 .finish()
601 }
602}
603
604#[cfg(feature = "v1_16")]
605#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
606#[repr(transparent)]
607#[doc(alias = "GstVideoCaptionMeta")]
608pub struct VideoCaptionMeta(ffi::GstVideoCaptionMeta);
609
610#[cfg(feature = "v1_16")]
611#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
612unsafe impl Send for VideoCaptionMeta {}
613#[cfg(feature = "v1_16")]
614#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
615unsafe impl Sync for VideoCaptionMeta {}
616
617#[cfg(feature = "v1_16")]
618#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
619impl VideoCaptionMeta {
620 #[doc(alias = "gst_buffer_add_video_caption_meta")]
621 pub fn add<'a>(
622 buffer: &'a mut gst::BufferRef,
623 caption_type: crate::VideoCaptionType,
624 data: &[u8],
625 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
626 skip_assert_initialized!();
627 assert!(!data.is_empty());
628 unsafe {
629 let meta = ffi::gst_buffer_add_video_caption_meta(
630 buffer.as_mut_ptr(),
631 caption_type.into_glib(),
632 data.as_ptr(),
633 data.len(),
634 );
635
636 Self::from_mut_ptr(buffer, meta)
637 }
638 }
639
640 #[doc(alias = "get_caption_type")]
641 #[inline]
642 pub fn caption_type(&self) -> crate::VideoCaptionType {
643 unsafe { from_glib(self.0.caption_type) }
644 }
645
646 #[doc(alias = "get_data")]
647 #[inline]
648 pub fn data(&self) -> &[u8] {
649 if self.0.size == 0 {
650 return &[];
651 }
652 unsafe {
653 use std::slice;
654
655 slice::from_raw_parts(self.0.data, self.0.size)
656 }
657 }
658}
659
660#[cfg(feature = "v1_16")]
661#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
662unsafe impl MetaAPI for VideoCaptionMeta {
663 type GstType = ffi::GstVideoCaptionMeta;
664
665 #[doc(alias = "gst_video_caption_meta_api_get_type")]
666 #[inline]
667 fn meta_api() -> glib::Type {
668 unsafe { from_glib(ffi::gst_video_caption_meta_api_get_type()) }
669 }
670}
671
672#[cfg(feature = "v1_16")]
673#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
674impl fmt::Debug for VideoCaptionMeta {
675 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
676 f.debug_struct("VideoCaptionMeta")
677 .field("caption_type", &self.caption_type())
678 .field("data", &self.data())
679 .finish()
680 }
681}
682
683#[cfg(feature = "v1_18")]
684#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
685#[repr(transparent)]
686#[doc(alias = "GstVideoAFDMeta")]
687pub struct VideoAFDMeta(ffi::GstVideoAFDMeta);
688
689#[cfg(feature = "v1_18")]
690#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
691unsafe impl Send for VideoAFDMeta {}
692#[cfg(feature = "v1_18")]
693#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
694unsafe impl Sync for VideoAFDMeta {}
695
696#[cfg(feature = "v1_18")]
697#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
698impl VideoAFDMeta {
699 #[doc(alias = "gst_buffer_add_video_afd_meta")]
700 pub fn add(
701 buffer: &mut gst::BufferRef,
702 field: u8,
703 spec: crate::VideoAFDSpec,
704 afd: crate::VideoAFDValue,
705 ) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
706 skip_assert_initialized!();
707
708 unsafe {
709 let meta = ffi::gst_buffer_add_video_afd_meta(
710 buffer.as_mut_ptr(),
711 field,
712 spec.into_glib(),
713 afd.into_glib(),
714 );
715
716 Self::from_mut_ptr(buffer, meta)
717 }
718 }
719
720 #[doc(alias = "get_field")]
721 #[inline]
722 pub fn field(&self) -> u8 {
723 self.0.field
724 }
725
726 #[doc(alias = "get_spec")]
727 #[inline]
728 pub fn spec(&self) -> crate::VideoAFDSpec {
729 unsafe { from_glib(self.0.spec) }
730 }
731
732 #[doc(alias = "get_afd")]
733 #[inline]
734 pub fn afd(&self) -> crate::VideoAFDValue {
735 unsafe { from_glib(self.0.afd) }
736 }
737}
738
739#[cfg(feature = "v1_18")]
740#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
741unsafe impl MetaAPI for VideoAFDMeta {
742 type GstType = ffi::GstVideoAFDMeta;
743
744 #[doc(alias = "gst_video_afd_meta_api_get_type")]
745 #[inline]
746 fn meta_api() -> glib::Type {
747 unsafe { from_glib(ffi::gst_video_afd_meta_api_get_type()) }
748 }
749}
750
751#[cfg(feature = "v1_18")]
752#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
753impl fmt::Debug for VideoAFDMeta {
754 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
755 f.debug_struct("VideoAFDMeta")
756 .field("field", &self.field())
757 .field("spec", &self.spec())
758 .field("afd", &self.afd())
759 .finish()
760 }
761}
762
763#[cfg(feature = "v1_18")]
764#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
765#[repr(transparent)]
766#[doc(alias = "GstVideoBarMeta")]
767pub struct VideoBarMeta(ffi::GstVideoBarMeta);
768
769#[cfg(feature = "v1_18")]
770#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
771unsafe impl Send for VideoBarMeta {}
772#[cfg(feature = "v1_18")]
773#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
774unsafe impl Sync for VideoBarMeta {}
775
776#[cfg(feature = "v1_18")]
777#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
778impl VideoBarMeta {
779 #[doc(alias = "gst_buffer_add_video_bar_meta")]
780 pub fn add(
781 buffer: &mut gst::BufferRef,
782 field: u8,
783 is_letterbox: bool,
784 bar_data1: u32,
785 bar_data2: u32,
786 ) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
787 skip_assert_initialized!();
788
789 unsafe {
790 let meta = ffi::gst_buffer_add_video_bar_meta(
791 buffer.as_mut_ptr(),
792 field,
793 is_letterbox.into_glib(),
794 bar_data1,
795 bar_data2,
796 );
797
798 Self::from_mut_ptr(buffer, meta)
799 }
800 }
801
802 #[doc(alias = "get_field")]
803 #[inline]
804 pub fn field(&self) -> u8 {
805 self.0.field
806 }
807
808 #[inline]
809 pub fn is_letterbox(&self) -> bool {
810 unsafe { from_glib(self.0.is_letterbox) }
811 }
812
813 #[doc(alias = "get_bar_data1")]
814 #[inline]
815 pub fn bar_data1(&self) -> u32 {
816 self.0.bar_data1
817 }
818
819 #[doc(alias = "get_bar_data2")]
820 #[inline]
821 pub fn bar_data2(&self) -> u32 {
822 self.0.bar_data2
823 }
824}
825
826#[cfg(feature = "v1_18")]
827#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
828unsafe impl MetaAPI for VideoBarMeta {
829 type GstType = ffi::GstVideoBarMeta;
830
831 #[doc(alias = "gst_video_bar_meta_api_get_type")]
832 #[inline]
833 fn meta_api() -> glib::Type {
834 unsafe { from_glib(ffi::gst_video_bar_meta_api_get_type()) }
835 }
836}
837
838#[cfg(feature = "v1_18")]
839#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
840impl fmt::Debug for VideoBarMeta {
841 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
842 f.debug_struct("VideoBarMeta")
843 .field("field", &self.field())
844 .field("is_letterbox", &self.is_letterbox())
845 .field("bar_data1", &self.bar_data1())
846 .field("bar_data2", &self.bar_data2())
847 .finish()
848 }
849}
850
851#[cfg(feature = "v1_20")]
852#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
853#[repr(transparent)]
854#[doc(alias = "GstVideoCodecAlphaMeta")]
855pub struct VideoCodecAlphaMeta(ffi::GstVideoCodecAlphaMeta);
856
857#[cfg(feature = "v1_20")]
858#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
859unsafe impl Send for VideoCodecAlphaMeta {}
860#[cfg(feature = "v1_20")]
861#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
862unsafe impl Sync for VideoCodecAlphaMeta {}
863
864#[cfg(feature = "v1_20")]
865#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
866impl VideoCodecAlphaMeta {
867 #[doc(alias = "gst_buffer_add_video_codec_alpha_meta")]
868 pub fn add(
869 buffer: &mut gst::BufferRef,
870 alpha_buffer: gst::Buffer,
871 ) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
872 skip_assert_initialized!();
873 unsafe {
874 let meta = ffi::gst_buffer_add_video_codec_alpha_meta(
875 buffer.as_mut_ptr(),
876 alpha_buffer.to_glib_none().0,
877 );
878
879 Self::from_mut_ptr(buffer, meta)
880 }
881 }
882
883 #[inline]
884 pub fn alpha_buffer(&self) -> &gst::BufferRef {
885 unsafe { gst::BufferRef::from_ptr(self.0.buffer) }
886 }
887
888 #[inline]
889 pub fn alpha_buffer_owned(&self) -> gst::Buffer {
890 unsafe { from_glib_none(self.0.buffer) }
891 }
892}
893
894#[cfg(feature = "v1_20")]
895#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
896unsafe impl MetaAPI for VideoCodecAlphaMeta {
897 type GstType = ffi::GstVideoCodecAlphaMeta;
898
899 #[doc(alias = "gst_video_codec_alpha_meta_api_get_type")]
900 #[inline]
901 fn meta_api() -> glib::Type {
902 unsafe { from_glib(ffi::gst_video_codec_alpha_meta_api_get_type()) }
903 }
904}
905
906#[cfg(feature = "v1_20")]
907#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
908impl fmt::Debug for VideoCodecAlphaMeta {
909 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
910 f.debug_struct("VideoCodecAlphaMeta")
911 .field("buffer", &self.alpha_buffer())
912 .finish()
913 }
914}
915
916#[cfg(feature = "v1_22")]
917#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
918#[repr(transparent)]
919#[doc(alias = "GstVideoSEIUserDataUnregisteredMeta")]
920pub struct VideoSeiUserDataUnregisteredMeta(ffi::GstVideoSEIUserDataUnregisteredMeta);
921
922#[cfg(feature = "v1_22")]
923#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
924unsafe impl Send for VideoSeiUserDataUnregisteredMeta {}
925#[cfg(feature = "v1_22")]
926#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
927unsafe impl Sync for VideoSeiUserDataUnregisteredMeta {}
928
929#[cfg(feature = "v1_22")]
930#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
931impl VideoSeiUserDataUnregisteredMeta {
932 #[doc(alias = "gst_buffer_add_video_sei_user_data_unregistered_meta")]
933 pub fn add<'a>(
934 buffer: &'a mut gst::BufferRef,
935 uuid: &[u8; 16],
936 data: &[u8],
937 ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
938 skip_assert_initialized!();
939 assert!(!data.is_empty());
940 unsafe {
941 let meta = ffi::gst_buffer_add_video_sei_user_data_unregistered_meta(
942 buffer.as_mut_ptr(),
943 mut_override(uuid.as_ptr()),
944 mut_override(data.as_ptr()),
945 data.len(),
946 );
947
948 Self::from_mut_ptr(buffer, meta)
949 }
950 }
951
952 #[doc(alias = "get_data")]
953 #[inline]
954 pub fn data(&self) -> &[u8] {
955 if self.0.size == 0 {
956 return &[];
957 }
958 // SAFETY: In the C API we have a pointer data and a size variable
959 // indicating the length of the data. Here we convert it to a size,
960 // making sure we read the size specified in the C API.
961 unsafe {
962 use std::slice;
963 slice::from_raw_parts(self.0.data, self.0.size)
964 }
965 }
966
967 #[doc(alias = "get_uuid")]
968 #[inline]
969 pub fn uuid(&self) -> [u8; 16] {
970 self.0.uuid
971 }
972}
973
974#[cfg(feature = "v1_22")]
975#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
976impl fmt::Debug for VideoSeiUserDataUnregisteredMeta {
977 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
978 f.debug_struct("VideoSeiUserDataUnregisteredMeta")
979 .field(
980 "uuid",
981 &format!("0x{:032X}", u128::from_be_bytes(self.uuid())),
982 )
983 .field("data", &self.data())
984 .finish()
985 }
986}
987
988#[cfg(feature = "v1_22")]
989#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
990unsafe impl MetaAPI for VideoSeiUserDataUnregisteredMeta {
991 type GstType = ffi::GstVideoSEIUserDataUnregisteredMeta;
992
993 #[doc(alias = "gst_video_sei_user_data_unregistered_meta_api_get_type")]
994 fn meta_api() -> glib::Type {
995 unsafe {
996 glib::translate::from_glib(ffi::gst_video_sei_user_data_unregistered_meta_api_get_type())
997 }
998 }
999}
1000
1001#[cfg(feature = "v1_24")]
1002#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1003#[repr(transparent)]
1004#[doc(alias = "GstAncillaryMeta")]
1005pub struct AncillaryMeta(ffi::GstAncillaryMeta);
1006
1007#[cfg(feature = "v1_24")]
1008#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1009unsafe impl Send for AncillaryMeta {}
1010#[cfg(feature = "v1_24")]
1011#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1012unsafe impl Sync for AncillaryMeta {}
1013
1014#[cfg(feature = "v1_24")]
1015#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1016impl AncillaryMeta {
1017 #[doc(alias = "gst_buffer_add_ancillary_meta")]
1018 pub fn add(buffer: &mut gst::BufferRef) -> gst::MetaRefMut<Self, gst::meta::Standalone> {
1019 skip_assert_initialized!();
1020 unsafe {
1021 let meta = ffi::gst_buffer_add_ancillary_meta(buffer.as_mut_ptr());
1022
1023 Self::from_mut_ptr(buffer, meta)
1024 }
1025 }
1026
1027 #[inline]
1028 pub fn field(&self) -> crate::AncillaryMetaField {
1029 unsafe { from_glib(self.0.field) }
1030 }
1031
1032 #[inline]
1033 pub fn set_field(&mut self, field: crate::AncillaryMetaField) {
1034 self.0.field = field.into_glib();
1035 }
1036
1037 #[inline]
1038 pub fn c_not_y_channel(&self) -> bool {
1039 unsafe { from_glib(self.0.c_not_y_channel) }
1040 }
1041
1042 #[inline]
1043 pub fn set_c_not_y_channel(&mut self, c_not_y_channel: bool) {
1044 self.0.c_not_y_channel = c_not_y_channel.into_glib();
1045 }
1046
1047 #[inline]
1048 pub fn line(&self) -> u16 {
1049 self.0.line
1050 }
1051
1052 #[inline]
1053 pub fn set_line(&mut self, line: u16) {
1054 self.0.line = line;
1055 }
1056
1057 #[inline]
1058 pub fn offset(&self) -> u16 {
1059 self.0.offset
1060 }
1061
1062 #[inline]
1063 pub fn set_offset(&mut self, offset: u16) {
1064 self.0.offset = offset;
1065 }
1066
1067 #[inline]
1068 pub fn did(&self) -> u16 {
1069 self.0.DID
1070 }
1071
1072 #[inline]
1073 pub fn set_did(&mut self, did: u16) {
1074 self.0.DID = did;
1075 }
1076
1077 #[inline]
1078 pub fn sdid_block_number(&self) -> u16 {
1079 self.0.SDID_block_number
1080 }
1081
1082 #[inline]
1083 pub fn set_sdid_block_number(&mut self, sdid_block_number: u16) {
1084 self.0.SDID_block_number = sdid_block_number;
1085 }
1086
1087 #[inline]
1088 pub fn data_count(&self) -> u16 {
1089 self.0.data_count
1090 }
1091
1092 #[inline]
1093 pub fn checksum(&self) -> u16 {
1094 self.0.checksum
1095 }
1096
1097 #[inline]
1098 pub fn set_checksum(&mut self, checksum: u16) {
1099 self.0.checksum = checksum;
1100 }
1101
1102 #[inline]
1103 pub fn data(&self) -> &[u16] {
1104 if self.0.data_count & 0xff == 0 {
1105 return &[];
1106 }
1107 unsafe {
1108 use std::slice;
1109
1110 slice::from_raw_parts(self.0.data, (self.0.data_count & 0xff) as usize)
1111 }
1112 }
1113
1114 #[inline]
1115 pub fn data_mut(&mut self) -> &mut [u16] {
1116 if self.0.data_count & 0xff == 0 {
1117 return &mut [];
1118 }
1119 unsafe {
1120 use std::slice;
1121
1122 slice::from_raw_parts_mut(self.0.data, (self.0.data_count & 0xff) as usize)
1123 }
1124 }
1125
1126 #[inline]
1127 pub fn set_data(&mut self, data: glib::Slice<u16>) {
1128 unsafe {
1129 assert!(data.len() < 256);
1130 self.0.data_count = data.len() as u16;
1131 self.0.data = data.into_glib_ptr();
1132 }
1133 }
1134
1135 #[inline]
1136 pub fn set_data_count_upper_two_bits(&mut self, upper_two_bits: u8) {
1137 assert!(upper_two_bits & !0x03 == 0);
1138 self.0.data_count = ((upper_two_bits as u16) << 8) | self.0.data_count & 0xff;
1139 }
1140}
1141
1142#[cfg(feature = "v1_24")]
1143#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1144unsafe impl MetaAPI for AncillaryMeta {
1145 type GstType = ffi::GstAncillaryMeta;
1146
1147 #[doc(alias = "gst_ancillary_meta_api_get_type")]
1148 #[inline]
1149 fn meta_api() -> glib::Type {
1150 unsafe { from_glib(ffi::gst_ancillary_meta_api_get_type()) }
1151 }
1152}
1153
1154#[cfg(feature = "v1_24")]
1155#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1156impl fmt::Debug for AncillaryMeta {
1157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1158 f.debug_struct("AncillaryMeta")
1159 .field("field", &self.field())
1160 .field("c_not_y_channel", &self.c_not_y_channel())
1161 .field("line", &self.line())
1162 .field("offset", &self.offset())
1163 .field("did", &self.did())
1164 .field("sdid_block_number", &self.sdid_block_number())
1165 .field("data_count", &self.data_count())
1166 .field("data", &self.data())
1167 .field("checksum", &self.checksum())
1168 .finish()
1169 }
1170}
1171
1172pub mod tags {
1173 gst::impl_meta_tag!(Video, crate::ffi::GST_META_TAG_VIDEO_STR);
1174 gst::impl_meta_tag!(Size, crate::ffi::GST_META_TAG_VIDEO_SIZE_STR);
1175 gst::impl_meta_tag!(Orientation, crate::ffi::GST_META_TAG_VIDEO_ORIENTATION_STR);
1176 gst::impl_meta_tag!(Colorspace, crate::ffi::GST_META_TAG_VIDEO_COLORSPACE_STR);
1177}
1178
1179#[derive(Debug, Clone, PartialEq, Eq)]
1180pub struct VideoMetaTransformScale<'a> {
1181 in_info: &'a crate::VideoInfo,
1182 out_info: &'a crate::VideoInfo,
1183}
1184
1185impl<'a> VideoMetaTransformScale<'a> {
1186 pub fn new(in_info: &'a crate::VideoInfo, out_info: &'a crate::VideoInfo) -> Self {
1187 skip_assert_initialized!();
1188 VideoMetaTransformScale { in_info, out_info }
1189 }
1190}
1191
1192unsafe impl<'a> gst::meta::MetaTransform<'a> for VideoMetaTransformScale<'a> {
1193 type GLibType = ffi::GstVideoMetaTransform;
1194
1195 #[doc(alias = "gst_video_meta_transform_scale_get_quark")]
1196 fn quark() -> glib::Quark {
1197 unsafe { from_glib(val:ffi::gst_video_meta_transform_scale_get_quark()) }
1198 }
1199
1200 fn to_raw<T: MetaAPI>(
1201 &self,
1202 _meta: &gst::MetaRef<T>,
1203 ) -> Result<ffi::GstVideoMetaTransform, glib::BoolError> {
1204 Ok(ffi::GstVideoMetaTransform {
1205 in_info: mut_override(self.in_info.to_glib_none().0),
1206 out_info: mut_override(self.out_info.to_glib_none().0),
1207 })
1208 }
1209}
1210
1211#[cfg(test)]
1212mod tests {
1213 use super::*;
1214
1215 #[test]
1216 fn test_add_get_meta() {
1217 gst::init().unwrap();
1218
1219 let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1220 {
1221 let meta = VideoMeta::add(
1222 buffer.get_mut().unwrap(),
1223 crate::VideoFrameFlags::empty(),
1224 crate::VideoFormat::Argb,
1225 320,
1226 240,
1227 )
1228 .unwrap();
1229 assert_eq!(meta.id(), 0);
1230 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1231 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1232 assert_eq!(meta.width(), 320);
1233 assert_eq!(meta.height(), 240);
1234 assert_eq!(meta.n_planes(), 1);
1235 assert_eq!(meta.offset(), &[0]);
1236 assert_eq!(meta.stride(), &[320 * 4]);
1237 assert!(meta.has_tag::<gst::meta::tags::Memory>());
1238 assert!(meta.has_tag::<tags::Video>());
1239 assert!(meta.has_tag::<tags::Colorspace>());
1240 assert!(meta.has_tag::<tags::Size>());
1241 }
1242
1243 {
1244 let meta = buffer.meta::<VideoMeta>().unwrap();
1245 assert_eq!(meta.id(), 0);
1246 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1247 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1248 assert_eq!(meta.width(), 320);
1249 assert_eq!(meta.height(), 240);
1250 assert_eq!(meta.n_planes(), 1);
1251 assert_eq!(meta.offset(), &[0]);
1252 assert_eq!(meta.stride(), &[320 * 4]);
1253 }
1254 }
1255
1256 #[test]
1257 fn test_add_full_get_meta() {
1258 gst::init().unwrap();
1259
1260 let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1261 {
1262 let meta = VideoMeta::add_full(
1263 buffer.get_mut().unwrap(),
1264 crate::VideoFrameFlags::empty(),
1265 crate::VideoFormat::Argb,
1266 320,
1267 240,
1268 &[0],
1269 &[320 * 4],
1270 )
1271 .unwrap();
1272 assert_eq!(meta.id(), 0);
1273 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1274 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1275 assert_eq!(meta.width(), 320);
1276 assert_eq!(meta.height(), 240);
1277 assert_eq!(meta.n_planes(), 1);
1278 assert_eq!(meta.offset(), &[0]);
1279 assert_eq!(meta.stride(), &[320 * 4]);
1280 }
1281
1282 {
1283 let meta = buffer.meta::<VideoMeta>().unwrap();
1284 assert_eq!(meta.id(), 0);
1285 assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1286 assert_eq!(meta.format(), crate::VideoFormat::Argb);
1287 assert_eq!(meta.width(), 320);
1288 assert_eq!(meta.height(), 240);
1289 assert_eq!(meta.n_planes(), 1);
1290 assert_eq!(meta.offset(), &[0]);
1291 assert_eq!(meta.stride(), &[320 * 4]);
1292 }
1293 }
1294
1295 #[test]
1296 #[cfg(feature = "v1_16")]
1297 fn test_add_full_alternate_interlacing() {
1298 gst::init().unwrap();
1299 let mut buffer = gst::Buffer::with_size(320 * 120 * 4).unwrap();
1300 VideoMeta::add_full(
1301 buffer.get_mut().unwrap(),
1302 crate::VideoFrameFlags::TOP_FIELD,
1303 crate::VideoFormat::Argb,
1304 320,
1305 240,
1306 &[0],
1307 &[320 * 4],
1308 )
1309 .unwrap();
1310 }
1311
1312 #[test]
1313 #[cfg(feature = "v1_18")]
1314 fn test_video_meta_alignment() {
1315 gst::init().unwrap();
1316
1317 let mut buffer = gst::Buffer::with_size(115200).unwrap();
1318 let meta = VideoMeta::add(
1319 buffer.get_mut().unwrap(),
1320 crate::VideoFrameFlags::empty(),
1321 crate::VideoFormat::Nv12,
1322 320,
1323 240,
1324 )
1325 .unwrap();
1326
1327 let alig = meta.alignment();
1328 assert_eq!(alig, crate::VideoAlignment::new(0, 0, 0, 0, &[0, 0, 0, 0]));
1329
1330 assert_eq!(meta.plane_size().unwrap(), [76800, 38400, 0, 0]);
1331 assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1332
1333 /* horizontal padding */
1334 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1335 .build()
1336 .expect("Failed to create VideoInfo");
1337 let mut alig = crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]);
1338 info.align(&mut alig).unwrap();
1339
1340 let mut meta = VideoMeta::add_full(
1341 buffer.get_mut().unwrap(),
1342 crate::VideoFrameFlags::empty(),
1343 crate::VideoFormat::Nv12,
1344 info.width(),
1345 info.height(),
1346 info.offset(),
1347 info.stride(),
1348 )
1349 .unwrap();
1350 meta.set_alignment(&alig).unwrap();
1351
1352 let alig = meta.alignment();
1353 assert_eq!(alig, crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]));
1354
1355 assert_eq!(meta.plane_size().unwrap(), [78720, 39360, 0, 0]);
1356 assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1357
1358 /* vertical alignment */
1359 let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1360 .build()
1361 .expect("Failed to create VideoInfo");
1362 let mut alig = crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]);
1363 info.align(&mut alig).unwrap();
1364
1365 let mut meta = VideoMeta::add_full(
1366 buffer.get_mut().unwrap(),
1367 crate::VideoFrameFlags::empty(),
1368 crate::VideoFormat::Nv12,
1369 info.width(),
1370 info.height(),
1371 info.offset(),
1372 info.stride(),
1373 )
1374 .unwrap();
1375 meta.set_alignment(&alig).unwrap();
1376
1377 let alig = meta.alignment();
1378 assert_eq!(alig, crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]));
1379
1380 assert_eq!(meta.plane_size().unwrap(), [79360, 39680, 0, 0]);
1381 assert_eq!(meta.plane_height().unwrap(), [248, 124, 0, 0]);
1382 }
1383
1384 #[test]
1385 #[cfg(feature = "v1_22")]
1386 fn test_get_video_sei_user_data_unregistered_meta() {
1387 gst::init().unwrap();
1388
1389 const META_UUID: &[u8; 16] = &[
1390 0x4D, 0x49, 0x53, 0x50, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x65, 0x63, 0x74, 0x69,
1391 0x6D, 0x65,
1392 ];
1393
1394 const META_DATA: &[u8] = &[
1395 0x1f, 0x00, 0x05, 0xff, 0x21, 0x7e, 0xff, 0x29, 0xb5, 0xff, 0xdc, 0x13,
1396 ];
1397
1398 let buffer_data = &[
1399 &[0x00, 0x00, 0x00, 0x20, 0x06, 0x05, 0x1c],
1400 META_UUID as &[u8],
1401 META_DATA,
1402 &[
1403 0x80, 0x00, 0x00, 0x00, 0x14, 0x65, 0x88, 0x84, 0x00, 0x10, 0xff, 0xfe, 0xf6, 0xf0,
1404 0xfe, 0x05, 0x36, 0x56, 0x04, 0x50, 0x96, 0x7b, 0x3f, 0x53, 0xe1,
1405 ],
1406 ]
1407 .concat();
1408
1409 let mut harness = gst_check::Harness::new("h264parse");
1410 harness.set_src_caps_str(r#"
1411 video/x-h264, stream-format=(string)avc,
1412 width=(int)1920, height=(int)1080, framerate=(fraction)25/1,
1413 bit-depth-chroma=(uint)8, parsed=(boolean)true,
1414 alignment=(string)au, profile=(string)high, level=(string)4,
1415 codec_data=(buffer)01640028ffe1001a67640028acb200f0044fcb080000030008000003019478c1924001000568ebccb22c
1416 "#);
1417 let buffer = gst::Buffer::from_slice(buffer_data.clone());
1418 let buffer = harness.push_and_pull(buffer).unwrap();
1419
1420 let meta = buffer.meta::<VideoSeiUserDataUnregisteredMeta>().unwrap();
1421 assert_eq!(meta.uuid(), *META_UUID);
1422 assert_eq!(meta.data(), META_DATA);
1423 assert_eq!(meta.data().len(), META_DATA.len());
1424 }
1425
1426 #[test]
1427 fn test_meta_video_transform() {
1428 gst::init().unwrap();
1429
1430 let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1431 let meta = VideoCropMeta::add(buffer.get_mut().unwrap(), (10, 10, 20, 20));
1432
1433 let mut buffer2 = gst::Buffer::with_size(640 * 480 * 4).unwrap();
1434
1435 let in_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 320, 240)
1436 .build()
1437 .unwrap();
1438 let out_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 640, 480)
1439 .build()
1440 .unwrap();
1441
1442 meta.transform(
1443 buffer2.get_mut().unwrap(),
1444 &VideoMetaTransformScale::new(&in_video_info, &out_video_info),
1445 )
1446 .unwrap();
1447
1448 let meta2 = buffer2.meta::<VideoCropMeta>().unwrap();
1449
1450 assert_eq!(meta2.rect(), (20, 20, 40, 40));
1451 }
1452}
1453