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