gstreamer_video/
video_meta.rs

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