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