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