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