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