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
418#[must_use = "iterators are lazy and do nothing unless consumed"]
419pub struct ParamsIter<'a> {
420    _meta: &'a VideoRegionOfInterestMeta,
421    list: Option<ptr::NonNull<glib::ffi::GList>>,
422}
423
424impl<'a> Iterator for ParamsIter<'a> {
425    type Item = &'a gst::StructureRef;
426
427    fn next(&mut self) -> Option<&'a gst::StructureRef> {
428        match self.list {
429            None => None,
430            Some(list) => unsafe {
431                self.list = ptr::NonNull::new(list.as_ref().next);
432                let data = list.as_ref().data;
433
434                let s = gst::StructureRef::from_glib_borrow(data as *const gst::ffi::GstStructure);
435
436                Some(s)
437            },
438        }
439    }
440}
441
442impl std::iter::FusedIterator for ParamsIter<'_> {}
443
444unsafe impl MetaAPI for VideoRegionOfInterestMeta {
445    type GstType = ffi::GstVideoRegionOfInterestMeta;
446
447    #[doc(alias = "gst_video_region_of_interest_meta_api_get_type")]
448    #[inline]
449    fn meta_api() -> glib::Type {
450        unsafe { from_glib(ffi::gst_video_region_of_interest_meta_api_get_type()) }
451    }
452}
453
454impl fmt::Debug for VideoRegionOfInterestMeta {
455    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
456        f.debug_struct("VideoRegionOfInterestMeta")
457            .field("roi_type", &self.roi_type())
458            .field("rect", &self.rect())
459            .field("id", &self.id())
460            .field("parent_id", &self.parent_id())
461            .field("params", &self.params().collect::<Vec<_>>())
462            .finish()
463    }
464}
465
466#[repr(transparent)]
467#[doc(alias = "GstVideoAffineTransformationMeta")]
468pub struct VideoAffineTransformationMeta(ffi::GstVideoAffineTransformationMeta);
469
470unsafe impl Send for VideoAffineTransformationMeta {}
471unsafe impl Sync for VideoAffineTransformationMeta {}
472
473impl VideoAffineTransformationMeta {
474    #[doc(alias = "gst_buffer_add_meta")]
475    pub fn add<'a>(
476        buffer: &'a mut gst::BufferRef,
477        matrix: Option<&[[f32; 4]; 4]>,
478    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
479        skip_assert_initialized!();
480        unsafe {
481            let meta = gst::ffi::gst_buffer_add_meta(
482                buffer.as_mut_ptr(),
483                ffi::gst_video_affine_transformation_meta_get_info(),
484                ptr::null_mut(),
485            ) as *mut ffi::GstVideoAffineTransformationMeta;
486
487            if let Some(matrix) = matrix {
488                let meta = &mut *meta;
489                for (i, o) in Iterator::zip(matrix.iter().flatten(), meta.matrix.iter_mut()) {
490                    *o = *i;
491                }
492            }
493
494            Self::from_mut_ptr(buffer, meta)
495        }
496    }
497
498    #[doc(alias = "get_matrix")]
499    #[inline]
500    pub fn matrix(&self) -> &[[f32; 4]; 4] {
501        unsafe { &*(&self.0.matrix as *const [f32; 16] as *const [[f32; 4]; 4]) }
502    }
503
504    #[inline]
505    pub fn set_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
506        for (i, o) in Iterator::zip(matrix.iter().flatten(), self.0.matrix.iter_mut()) {
507            *o = *i;
508        }
509    }
510
511    #[doc(alias = "gst_video_affine_transformation_meta_apply_matrix")]
512    pub fn apply_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
513        unsafe {
514            ffi::gst_video_affine_transformation_meta_apply_matrix(
515                &mut self.0,
516                matrix as *const [[f32; 4]; 4] as *const [f32; 16],
517            );
518        }
519    }
520}
521
522unsafe impl MetaAPI for VideoAffineTransformationMeta {
523    type GstType = ffi::GstVideoAffineTransformationMeta;
524
525    #[doc(alias = "gst_video_affine_transformation_meta_api_get_type")]
526    #[inline]
527    fn meta_api() -> glib::Type {
528        unsafe { from_glib(ffi::gst_video_affine_transformation_meta_api_get_type()) }
529    }
530}
531
532impl fmt::Debug for VideoAffineTransformationMeta {
533    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534        f.debug_struct("VideoAffineTransformationMeta")
535            .field("matrix", &self.matrix())
536            .finish()
537    }
538}
539
540#[repr(transparent)]
541#[doc(alias = "GstVideoOverlayCompositionMeta")]
542pub struct VideoOverlayCompositionMeta(ffi::GstVideoOverlayCompositionMeta);
543
544unsafe impl Send for VideoOverlayCompositionMeta {}
545unsafe impl Sync for VideoOverlayCompositionMeta {}
546
547impl VideoOverlayCompositionMeta {
548    #[doc(alias = "gst_buffer_add_video_overlay_composition_meta")]
549    pub fn add<'a>(
550        buffer: &'a mut gst::BufferRef,
551        overlay: &crate::VideoOverlayComposition,
552    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
553        skip_assert_initialized!();
554        unsafe {
555            let meta = ffi::gst_buffer_add_video_overlay_composition_meta(
556                buffer.as_mut_ptr(),
557                overlay.as_mut_ptr(),
558            );
559
560            Self::from_mut_ptr(buffer, meta)
561        }
562    }
563
564    #[doc(alias = "get_overlay")]
565    #[inline]
566    pub fn overlay(&self) -> &crate::VideoOverlayCompositionRef {
567        unsafe { crate::VideoOverlayCompositionRef::from_ptr(self.0.overlay) }
568    }
569
570    #[doc(alias = "get_overlay_owned")]
571    #[inline]
572    pub fn overlay_owned(&self) -> crate::VideoOverlayComposition {
573        unsafe { from_glib_none(self.overlay().as_ptr()) }
574    }
575
576    #[inline]
577    pub fn set_overlay(&mut self, overlay: &crate::VideoOverlayComposition) {
578        #![allow(clippy::cast_ptr_alignment)]
579        unsafe {
580            gst::ffi::gst_mini_object_unref(self.0.overlay as *mut _);
581            self.0.overlay =
582                gst::ffi::gst_mini_object_ref(overlay.as_mut_ptr() as *mut _) as *mut _;
583        }
584    }
585}
586
587unsafe impl MetaAPI for VideoOverlayCompositionMeta {
588    type GstType = ffi::GstVideoOverlayCompositionMeta;
589
590    #[doc(alias = "gst_video_overlay_composition_meta_api_get_type")]
591    #[inline]
592    fn meta_api() -> glib::Type {
593        unsafe { from_glib(ffi::gst_video_overlay_composition_meta_api_get_type()) }
594    }
595}
596
597impl fmt::Debug for VideoOverlayCompositionMeta {
598    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
599        f.debug_struct("VideoOverlayCompositionMeta")
600            .field("overlay", &self.overlay())
601            .finish()
602    }
603}
604
605#[cfg(feature = "v1_16")]
606#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
607#[repr(transparent)]
608#[doc(alias = "GstVideoCaptionMeta")]
609pub struct VideoCaptionMeta(ffi::GstVideoCaptionMeta);
610
611#[cfg(feature = "v1_16")]
612#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
613unsafe impl Send for VideoCaptionMeta {}
614#[cfg(feature = "v1_16")]
615#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
616unsafe impl Sync for VideoCaptionMeta {}
617
618#[cfg(feature = "v1_16")]
619#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
620impl VideoCaptionMeta {
621    #[doc(alias = "gst_buffer_add_video_caption_meta")]
622    pub fn add<'a>(
623        buffer: &'a mut gst::BufferRef,
624        caption_type: crate::VideoCaptionType,
625        data: &[u8],
626    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
627        skip_assert_initialized!();
628        assert!(!data.is_empty());
629        unsafe {
630            let meta = ffi::gst_buffer_add_video_caption_meta(
631                buffer.as_mut_ptr(),
632                caption_type.into_glib(),
633                data.as_ptr(),
634                data.len(),
635            );
636
637            Self::from_mut_ptr(buffer, meta)
638        }
639    }
640
641    #[doc(alias = "get_caption_type")]
642    #[inline]
643    pub fn caption_type(&self) -> crate::VideoCaptionType {
644        unsafe { from_glib(self.0.caption_type) }
645    }
646
647    #[doc(alias = "get_data")]
648    #[inline]
649    pub fn data(&self) -> &[u8] {
650        if self.0.size == 0 {
651            return &[];
652        }
653        unsafe {
654            use std::slice;
655
656            slice::from_raw_parts(self.0.data, self.0.size)
657        }
658    }
659}
660
661#[cfg(feature = "v1_16")]
662#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
663unsafe impl MetaAPI for VideoCaptionMeta {
664    type GstType = ffi::GstVideoCaptionMeta;
665
666    #[doc(alias = "gst_video_caption_meta_api_get_type")]
667    #[inline]
668    fn meta_api() -> glib::Type {
669        unsafe { from_glib(ffi::gst_video_caption_meta_api_get_type()) }
670    }
671}
672
673#[cfg(feature = "v1_16")]
674#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
675impl fmt::Debug for VideoCaptionMeta {
676    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
677        f.debug_struct("VideoCaptionMeta")
678            .field("caption_type", &self.caption_type())
679            .field("data", &self.data())
680            .finish()
681    }
682}
683
684#[cfg(feature = "v1_18")]
685#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
686#[repr(transparent)]
687#[doc(alias = "GstVideoAFDMeta")]
688pub struct VideoAFDMeta(ffi::GstVideoAFDMeta);
689
690#[cfg(feature = "v1_18")]
691#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
692unsafe impl Send for VideoAFDMeta {}
693#[cfg(feature = "v1_18")]
694#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
695unsafe impl Sync for VideoAFDMeta {}
696
697#[cfg(feature = "v1_18")]
698#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
699impl VideoAFDMeta {
700    #[doc(alias = "gst_buffer_add_video_afd_meta")]
701    pub fn add(
702        buffer: &mut gst::BufferRef,
703        field: u8,
704        spec: crate::VideoAFDSpec,
705        afd: crate::VideoAFDValue,
706    ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
707        skip_assert_initialized!();
708
709        unsafe {
710            let meta = ffi::gst_buffer_add_video_afd_meta(
711                buffer.as_mut_ptr(),
712                field,
713                spec.into_glib(),
714                afd.into_glib(),
715            );
716
717            Self::from_mut_ptr(buffer, meta)
718        }
719    }
720
721    #[doc(alias = "get_field")]
722    #[inline]
723    pub fn field(&self) -> u8 {
724        self.0.field
725    }
726
727    #[doc(alias = "get_spec")]
728    #[inline]
729    pub fn spec(&self) -> crate::VideoAFDSpec {
730        unsafe { from_glib(self.0.spec) }
731    }
732
733    #[doc(alias = "get_afd")]
734    #[inline]
735    pub fn afd(&self) -> crate::VideoAFDValue {
736        unsafe { from_glib(self.0.afd) }
737    }
738}
739
740#[cfg(feature = "v1_18")]
741#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
742unsafe impl MetaAPI for VideoAFDMeta {
743    type GstType = ffi::GstVideoAFDMeta;
744
745    #[doc(alias = "gst_video_afd_meta_api_get_type")]
746    #[inline]
747    fn meta_api() -> glib::Type {
748        unsafe { from_glib(ffi::gst_video_afd_meta_api_get_type()) }
749    }
750}
751
752#[cfg(feature = "v1_18")]
753#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
754impl fmt::Debug for VideoAFDMeta {
755    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
756        f.debug_struct("VideoAFDMeta")
757            .field("field", &self.field())
758            .field("spec", &self.spec())
759            .field("afd", &self.afd())
760            .finish()
761    }
762}
763
764#[cfg(feature = "v1_18")]
765#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
766#[repr(transparent)]
767#[doc(alias = "GstVideoBarMeta")]
768pub struct VideoBarMeta(ffi::GstVideoBarMeta);
769
770#[cfg(feature = "v1_18")]
771#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
772unsafe impl Send for VideoBarMeta {}
773#[cfg(feature = "v1_18")]
774#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
775unsafe impl Sync for VideoBarMeta {}
776
777#[cfg(feature = "v1_18")]
778#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
779impl VideoBarMeta {
780    #[doc(alias = "gst_buffer_add_video_bar_meta")]
781    pub fn add(
782        buffer: &mut gst::BufferRef,
783        field: u8,
784        is_letterbox: bool,
785        bar_data1: u32,
786        bar_data2: u32,
787    ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
788        skip_assert_initialized!();
789
790        unsafe {
791            let meta = ffi::gst_buffer_add_video_bar_meta(
792                buffer.as_mut_ptr(),
793                field,
794                is_letterbox.into_glib(),
795                bar_data1,
796                bar_data2,
797            );
798
799            Self::from_mut_ptr(buffer, meta)
800        }
801    }
802
803    #[doc(alias = "get_field")]
804    #[inline]
805    pub fn field(&self) -> u8 {
806        self.0.field
807    }
808
809    #[inline]
810    pub fn is_letterbox(&self) -> bool {
811        unsafe { from_glib(self.0.is_letterbox) }
812    }
813
814    #[doc(alias = "get_bar_data1")]
815    #[inline]
816    pub fn bar_data1(&self) -> u32 {
817        self.0.bar_data1
818    }
819
820    #[doc(alias = "get_bar_data2")]
821    #[inline]
822    pub fn bar_data2(&self) -> u32 {
823        self.0.bar_data2
824    }
825}
826
827#[cfg(feature = "v1_18")]
828#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
829unsafe impl MetaAPI for VideoBarMeta {
830    type GstType = ffi::GstVideoBarMeta;
831
832    #[doc(alias = "gst_video_bar_meta_api_get_type")]
833    #[inline]
834    fn meta_api() -> glib::Type {
835        unsafe { from_glib(ffi::gst_video_bar_meta_api_get_type()) }
836    }
837}
838
839#[cfg(feature = "v1_18")]
840#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
841impl fmt::Debug for VideoBarMeta {
842    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
843        f.debug_struct("VideoBarMeta")
844            .field("field", &self.field())
845            .field("is_letterbox", &self.is_letterbox())
846            .field("bar_data1", &self.bar_data1())
847            .field("bar_data2", &self.bar_data2())
848            .finish()
849    }
850}
851
852#[cfg(feature = "v1_20")]
853#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
854#[repr(transparent)]
855#[doc(alias = "GstVideoCodecAlphaMeta")]
856pub struct VideoCodecAlphaMeta(ffi::GstVideoCodecAlphaMeta);
857
858#[cfg(feature = "v1_20")]
859#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
860unsafe impl Send for VideoCodecAlphaMeta {}
861#[cfg(feature = "v1_20")]
862#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
863unsafe impl Sync for VideoCodecAlphaMeta {}
864
865#[cfg(feature = "v1_20")]
866#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
867impl VideoCodecAlphaMeta {
868    #[doc(alias = "gst_buffer_add_video_codec_alpha_meta")]
869    pub fn add(
870        buffer: &mut gst::BufferRef,
871        alpha_buffer: gst::Buffer,
872    ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
873        skip_assert_initialized!();
874        unsafe {
875            let meta = ffi::gst_buffer_add_video_codec_alpha_meta(
876                buffer.as_mut_ptr(),
877                alpha_buffer.to_glib_none().0,
878            );
879
880            Self::from_mut_ptr(buffer, meta)
881        }
882    }
883
884    #[inline]
885    pub fn alpha_buffer(&self) -> &gst::BufferRef {
886        unsafe { gst::BufferRef::from_ptr(self.0.buffer) }
887    }
888
889    #[inline]
890    pub fn alpha_buffer_owned(&self) -> gst::Buffer {
891        unsafe { from_glib_none(self.0.buffer) }
892    }
893}
894
895#[cfg(feature = "v1_20")]
896#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
897unsafe impl MetaAPI for VideoCodecAlphaMeta {
898    type GstType = ffi::GstVideoCodecAlphaMeta;
899
900    #[doc(alias = "gst_video_codec_alpha_meta_api_get_type")]
901    #[inline]
902    fn meta_api() -> glib::Type {
903        unsafe { from_glib(ffi::gst_video_codec_alpha_meta_api_get_type()) }
904    }
905}
906
907#[cfg(feature = "v1_20")]
908#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
909impl fmt::Debug for VideoCodecAlphaMeta {
910    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
911        f.debug_struct("VideoCodecAlphaMeta")
912            .field("buffer", &self.alpha_buffer())
913            .finish()
914    }
915}
916
917#[cfg(feature = "v1_22")]
918#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
919#[repr(transparent)]
920#[doc(alias = "GstVideoSEIUserDataUnregisteredMeta")]
921pub struct VideoSeiUserDataUnregisteredMeta(ffi::GstVideoSEIUserDataUnregisteredMeta);
922
923#[cfg(feature = "v1_22")]
924#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
925unsafe impl Send for VideoSeiUserDataUnregisteredMeta {}
926#[cfg(feature = "v1_22")]
927#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
928unsafe impl Sync for VideoSeiUserDataUnregisteredMeta {}
929
930#[cfg(feature = "v1_22")]
931#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
932impl VideoSeiUserDataUnregisteredMeta {
933    #[doc(alias = "gst_buffer_add_video_sei_user_data_unregistered_meta")]
934    pub fn add<'a>(
935        buffer: &'a mut gst::BufferRef,
936        uuid: &[u8; 16],
937        data: &[u8],
938    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
939        skip_assert_initialized!();
940        assert!(!data.is_empty());
941        unsafe {
942            let meta = ffi::gst_buffer_add_video_sei_user_data_unregistered_meta(
943                buffer.as_mut_ptr(),
944                mut_override(uuid.as_ptr()),
945                mut_override(data.as_ptr()),
946                data.len(),
947            );
948
949            Self::from_mut_ptr(buffer, meta)
950        }
951    }
952
953    #[doc(alias = "get_data")]
954    #[inline]
955    pub fn data(&self) -> &[u8] {
956        if self.0.size == 0 {
957            return &[];
958        }
959        // SAFETY: In the C API we have a pointer data and a size variable
960        // indicating the length of the data. Here we convert it to a size,
961        // making sure we read the size specified in the C API.
962        unsafe {
963            use std::slice;
964            slice::from_raw_parts(self.0.data, self.0.size)
965        }
966    }
967
968    #[doc(alias = "get_uuid")]
969    #[inline]
970    pub fn uuid(&self) -> [u8; 16] {
971        self.0.uuid
972    }
973}
974
975#[cfg(feature = "v1_22")]
976#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
977impl fmt::Debug for VideoSeiUserDataUnregisteredMeta {
978    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
979        f.debug_struct("VideoSeiUserDataUnregisteredMeta")
980            .field(
981                "uuid",
982                &format!("0x{:032X}", u128::from_be_bytes(self.uuid())),
983            )
984            .field("data", &self.data())
985            .finish()
986    }
987}
988
989#[cfg(feature = "v1_22")]
990#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
991unsafe impl MetaAPI for VideoSeiUserDataUnregisteredMeta {
992    type GstType = ffi::GstVideoSEIUserDataUnregisteredMeta;
993
994    #[doc(alias = "gst_video_sei_user_data_unregistered_meta_api_get_type")]
995    fn meta_api() -> glib::Type {
996        unsafe {
997            glib::translate::from_glib(ffi::gst_video_sei_user_data_unregistered_meta_api_get_type())
998        }
999    }
1000}
1001
1002#[cfg(feature = "v1_24")]
1003#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1004#[repr(transparent)]
1005#[doc(alias = "GstAncillaryMeta")]
1006pub struct AncillaryMeta(ffi::GstAncillaryMeta);
1007
1008#[cfg(feature = "v1_24")]
1009#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1010unsafe impl Send for AncillaryMeta {}
1011#[cfg(feature = "v1_24")]
1012#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1013unsafe impl Sync for AncillaryMeta {}
1014
1015#[cfg(feature = "v1_24")]
1016#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1017impl AncillaryMeta {
1018    #[doc(alias = "gst_buffer_add_ancillary_meta")]
1019    pub fn add(buffer: &mut gst::BufferRef) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
1020        skip_assert_initialized!();
1021        unsafe {
1022            let meta = ffi::gst_buffer_add_ancillary_meta(buffer.as_mut_ptr());
1023
1024            Self::from_mut_ptr(buffer, meta)
1025        }
1026    }
1027
1028    #[inline]
1029    pub fn field(&self) -> crate::AncillaryMetaField {
1030        unsafe { from_glib(self.0.field) }
1031    }
1032
1033    #[inline]
1034    pub fn set_field(&mut self, field: crate::AncillaryMetaField) {
1035        self.0.field = field.into_glib();
1036    }
1037
1038    #[inline]
1039    pub fn c_not_y_channel(&self) -> bool {
1040        unsafe { from_glib(self.0.c_not_y_channel) }
1041    }
1042
1043    #[inline]
1044    pub fn set_c_not_y_channel(&mut self, c_not_y_channel: bool) {
1045        self.0.c_not_y_channel = c_not_y_channel.into_glib();
1046    }
1047
1048    #[inline]
1049    pub fn line(&self) -> u16 {
1050        self.0.line
1051    }
1052
1053    #[inline]
1054    pub fn set_line(&mut self, line: u16) {
1055        self.0.line = line;
1056    }
1057
1058    #[inline]
1059    pub fn offset(&self) -> u16 {
1060        self.0.offset
1061    }
1062
1063    #[inline]
1064    pub fn set_offset(&mut self, offset: u16) {
1065        self.0.offset = offset;
1066    }
1067
1068    #[inline]
1069    pub fn did(&self) -> u16 {
1070        self.0.DID
1071    }
1072
1073    #[inline]
1074    pub fn set_did(&mut self, did: u16) {
1075        self.0.DID = did;
1076    }
1077
1078    #[inline]
1079    pub fn sdid_block_number(&self) -> u16 {
1080        self.0.SDID_block_number
1081    }
1082
1083    #[inline]
1084    pub fn set_sdid_block_number(&mut self, sdid_block_number: u16) {
1085        self.0.SDID_block_number = sdid_block_number;
1086    }
1087
1088    #[inline]
1089    pub fn data_count(&self) -> u16 {
1090        self.0.data_count
1091    }
1092
1093    #[inline]
1094    pub fn checksum(&self) -> u16 {
1095        self.0.checksum
1096    }
1097
1098    #[inline]
1099    pub fn set_checksum(&mut self, checksum: u16) {
1100        self.0.checksum = checksum;
1101    }
1102
1103    #[inline]
1104    pub fn data(&self) -> &[u16] {
1105        if self.0.data_count & 0xff == 0 {
1106            return &[];
1107        }
1108        unsafe {
1109            use std::slice;
1110
1111            slice::from_raw_parts(self.0.data, (self.0.data_count & 0xff) as usize)
1112        }
1113    }
1114
1115    #[inline]
1116    pub fn data_mut(&mut self) -> &mut [u16] {
1117        if self.0.data_count & 0xff == 0 {
1118            return &mut [];
1119        }
1120        unsafe {
1121            use std::slice;
1122
1123            slice::from_raw_parts_mut(self.0.data, (self.0.data_count & 0xff) as usize)
1124        }
1125    }
1126
1127    #[inline]
1128    pub fn set_data(&mut self, data: glib::Slice<u16>) {
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    #[inline]
1135    pub fn set_data_count_upper_two_bits(&mut self, upper_two_bits: u8) {
1136        assert!(upper_two_bits & !0x03 == 0);
1137        self.0.data_count = ((upper_two_bits as u16) << 8) | self.0.data_count & 0xff;
1138    }
1139}
1140
1141#[cfg(feature = "v1_24")]
1142#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1143unsafe impl MetaAPI for AncillaryMeta {
1144    type GstType = ffi::GstAncillaryMeta;
1145
1146    #[doc(alias = "gst_ancillary_meta_api_get_type")]
1147    #[inline]
1148    fn meta_api() -> glib::Type {
1149        unsafe { from_glib(ffi::gst_ancillary_meta_api_get_type()) }
1150    }
1151}
1152
1153#[cfg(feature = "v1_24")]
1154#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1155impl fmt::Debug for AncillaryMeta {
1156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1157        f.debug_struct("AncillaryMeta")
1158            .field("field", &self.field())
1159            .field("c_not_y_channel", &self.c_not_y_channel())
1160            .field("line", &self.line())
1161            .field("offset", &self.offset())
1162            .field("did", &self.did())
1163            .field("sdid_block_number", &self.sdid_block_number())
1164            .field("data_count", &self.data_count())
1165            .field("data", &self.data())
1166            .field("checksum", &self.checksum())
1167            .finish()
1168    }
1169}
1170
1171pub mod tags {
1172    gst::impl_meta_tag!(Video, crate::ffi::GST_META_TAG_VIDEO_STR);
1173    gst::impl_meta_tag!(Size, crate::ffi::GST_META_TAG_VIDEO_SIZE_STR);
1174    gst::impl_meta_tag!(Orientation, crate::ffi::GST_META_TAG_VIDEO_ORIENTATION_STR);
1175    gst::impl_meta_tag!(Colorspace, crate::ffi::GST_META_TAG_VIDEO_COLORSPACE_STR);
1176}
1177
1178#[derive(Debug, Clone, PartialEq, Eq)]
1179pub struct VideoMetaTransformScale<'a> {
1180    in_info: &'a crate::VideoInfo,
1181    out_info: &'a crate::VideoInfo,
1182}
1183
1184impl<'a> VideoMetaTransformScale<'a> {
1185    pub fn new(in_info: &'a crate::VideoInfo, out_info: &'a crate::VideoInfo) -> Self {
1186        skip_assert_initialized!();
1187        VideoMetaTransformScale { in_info, out_info }
1188    }
1189}
1190
1191unsafe impl<'a> gst::meta::MetaTransform<'a> for VideoMetaTransformScale<'a> {
1192    type GLibType = ffi::GstVideoMetaTransform;
1193
1194    #[doc(alias = "gst_video_meta_transform_scale_get_quark")]
1195    fn quark() -> glib::Quark {
1196        unsafe { from_glib(ffi::gst_video_meta_transform_scale_get_quark()) }
1197    }
1198
1199    fn to_raw<T: MetaAPI>(
1200        &self,
1201        _meta: &gst::MetaRef<T>,
1202    ) -> Result<ffi::GstVideoMetaTransform, glib::BoolError> {
1203        Ok(ffi::GstVideoMetaTransform {
1204            in_info: mut_override(self.in_info.to_glib_none().0),
1205            out_info: mut_override(self.out_info.to_glib_none().0),
1206        })
1207    }
1208}
1209
1210#[cfg(test)]
1211mod tests {
1212    use super::*;
1213
1214    #[test]
1215    fn test_add_get_meta() {
1216        gst::init().unwrap();
1217
1218        let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1219        {
1220            let meta = VideoMeta::add(
1221                buffer.get_mut().unwrap(),
1222                crate::VideoFrameFlags::empty(),
1223                crate::VideoFormat::Argb,
1224                320,
1225                240,
1226            )
1227            .unwrap();
1228            assert_eq!(meta.id(), 0);
1229            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1230            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1231            assert_eq!(meta.width(), 320);
1232            assert_eq!(meta.height(), 240);
1233            assert_eq!(meta.n_planes(), 1);
1234            assert_eq!(meta.offset(), &[0]);
1235            assert_eq!(meta.stride(), &[320 * 4]);
1236            assert!(meta.has_tag::<gst::meta::tags::Memory>());
1237            assert!(meta.has_tag::<tags::Video>());
1238            assert!(meta.has_tag::<tags::Colorspace>());
1239            assert!(meta.has_tag::<tags::Size>());
1240        }
1241
1242        {
1243            let meta = buffer.meta::<VideoMeta>().unwrap();
1244            assert_eq!(meta.id(), 0);
1245            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1246            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1247            assert_eq!(meta.width(), 320);
1248            assert_eq!(meta.height(), 240);
1249            assert_eq!(meta.n_planes(), 1);
1250            assert_eq!(meta.offset(), &[0]);
1251            assert_eq!(meta.stride(), &[320 * 4]);
1252        }
1253    }
1254
1255    #[test]
1256    fn test_add_full_get_meta() {
1257        gst::init().unwrap();
1258
1259        let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1260        {
1261            let meta = VideoMeta::add_full(
1262                buffer.get_mut().unwrap(),
1263                crate::VideoFrameFlags::empty(),
1264                crate::VideoFormat::Argb,
1265                320,
1266                240,
1267                &[0],
1268                &[320 * 4],
1269            )
1270            .unwrap();
1271            assert_eq!(meta.id(), 0);
1272            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1273            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1274            assert_eq!(meta.width(), 320);
1275            assert_eq!(meta.height(), 240);
1276            assert_eq!(meta.n_planes(), 1);
1277            assert_eq!(meta.offset(), &[0]);
1278            assert_eq!(meta.stride(), &[320 * 4]);
1279        }
1280
1281        {
1282            let meta = buffer.meta::<VideoMeta>().unwrap();
1283            assert_eq!(meta.id(), 0);
1284            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1285            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1286            assert_eq!(meta.width(), 320);
1287            assert_eq!(meta.height(), 240);
1288            assert_eq!(meta.n_planes(), 1);
1289            assert_eq!(meta.offset(), &[0]);
1290            assert_eq!(meta.stride(), &[320 * 4]);
1291        }
1292    }
1293
1294    #[test]
1295    #[cfg(feature = "v1_16")]
1296    fn test_add_full_alternate_interlacing() {
1297        gst::init().unwrap();
1298        let mut buffer = gst::Buffer::with_size(320 * 120 * 4).unwrap();
1299        VideoMeta::add_full(
1300            buffer.get_mut().unwrap(),
1301            crate::VideoFrameFlags::TOP_FIELD,
1302            crate::VideoFormat::Argb,
1303            320,
1304            240,
1305            &[0],
1306            &[320 * 4],
1307        )
1308        .unwrap();
1309    }
1310
1311    #[test]
1312    #[cfg(feature = "v1_18")]
1313    fn test_video_meta_alignment() {
1314        gst::init().unwrap();
1315
1316        let mut buffer = gst::Buffer::with_size(115200).unwrap();
1317        let meta = VideoMeta::add(
1318            buffer.get_mut().unwrap(),
1319            crate::VideoFrameFlags::empty(),
1320            crate::VideoFormat::Nv12,
1321            320,
1322            240,
1323        )
1324        .unwrap();
1325
1326        let alig = meta.alignment();
1327        assert_eq!(alig, crate::VideoAlignment::new(0, 0, 0, 0, &[0, 0, 0, 0]));
1328
1329        assert_eq!(meta.plane_size().unwrap(), [76800, 38400, 0, 0]);
1330        assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1331
1332        /* horizontal padding */
1333        let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1334            .build()
1335            .expect("Failed to create VideoInfo");
1336        let mut alig = crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]);
1337        info.align(&mut alig).unwrap();
1338
1339        let mut meta = VideoMeta::add_full(
1340            buffer.get_mut().unwrap(),
1341            crate::VideoFrameFlags::empty(),
1342            crate::VideoFormat::Nv12,
1343            info.width(),
1344            info.height(),
1345            info.offset(),
1346            info.stride(),
1347        )
1348        .unwrap();
1349        meta.set_alignment(&alig).unwrap();
1350
1351        let alig = meta.alignment();
1352        assert_eq!(alig, crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]));
1353
1354        assert_eq!(meta.plane_size().unwrap(), [78720, 39360, 0, 0]);
1355        assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1356
1357        /* vertical alignment */
1358        let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1359            .build()
1360            .expect("Failed to create VideoInfo");
1361        let mut alig = crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]);
1362        info.align(&mut alig).unwrap();
1363
1364        let mut meta = VideoMeta::add_full(
1365            buffer.get_mut().unwrap(),
1366            crate::VideoFrameFlags::empty(),
1367            crate::VideoFormat::Nv12,
1368            info.width(),
1369            info.height(),
1370            info.offset(),
1371            info.stride(),
1372        )
1373        .unwrap();
1374        meta.set_alignment(&alig).unwrap();
1375
1376        let alig = meta.alignment();
1377        assert_eq!(alig, crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]));
1378
1379        assert_eq!(meta.plane_size().unwrap(), [79360, 39680, 0, 0]);
1380        assert_eq!(meta.plane_height().unwrap(), [248, 124, 0, 0]);
1381    }
1382
1383    #[test]
1384    #[cfg(feature = "v1_22")]
1385    fn test_get_video_sei_user_data_unregistered_meta() {
1386        gst::init().unwrap();
1387
1388        const META_UUID: &[u8; 16] = &[
1389            0x4D, 0x49, 0x53, 0x50, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x65, 0x63, 0x74, 0x69,
1390            0x6D, 0x65,
1391        ];
1392
1393        const META_DATA: &[u8] = &[
1394            0x1f, 0x00, 0x05, 0xff, 0x21, 0x7e, 0xff, 0x29, 0xb5, 0xff, 0xdc, 0x13,
1395        ];
1396
1397        let buffer_data = &[
1398            &[0x00, 0x00, 0x00, 0x20, 0x06, 0x05, 0x1c],
1399            META_UUID as &[u8],
1400            META_DATA,
1401            &[
1402                0x80, 0x00, 0x00, 0x00, 0x14, 0x65, 0x88, 0x84, 0x00, 0x10, 0xff, 0xfe, 0xf6, 0xf0,
1403                0xfe, 0x05, 0x36, 0x56, 0x04, 0x50, 0x96, 0x7b, 0x3f, 0x53, 0xe1,
1404            ],
1405        ]
1406        .concat();
1407
1408        let mut harness = gst_check::Harness::new("h264parse");
1409        harness.set_src_caps_str(r#"
1410            video/x-h264, stream-format=(string)avc,
1411            width=(int)1920, height=(int)1080, framerate=(fraction)25/1,
1412            bit-depth-chroma=(uint)8, parsed=(boolean)true,
1413            alignment=(string)au, profile=(string)high, level=(string)4,
1414            codec_data=(buffer)01640028ffe1001a67640028acb200f0044fcb080000030008000003019478c1924001000568ebccb22c
1415        "#);
1416        let buffer = gst::Buffer::from_slice(buffer_data.clone());
1417        let buffer = harness.push_and_pull(buffer).unwrap();
1418
1419        let meta = buffer.meta::<VideoSeiUserDataUnregisteredMeta>().unwrap();
1420        assert_eq!(meta.uuid(), *META_UUID);
1421        assert_eq!(meta.data(), META_DATA);
1422        assert_eq!(meta.data().len(), META_DATA.len());
1423    }
1424
1425    #[test]
1426    fn test_meta_video_transform() {
1427        gst::init().unwrap();
1428
1429        let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1430        let meta = VideoCropMeta::add(buffer.get_mut().unwrap(), (10, 10, 20, 20));
1431
1432        let mut buffer2 = gst::Buffer::with_size(640 * 480 * 4).unwrap();
1433
1434        let in_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 320, 240)
1435            .build()
1436            .unwrap();
1437        let out_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 640, 480)
1438            .build()
1439            .unwrap();
1440
1441        meta.transform(
1442            buffer2.get_mut().unwrap(),
1443            &VideoMetaTransformScale::new(&in_video_info, &out_video_info),
1444        )
1445        .unwrap();
1446
1447        let meta2 = buffer2.meta::<VideoCropMeta>().unwrap();
1448
1449        assert_eq!(meta2.rect(), (20, 20, 40, 40));
1450    }
1451}