Skip to main content

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    ///
294    /// # Deprecated since 1.28
295    ///
296    /// Use [`set_alignment_full()`][Self::set_alignment_full()] instead
297    /// ## `alignment`
298    /// a `GstVideoAlignment`
299    ///
300    /// # Returns
301    ///
302    /// [`true`] if `alignment`'s meta has been updated, [`false`] if not
303    #[cfg(feature = "v1_18")]
304    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
305    #[doc(alias = "gst_video_meta_set_alignment")]
306    #[doc(alias = "gst_video_meta_set_alignment_full")]
307    pub fn set_alignment(
308        &mut self,
309        alignment: &crate::VideoAlignment,
310    ) -> Result<(), glib::BoolError> {
311        #[cfg(feature = "v1_28")]
312        unsafe {
313            glib::result_from_gboolean!(
314                ffi::gst_video_meta_set_alignment_full(&mut self.0, &alignment.0),
315                "Failed to set alignment on VideoMeta"
316            )
317        }
318        #[cfg(not(feature = "v1_28"))]
319        unsafe {
320            glib::result_from_gboolean!(
321                ffi::gst_video_meta_set_alignment(&mut self.0, alignment.0),
322                "Failed to set alignment on VideoMeta"
323            )
324        }
325    }
326}
327
328unsafe impl MetaAPI for VideoMeta {
329    type GstType = ffi::GstVideoMeta;
330
331    #[doc(alias = "gst_video_meta_api_get_type")]
332    #[inline]
333    fn meta_api() -> glib::Type {
334        unsafe { from_glib(ffi::gst_video_meta_api_get_type()) }
335    }
336}
337
338impl fmt::Debug for VideoMeta {
339    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340        f.debug_struct("VideoMeta")
341            .field("id", &self.id())
342            .field("video_frame_flags", &self.video_frame_flags())
343            .field("format", &self.format())
344            .field("width", &self.width())
345            .field("height", &self.height())
346            .field("n_planes", &self.n_planes())
347            .field("offset", &self.offset())
348            .field("stride", &self.stride())
349            .finish()
350    }
351}
352
353#[repr(transparent)]
354#[doc(alias = "GstVideoCropMeta")]
355pub struct VideoCropMeta(ffi::GstVideoCropMeta);
356
357unsafe impl Send for VideoCropMeta {}
358unsafe impl Sync for VideoCropMeta {}
359
360impl VideoCropMeta {
361    #[doc(alias = "gst_buffer_add_meta")]
362    pub fn add(
363        buffer: &mut gst::BufferRef,
364        rect: (u32, u32, u32, u32),
365    ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
366        skip_assert_initialized!();
367        unsafe {
368            let meta = gst::ffi::gst_buffer_add_meta(
369                buffer.as_mut_ptr(),
370                ffi::gst_video_crop_meta_get_info(),
371                ptr::null_mut(),
372            ) as *mut ffi::GstVideoCropMeta;
373
374            {
375                let meta = &mut *meta;
376                meta.x = rect.0;
377                meta.y = rect.1;
378                meta.width = rect.2;
379                meta.height = rect.3;
380            }
381
382            Self::from_mut_ptr(buffer, meta)
383        }
384    }
385
386    #[doc(alias = "get_rect")]
387    #[inline]
388    pub fn rect(&self) -> (u32, u32, u32, u32) {
389        (self.0.x, self.0.y, self.0.width, self.0.height)
390    }
391
392    #[inline]
393    pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
394        self.0.x = rect.0;
395        self.0.y = rect.1;
396        self.0.width = rect.2;
397        self.0.height = rect.3;
398    }
399}
400
401unsafe impl MetaAPI for VideoCropMeta {
402    type GstType = ffi::GstVideoCropMeta;
403
404    #[doc(alias = "gst_video_crop_meta_api_get_type")]
405    #[inline]
406    fn meta_api() -> glib::Type {
407        unsafe { from_glib(ffi::gst_video_crop_meta_api_get_type()) }
408    }
409}
410
411impl fmt::Debug for VideoCropMeta {
412    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413        f.debug_struct("VideoCropMeta")
414            .field("rect", &self.rect())
415            .finish()
416    }
417}
418
419#[repr(transparent)]
420#[doc(alias = "GstVideoRegionOfInterestMeta")]
421pub struct VideoRegionOfInterestMeta(ffi::GstVideoRegionOfInterestMeta);
422
423unsafe impl Send for VideoRegionOfInterestMeta {}
424unsafe impl Sync for VideoRegionOfInterestMeta {}
425
426impl VideoRegionOfInterestMeta {
427    #[doc(alias = "gst_buffer_add_video_region_of_interest_meta")]
428    pub fn add<'a>(
429        buffer: &'a mut gst::BufferRef,
430        roi_type: &str,
431        rect: (u32, u32, u32, u32),
432    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
433        skip_assert_initialized!();
434        unsafe {
435            let meta = ffi::gst_buffer_add_video_region_of_interest_meta(
436                buffer.as_mut_ptr(),
437                roi_type.to_glib_none().0,
438                rect.0,
439                rect.1,
440                rect.2,
441                rect.3,
442            );
443
444            Self::from_mut_ptr(buffer, meta)
445        }
446    }
447
448    #[doc(alias = "get_rect")]
449    #[inline]
450    pub fn rect(&self) -> (u32, u32, u32, u32) {
451        (self.0.x, self.0.y, self.0.w, self.0.h)
452    }
453
454    #[doc(alias = "get_id")]
455    #[inline]
456    pub fn id(&self) -> i32 {
457        self.0.id
458    }
459
460    #[doc(alias = "get_parent_id")]
461    #[inline]
462    pub fn parent_id(&self) -> i32 {
463        self.0.parent_id
464    }
465
466    #[doc(alias = "get_roi_type")]
467    #[inline]
468    pub fn roi_type<'a>(&self) -> &'a str {
469        unsafe { glib::Quark::from_glib(self.0.roi_type).as_str() }
470    }
471
472    #[doc(alias = "get_params")]
473    pub fn params(&self) -> ParamsIter<'_> {
474        ParamsIter {
475            _meta: self,
476            list: ptr::NonNull::new(self.0.params),
477        }
478    }
479
480    #[doc(alias = "get_param")]
481    #[inline]
482    pub fn param<'b>(&'b self, name: &str) -> Option<&'b gst::StructureRef> {
483        self.params().find(|s| s.name() == name)
484    }
485
486    #[inline]
487    pub fn set_rect(&mut self, rect: (u32, u32, u32, u32)) {
488        self.0.x = rect.0;
489        self.0.y = rect.1;
490        self.0.w = rect.2;
491        self.0.h = rect.3;
492    }
493
494    #[inline]
495    pub fn set_id(&mut self, id: i32) {
496        self.0.id = id
497    }
498
499    #[inline]
500    pub fn set_parent_id(&mut self, id: i32) {
501        self.0.parent_id = id
502    }
503
504    #[doc(alias = "gst_video_region_of_interest_meta_add_param")]
505    pub fn add_param(&mut self, s: gst::Structure) {
506        unsafe {
507            ffi::gst_video_region_of_interest_meta_add_param(&mut self.0, s.into_glib_ptr());
508        }
509    }
510}
511
512#[must_use = "iterators are lazy and do nothing unless consumed"]
513pub struct ParamsIter<'a> {
514    _meta: &'a VideoRegionOfInterestMeta,
515    list: Option<ptr::NonNull<glib::ffi::GList>>,
516}
517
518impl<'a> Iterator for ParamsIter<'a> {
519    type Item = &'a gst::StructureRef;
520
521    fn next(&mut self) -> Option<&'a gst::StructureRef> {
522        match self.list {
523            None => None,
524            Some(list) => unsafe {
525                self.list = ptr::NonNull::new(list.as_ref().next);
526                let data = list.as_ref().data;
527
528                let s = gst::StructureRef::from_glib_borrow(data as *const gst::ffi::GstStructure);
529
530                Some(s)
531            },
532        }
533    }
534}
535
536impl std::iter::FusedIterator for ParamsIter<'_> {}
537
538unsafe impl MetaAPI for VideoRegionOfInterestMeta {
539    type GstType = ffi::GstVideoRegionOfInterestMeta;
540
541    #[doc(alias = "gst_video_region_of_interest_meta_api_get_type")]
542    #[inline]
543    fn meta_api() -> glib::Type {
544        unsafe { from_glib(ffi::gst_video_region_of_interest_meta_api_get_type()) }
545    }
546}
547
548impl fmt::Debug for VideoRegionOfInterestMeta {
549    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550        f.debug_struct("VideoRegionOfInterestMeta")
551            .field("roi_type", &self.roi_type())
552            .field("rect", &self.rect())
553            .field("id", &self.id())
554            .field("parent_id", &self.parent_id())
555            .field("params", &self.params().collect::<Vec<_>>())
556            .finish()
557    }
558}
559
560#[repr(transparent)]
561#[doc(alias = "GstVideoAffineTransformationMeta")]
562pub struct VideoAffineTransformationMeta(ffi::GstVideoAffineTransformationMeta);
563
564unsafe impl Send for VideoAffineTransformationMeta {}
565unsafe impl Sync for VideoAffineTransformationMeta {}
566
567impl VideoAffineTransformationMeta {
568    #[doc(alias = "gst_buffer_add_meta")]
569    pub fn add<'a>(
570        buffer: &'a mut gst::BufferRef,
571        matrix: Option<&[[f32; 4]; 4]>,
572    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
573        skip_assert_initialized!();
574        unsafe {
575            let meta = gst::ffi::gst_buffer_add_meta(
576                buffer.as_mut_ptr(),
577                ffi::gst_video_affine_transformation_meta_get_info(),
578                ptr::null_mut(),
579            ) as *mut ffi::GstVideoAffineTransformationMeta;
580
581            if let Some(matrix) = matrix {
582                let meta = &mut *meta;
583                for (i, o) in Iterator::zip(matrix.iter().flatten(), meta.matrix.iter_mut()) {
584                    *o = *i;
585                }
586            }
587
588            Self::from_mut_ptr(buffer, meta)
589        }
590    }
591
592    #[doc(alias = "get_matrix")]
593    #[inline]
594    pub fn matrix(&self) -> &[[f32; 4]; 4] {
595        unsafe { &*(&self.0.matrix as *const [f32; 16] as *const [[f32; 4]; 4]) }
596    }
597
598    #[inline]
599    pub fn set_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
600        for (i, o) in Iterator::zip(matrix.iter().flatten(), self.0.matrix.iter_mut()) {
601            *o = *i;
602        }
603    }
604
605    #[doc(alias = "gst_video_affine_transformation_meta_apply_matrix")]
606    pub fn apply_matrix(&mut self, matrix: &[[f32; 4]; 4]) {
607        unsafe {
608            ffi::gst_video_affine_transformation_meta_apply_matrix(
609                &mut self.0,
610                matrix as *const [[f32; 4]; 4] as *const [f32; 16],
611            );
612        }
613    }
614}
615
616unsafe impl MetaAPI for VideoAffineTransformationMeta {
617    type GstType = ffi::GstVideoAffineTransformationMeta;
618
619    #[doc(alias = "gst_video_affine_transformation_meta_api_get_type")]
620    #[inline]
621    fn meta_api() -> glib::Type {
622        unsafe { from_glib(ffi::gst_video_affine_transformation_meta_api_get_type()) }
623    }
624}
625
626impl fmt::Debug for VideoAffineTransformationMeta {
627    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
628        f.debug_struct("VideoAffineTransformationMeta")
629            .field("matrix", &self.matrix())
630            .finish()
631    }
632}
633
634#[repr(transparent)]
635#[doc(alias = "GstVideoOverlayCompositionMeta")]
636pub struct VideoOverlayCompositionMeta(ffi::GstVideoOverlayCompositionMeta);
637
638unsafe impl Send for VideoOverlayCompositionMeta {}
639unsafe impl Sync for VideoOverlayCompositionMeta {}
640
641impl VideoOverlayCompositionMeta {
642    #[doc(alias = "gst_buffer_add_video_overlay_composition_meta")]
643    pub fn add<'a>(
644        buffer: &'a mut gst::BufferRef,
645        overlay: &crate::VideoOverlayComposition,
646    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
647        skip_assert_initialized!();
648        unsafe {
649            let meta = ffi::gst_buffer_add_video_overlay_composition_meta(
650                buffer.as_mut_ptr(),
651                overlay.as_mut_ptr(),
652            );
653
654            Self::from_mut_ptr(buffer, meta)
655        }
656    }
657
658    #[doc(alias = "get_overlay")]
659    #[inline]
660    pub fn overlay(&self) -> &crate::VideoOverlayCompositionRef {
661        unsafe { crate::VideoOverlayCompositionRef::from_ptr(self.0.overlay) }
662    }
663
664    #[doc(alias = "get_overlay_owned")]
665    #[inline]
666    pub fn overlay_owned(&self) -> crate::VideoOverlayComposition {
667        unsafe { from_glib_none(self.overlay().as_ptr()) }
668    }
669
670    #[inline]
671    pub fn set_overlay(&mut self, overlay: &crate::VideoOverlayComposition) {
672        #![allow(clippy::cast_ptr_alignment)]
673        unsafe {
674            gst::ffi::gst_mini_object_unref(self.0.overlay as *mut _);
675            self.0.overlay =
676                gst::ffi::gst_mini_object_ref(overlay.as_mut_ptr() as *mut _) as *mut _;
677        }
678    }
679}
680
681unsafe impl MetaAPI for VideoOverlayCompositionMeta {
682    type GstType = ffi::GstVideoOverlayCompositionMeta;
683
684    #[doc(alias = "gst_video_overlay_composition_meta_api_get_type")]
685    #[inline]
686    fn meta_api() -> glib::Type {
687        unsafe { from_glib(ffi::gst_video_overlay_composition_meta_api_get_type()) }
688    }
689}
690
691impl fmt::Debug for VideoOverlayCompositionMeta {
692    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
693        f.debug_struct("VideoOverlayCompositionMeta")
694            .field("overlay", &self.overlay())
695            .finish()
696    }
697}
698
699#[cfg(feature = "v1_16")]
700#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
701#[repr(transparent)]
702#[doc(alias = "GstVideoCaptionMeta")]
703pub struct VideoCaptionMeta(ffi::GstVideoCaptionMeta);
704
705#[cfg(feature = "v1_16")]
706#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
707unsafe impl Send for VideoCaptionMeta {}
708#[cfg(feature = "v1_16")]
709#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
710unsafe impl Sync for VideoCaptionMeta {}
711
712#[cfg(feature = "v1_16")]
713#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
714impl VideoCaptionMeta {
715    #[doc(alias = "gst_buffer_add_video_caption_meta")]
716    pub fn add<'a>(
717        buffer: &'a mut gst::BufferRef,
718        caption_type: crate::VideoCaptionType,
719        data: &[u8],
720    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
721        skip_assert_initialized!();
722        assert!(!data.is_empty());
723        unsafe {
724            let meta = ffi::gst_buffer_add_video_caption_meta(
725                buffer.as_mut_ptr(),
726                caption_type.into_glib(),
727                data.as_ptr(),
728                data.len(),
729            );
730
731            Self::from_mut_ptr(buffer, meta)
732        }
733    }
734
735    #[doc(alias = "get_caption_type")]
736    #[inline]
737    pub fn caption_type(&self) -> crate::VideoCaptionType {
738        unsafe { from_glib(self.0.caption_type) }
739    }
740
741    #[doc(alias = "get_data")]
742    #[inline]
743    pub fn data(&self) -> &[u8] {
744        if self.0.size == 0 {
745            return &[];
746        }
747        unsafe {
748            use std::slice;
749
750            slice::from_raw_parts(self.0.data, self.0.size)
751        }
752    }
753}
754
755#[cfg(feature = "v1_16")]
756#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
757unsafe impl MetaAPI for VideoCaptionMeta {
758    type GstType = ffi::GstVideoCaptionMeta;
759
760    #[doc(alias = "gst_video_caption_meta_api_get_type")]
761    #[inline]
762    fn meta_api() -> glib::Type {
763        unsafe { from_glib(ffi::gst_video_caption_meta_api_get_type()) }
764    }
765}
766
767#[cfg(feature = "v1_16")]
768#[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
769impl fmt::Debug for VideoCaptionMeta {
770    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
771        f.debug_struct("VideoCaptionMeta")
772            .field("caption_type", &self.caption_type())
773            .field("data", &self.data())
774            .finish()
775    }
776}
777
778#[cfg(feature = "v1_18")]
779#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
780#[repr(transparent)]
781#[doc(alias = "GstVideoAFDMeta")]
782pub struct VideoAFDMeta(ffi::GstVideoAFDMeta);
783
784#[cfg(feature = "v1_18")]
785#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
786unsafe impl Send for VideoAFDMeta {}
787#[cfg(feature = "v1_18")]
788#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
789unsafe impl Sync for VideoAFDMeta {}
790
791#[cfg(feature = "v1_18")]
792#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
793impl VideoAFDMeta {
794    #[doc(alias = "gst_buffer_add_video_afd_meta")]
795    pub fn add(
796        buffer: &mut gst::BufferRef,
797        field: u8,
798        spec: crate::VideoAFDSpec,
799        afd: crate::VideoAFDValue,
800    ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
801        skip_assert_initialized!();
802
803        unsafe {
804            let meta = ffi::gst_buffer_add_video_afd_meta(
805                buffer.as_mut_ptr(),
806                field,
807                spec.into_glib(),
808                afd.into_glib(),
809            );
810
811            Self::from_mut_ptr(buffer, meta)
812        }
813    }
814
815    #[doc(alias = "get_field")]
816    #[inline]
817    pub fn field(&self) -> u8 {
818        self.0.field
819    }
820
821    #[doc(alias = "get_spec")]
822    #[inline]
823    pub fn spec(&self) -> crate::VideoAFDSpec {
824        unsafe { from_glib(self.0.spec) }
825    }
826
827    #[doc(alias = "get_afd")]
828    #[inline]
829    pub fn afd(&self) -> crate::VideoAFDValue {
830        unsafe { from_glib(self.0.afd) }
831    }
832}
833
834#[cfg(feature = "v1_18")]
835#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
836unsafe impl MetaAPI for VideoAFDMeta {
837    type GstType = ffi::GstVideoAFDMeta;
838
839    #[doc(alias = "gst_video_afd_meta_api_get_type")]
840    #[inline]
841    fn meta_api() -> glib::Type {
842        unsafe { from_glib(ffi::gst_video_afd_meta_api_get_type()) }
843    }
844}
845
846#[cfg(feature = "v1_18")]
847#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
848impl fmt::Debug for VideoAFDMeta {
849    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
850        f.debug_struct("VideoAFDMeta")
851            .field("field", &self.field())
852            .field("spec", &self.spec())
853            .field("afd", &self.afd())
854            .finish()
855    }
856}
857
858#[cfg(feature = "v1_18")]
859#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
860#[repr(transparent)]
861#[doc(alias = "GstVideoBarMeta")]
862pub struct VideoBarMeta(ffi::GstVideoBarMeta);
863
864#[cfg(feature = "v1_18")]
865#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
866unsafe impl Send for VideoBarMeta {}
867#[cfg(feature = "v1_18")]
868#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
869unsafe impl Sync for VideoBarMeta {}
870
871#[cfg(feature = "v1_18")]
872#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
873impl VideoBarMeta {
874    #[doc(alias = "gst_buffer_add_video_bar_meta")]
875    pub fn add(
876        buffer: &mut gst::BufferRef,
877        field: u8,
878        is_letterbox: bool,
879        bar_data1: u32,
880        bar_data2: u32,
881    ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
882        skip_assert_initialized!();
883
884        unsafe {
885            let meta = ffi::gst_buffer_add_video_bar_meta(
886                buffer.as_mut_ptr(),
887                field,
888                is_letterbox.into_glib(),
889                bar_data1,
890                bar_data2,
891            );
892
893            Self::from_mut_ptr(buffer, meta)
894        }
895    }
896
897    #[doc(alias = "get_field")]
898    #[inline]
899    pub fn field(&self) -> u8 {
900        self.0.field
901    }
902
903    #[inline]
904    pub fn is_letterbox(&self) -> bool {
905        unsafe { from_glib(self.0.is_letterbox) }
906    }
907
908    #[doc(alias = "get_bar_data1")]
909    #[inline]
910    pub fn bar_data1(&self) -> u32 {
911        self.0.bar_data1
912    }
913
914    #[doc(alias = "get_bar_data2")]
915    #[inline]
916    pub fn bar_data2(&self) -> u32 {
917        self.0.bar_data2
918    }
919}
920
921#[cfg(feature = "v1_18")]
922#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
923unsafe impl MetaAPI for VideoBarMeta {
924    type GstType = ffi::GstVideoBarMeta;
925
926    #[doc(alias = "gst_video_bar_meta_api_get_type")]
927    #[inline]
928    fn meta_api() -> glib::Type {
929        unsafe { from_glib(ffi::gst_video_bar_meta_api_get_type()) }
930    }
931}
932
933#[cfg(feature = "v1_18")]
934#[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
935impl fmt::Debug for VideoBarMeta {
936    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
937        f.debug_struct("VideoBarMeta")
938            .field("field", &self.field())
939            .field("is_letterbox", &self.is_letterbox())
940            .field("bar_data1", &self.bar_data1())
941            .field("bar_data2", &self.bar_data2())
942            .finish()
943    }
944}
945
946#[cfg(feature = "v1_20")]
947#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
948#[repr(transparent)]
949#[doc(alias = "GstVideoCodecAlphaMeta")]
950pub struct VideoCodecAlphaMeta(ffi::GstVideoCodecAlphaMeta);
951
952#[cfg(feature = "v1_20")]
953#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
954unsafe impl Send for VideoCodecAlphaMeta {}
955#[cfg(feature = "v1_20")]
956#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
957unsafe impl Sync for VideoCodecAlphaMeta {}
958
959#[cfg(feature = "v1_20")]
960#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
961impl VideoCodecAlphaMeta {
962    #[doc(alias = "gst_buffer_add_video_codec_alpha_meta")]
963    pub fn add(
964        buffer: &mut gst::BufferRef,
965        alpha_buffer: gst::Buffer,
966    ) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
967        skip_assert_initialized!();
968        unsafe {
969            let meta = ffi::gst_buffer_add_video_codec_alpha_meta(
970                buffer.as_mut_ptr(),
971                alpha_buffer.to_glib_none().0,
972            );
973
974            Self::from_mut_ptr(buffer, meta)
975        }
976    }
977
978    #[inline]
979    pub fn alpha_buffer(&self) -> &gst::BufferRef {
980        unsafe { gst::BufferRef::from_ptr(self.0.buffer) }
981    }
982
983    #[inline]
984    pub fn alpha_buffer_owned(&self) -> gst::Buffer {
985        unsafe { from_glib_none(self.0.buffer) }
986    }
987}
988
989#[cfg(feature = "v1_20")]
990#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
991unsafe impl MetaAPI for VideoCodecAlphaMeta {
992    type GstType = ffi::GstVideoCodecAlphaMeta;
993
994    #[doc(alias = "gst_video_codec_alpha_meta_api_get_type")]
995    #[inline]
996    fn meta_api() -> glib::Type {
997        unsafe { from_glib(ffi::gst_video_codec_alpha_meta_api_get_type()) }
998    }
999}
1000
1001#[cfg(feature = "v1_20")]
1002#[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
1003impl fmt::Debug for VideoCodecAlphaMeta {
1004    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1005        f.debug_struct("VideoCodecAlphaMeta")
1006            .field("buffer", &self.alpha_buffer())
1007            .finish()
1008    }
1009}
1010
1011#[cfg(feature = "v1_22")]
1012#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1013#[repr(transparent)]
1014#[doc(alias = "GstVideoSEIUserDataUnregisteredMeta")]
1015pub struct VideoSeiUserDataUnregisteredMeta(ffi::GstVideoSEIUserDataUnregisteredMeta);
1016
1017#[cfg(feature = "v1_22")]
1018#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1019unsafe impl Send for VideoSeiUserDataUnregisteredMeta {}
1020#[cfg(feature = "v1_22")]
1021#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1022unsafe impl Sync for VideoSeiUserDataUnregisteredMeta {}
1023
1024#[cfg(feature = "v1_22")]
1025#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1026impl VideoSeiUserDataUnregisteredMeta {
1027    #[doc(alias = "gst_buffer_add_video_sei_user_data_unregistered_meta")]
1028    pub fn add<'a>(
1029        buffer: &'a mut gst::BufferRef,
1030        uuid: &[u8; 16],
1031        data: &[u8],
1032    ) -> gst::MetaRefMut<'a, Self, gst::meta::Standalone> {
1033        skip_assert_initialized!();
1034        assert!(!data.is_empty());
1035        unsafe {
1036            let meta = ffi::gst_buffer_add_video_sei_user_data_unregistered_meta(
1037                buffer.as_mut_ptr(),
1038                mut_override(uuid as *const _),
1039                mut_override(data.as_ptr()),
1040                data.len(),
1041            );
1042
1043            Self::from_mut_ptr(buffer, meta)
1044        }
1045    }
1046
1047    #[doc(alias = "get_data")]
1048    #[inline]
1049    pub fn data(&self) -> &[u8] {
1050        if self.0.size == 0 {
1051            return &[];
1052        }
1053        // SAFETY: In the C API we have a pointer data and a size variable
1054        // indicating the length of the data. Here we convert it to a size,
1055        // making sure we read the size specified in the C API.
1056        unsafe {
1057            use std::slice;
1058            slice::from_raw_parts(self.0.data, self.0.size)
1059        }
1060    }
1061
1062    #[doc(alias = "get_uuid")]
1063    #[inline]
1064    pub fn uuid(&self) -> [u8; 16] {
1065        self.0.uuid
1066    }
1067}
1068
1069#[cfg(feature = "v1_22")]
1070#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1071impl fmt::Debug for VideoSeiUserDataUnregisteredMeta {
1072    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1073        f.debug_struct("VideoSeiUserDataUnregisteredMeta")
1074            .field(
1075                "uuid",
1076                &format!("0x{:032X}", u128::from_be_bytes(self.uuid())),
1077            )
1078            .field("data", &self.data())
1079            .finish()
1080    }
1081}
1082
1083#[cfg(feature = "v1_22")]
1084#[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
1085unsafe impl MetaAPI for VideoSeiUserDataUnregisteredMeta {
1086    type GstType = ffi::GstVideoSEIUserDataUnregisteredMeta;
1087
1088    #[doc(alias = "gst_video_sei_user_data_unregistered_meta_api_get_type")]
1089    fn meta_api() -> glib::Type {
1090        unsafe {
1091            glib::translate::from_glib(ffi::gst_video_sei_user_data_unregistered_meta_api_get_type())
1092        }
1093    }
1094}
1095
1096#[cfg(feature = "v1_24")]
1097#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1098#[repr(transparent)]
1099#[doc(alias = "GstAncillaryMeta")]
1100pub struct AncillaryMeta(ffi::GstAncillaryMeta);
1101
1102#[cfg(feature = "v1_24")]
1103#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1104unsafe impl Send for AncillaryMeta {}
1105#[cfg(feature = "v1_24")]
1106#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1107unsafe impl Sync for AncillaryMeta {}
1108
1109#[cfg(feature = "v1_24")]
1110#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1111impl AncillaryMeta {
1112    #[doc(alias = "gst_buffer_add_ancillary_meta")]
1113    pub fn add(buffer: &mut gst::BufferRef) -> gst::MetaRefMut<'_, Self, gst::meta::Standalone> {
1114        skip_assert_initialized!();
1115        unsafe {
1116            let meta = ffi::gst_buffer_add_ancillary_meta(buffer.as_mut_ptr());
1117
1118            Self::from_mut_ptr(buffer, meta)
1119        }
1120    }
1121
1122    #[inline]
1123    pub fn field(&self) -> crate::AncillaryMetaField {
1124        unsafe { from_glib(self.0.field) }
1125    }
1126
1127    #[inline]
1128    pub fn set_field(&mut self, field: crate::AncillaryMetaField) {
1129        self.0.field = field.into_glib();
1130    }
1131
1132    #[inline]
1133    pub fn c_not_y_channel(&self) -> bool {
1134        unsafe { from_glib(self.0.c_not_y_channel) }
1135    }
1136
1137    #[inline]
1138    pub fn set_c_not_y_channel(&mut self, c_not_y_channel: bool) {
1139        self.0.c_not_y_channel = c_not_y_channel.into_glib();
1140    }
1141
1142    #[inline]
1143    pub fn line(&self) -> u16 {
1144        self.0.line
1145    }
1146
1147    #[inline]
1148    pub fn set_line(&mut self, line: u16) {
1149        self.0.line = line;
1150    }
1151
1152    #[inline]
1153    pub fn offset(&self) -> u16 {
1154        self.0.offset
1155    }
1156
1157    #[inline]
1158    pub fn set_offset(&mut self, offset: u16) {
1159        self.0.offset = offset;
1160    }
1161
1162    #[inline]
1163    pub fn did(&self) -> u16 {
1164        self.0.DID
1165    }
1166
1167    #[inline]
1168    pub fn set_did(&mut self, did: u16) {
1169        self.0.DID = did;
1170    }
1171
1172    #[inline]
1173    pub fn sdid_block_number(&self) -> u16 {
1174        self.0.SDID_block_number
1175    }
1176
1177    #[inline]
1178    pub fn set_sdid_block_number(&mut self, sdid_block_number: u16) {
1179        self.0.SDID_block_number = sdid_block_number;
1180    }
1181
1182    #[inline]
1183    pub fn data_count(&self) -> u16 {
1184        self.0.data_count
1185    }
1186
1187    #[inline]
1188    pub fn checksum(&self) -> u16 {
1189        self.0.checksum
1190    }
1191
1192    #[inline]
1193    pub fn set_checksum(&mut self, checksum: u16) {
1194        self.0.checksum = checksum;
1195    }
1196
1197    #[inline]
1198    pub fn data(&self) -> &[u16] {
1199        if self.0.data_count & 0xff == 0 {
1200            return &[];
1201        }
1202        unsafe {
1203            use std::slice;
1204
1205            slice::from_raw_parts(self.0.data, (self.0.data_count & 0xff) as usize)
1206        }
1207    }
1208
1209    #[inline]
1210    pub fn data_mut(&mut self) -> &mut [u16] {
1211        if self.0.data_count & 0xff == 0 {
1212            return &mut [];
1213        }
1214        unsafe {
1215            use std::slice;
1216
1217            slice::from_raw_parts_mut(self.0.data, (self.0.data_count & 0xff) as usize)
1218        }
1219    }
1220
1221    #[inline]
1222    pub fn set_data(&mut self, data: glib::Slice<u16>) {
1223        assert!(data.len() < 256);
1224        self.0.data_count = data.len() as u16;
1225        self.0.data = data.into_glib_ptr();
1226    }
1227
1228    #[inline]
1229    pub fn set_data_count_upper_two_bits(&mut self, upper_two_bits: u8) {
1230        assert!(upper_two_bits & !0x03 == 0);
1231        self.0.data_count = ((upper_two_bits as u16) << 8) | self.0.data_count & 0xff;
1232    }
1233}
1234
1235#[cfg(feature = "v1_24")]
1236#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1237unsafe impl MetaAPI for AncillaryMeta {
1238    type GstType = ffi::GstAncillaryMeta;
1239
1240    #[doc(alias = "gst_ancillary_meta_api_get_type")]
1241    #[inline]
1242    fn meta_api() -> glib::Type {
1243        unsafe { from_glib(ffi::gst_ancillary_meta_api_get_type()) }
1244    }
1245}
1246
1247#[cfg(feature = "v1_24")]
1248#[cfg_attr(docsrs, doc(cfg(feature = "v1_24")))]
1249impl fmt::Debug for AncillaryMeta {
1250    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1251        f.debug_struct("AncillaryMeta")
1252            .field("field", &self.field())
1253            .field("c_not_y_channel", &self.c_not_y_channel())
1254            .field("line", &self.line())
1255            .field("offset", &self.offset())
1256            .field("did", &self.did())
1257            .field("sdid_block_number", &self.sdid_block_number())
1258            .field("data_count", &self.data_count())
1259            .field("data", &self.data())
1260            .field("checksum", &self.checksum())
1261            .finish()
1262    }
1263}
1264
1265pub mod tags {
1266    gst::impl_meta_tag!(Video, crate::ffi::GST_META_TAG_VIDEO_STR);
1267    gst::impl_meta_tag!(Size, crate::ffi::GST_META_TAG_VIDEO_SIZE_STR);
1268    gst::impl_meta_tag!(Orientation, crate::ffi::GST_META_TAG_VIDEO_ORIENTATION_STR);
1269    gst::impl_meta_tag!(Colorspace, crate::ffi::GST_META_TAG_VIDEO_COLORSPACE_STR);
1270}
1271
1272#[repr(transparent)]
1273#[doc(alias = "GstVideoMetaTransform")]
1274pub struct VideoMetaTransformScale(ffi::GstVideoMetaTransform);
1275
1276unsafe impl Sync for VideoMetaTransformScale {}
1277unsafe impl Send for VideoMetaTransformScale {}
1278
1279impl VideoMetaTransformScale {
1280    pub fn new(in_info: &crate::VideoInfo, out_info: &crate::VideoInfo) -> Self {
1281        skip_assert_initialized!();
1282        Self(ffi::GstVideoMetaTransform {
1283            in_info: mut_override(in_info.to_glib_none().0),
1284            out_info: mut_override(out_info.to_glib_none().0),
1285        })
1286    }
1287
1288    pub fn in_info(&self) -> &crate::VideoInfo {
1289        unsafe { &*(self.0.in_info as *const crate::VideoInfo) }
1290    }
1291
1292    pub fn out_info(&self) -> &crate::VideoInfo {
1293        unsafe { &*(self.0.out_info as *const crate::VideoInfo) }
1294    }
1295}
1296
1297unsafe impl gst::meta::MetaTransform for VideoMetaTransformScale {
1298    type GLibType = ffi::GstVideoMetaTransform;
1299
1300    #[doc(alias = "gst_video_meta_transform_scale_get_quark")]
1301    fn quark() -> glib::Quark {
1302        unsafe { from_glib(ffi::gst_video_meta_transform_scale_get_quark()) }
1303    }
1304
1305    fn as_ptr(&self) -> *const ffi::GstVideoMetaTransform {
1306        &self.0
1307    }
1308}
1309
1310#[cfg(feature = "v1_28")]
1311#[cfg_attr(docsrs, doc(cfg(feature = "v1_28")))]
1312mod video_meta_transform_matrix {
1313    use super::*;
1314
1315    use std::mem;
1316
1317    #[repr(transparent)]
1318    #[doc(alias = "GstVideoMetaTransformMatrix")]
1319    pub struct VideoMetaTransformMatrix(ffi::GstVideoMetaTransformMatrix);
1320
1321    unsafe impl Sync for VideoMetaTransformMatrix {}
1322    unsafe impl Send for VideoMetaTransformMatrix {}
1323
1324    impl VideoMetaTransformMatrix {
1325        #[doc(alias = "gst_video_meta_transform_matrix_init")]
1326        pub fn new(
1327            in_info: &crate::VideoInfo,
1328            in_rectangle: &crate::VideoRectangle,
1329            out_info: &crate::VideoInfo,
1330            out_rectangle: &crate::VideoRectangle,
1331        ) -> Self {
1332            skip_assert_initialized!();
1333
1334            unsafe {
1335                let mut trans = mem::MaybeUninit::uninit();
1336
1337                ffi::gst_video_meta_transform_matrix_init(
1338                    trans.as_mut_ptr(),
1339                    in_info.to_glib_none().0,
1340                    in_rectangle.to_glib_none().0,
1341                    out_info.to_glib_none().0,
1342                    out_rectangle.to_glib_none().0,
1343                );
1344
1345                Self(trans.assume_init())
1346            }
1347        }
1348
1349        pub fn in_info(&self) -> &crate::VideoInfo {
1350            unsafe { &*(self.0.in_info as *const crate::VideoInfo) }
1351        }
1352
1353        pub fn in_rectangle(&self) -> &crate::VideoRectangle {
1354            unsafe { &*(&self.0.in_rectangle as *const _ as *const crate::VideoRectangle) }
1355        }
1356
1357        pub fn out_info(&self) -> &crate::VideoInfo {
1358            unsafe { &*(self.0.out_info as *const crate::VideoInfo) }
1359        }
1360
1361        pub fn out_rectangle(&self) -> &crate::VideoRectangle {
1362            unsafe { &*(&self.0.out_rectangle as *const _ as *const crate::VideoRectangle) }
1363        }
1364
1365        #[doc(alias = "gst_video_meta_transform_matrix_point")]
1366        pub fn point(&self, x: i32, y: i32) -> Option<(i32, i32)> {
1367            unsafe {
1368                let mut x = x;
1369                let mut y = y;
1370                let res = from_glib(ffi::gst_video_meta_transform_matrix_point(
1371                    &self.0, &mut x, &mut y,
1372                ));
1373                if res { Some((x, y)) } else { None }
1374            }
1375        }
1376
1377        #[doc(alias = "gst_video_meta_transform_matrix_point_clipped")]
1378        pub fn point_clipped(&self, x: i32, y: i32) -> Option<(i32, i32)> {
1379            unsafe {
1380                let mut x = x;
1381                let mut y = y;
1382                let res = from_glib(ffi::gst_video_meta_transform_matrix_point_clipped(
1383                    &self.0, &mut x, &mut y,
1384                ));
1385                if res { Some((x, y)) } else { None }
1386            }
1387        }
1388
1389        #[doc(alias = "gst_video_meta_transform_matrix_rectangle")]
1390        pub fn rectangle(
1391            &self,
1392            rectangle: &crate::VideoRectangle,
1393        ) -> Option<crate::VideoRectangle> {
1394            unsafe {
1395                let mut rectangle = rectangle.clone();
1396                let res = from_glib(ffi::gst_video_meta_transform_matrix_rectangle(
1397                    &self.0,
1398                    rectangle.to_glib_none_mut().0,
1399                ));
1400                if res { Some(rectangle) } else { None }
1401            }
1402        }
1403
1404        #[doc(alias = "gst_video_meta_transform_matrix_rectangle_clipped")]
1405        pub fn rectangle_clipped(
1406            &self,
1407            rectangle: &crate::VideoRectangle,
1408        ) -> Option<crate::VideoRectangle> {
1409            unsafe {
1410                let mut rectangle = rectangle.clone();
1411                let res = from_glib(ffi::gst_video_meta_transform_matrix_rectangle_clipped(
1412                    &self.0,
1413                    rectangle.to_glib_none_mut().0,
1414                ));
1415                if res { Some(rectangle) } else { None }
1416            }
1417        }
1418    }
1419
1420    unsafe impl gst::meta::MetaTransform for VideoMetaTransformMatrix {
1421        type GLibType = ffi::GstVideoMetaTransformMatrix;
1422
1423        #[doc(alias = "gst_video_meta_transform_matrix_get_quark")]
1424        fn quark() -> glib::Quark {
1425            unsafe { from_glib(ffi::gst_video_meta_transform_matrix_get_quark()) }
1426        }
1427
1428        fn as_ptr(&self) -> *const ffi::GstVideoMetaTransformMatrix {
1429            &self.0
1430        }
1431    }
1432}
1433
1434#[cfg(feature = "v1_28")]
1435#[cfg_attr(docsrs, doc(cfg(feature = "v1_28")))]
1436pub use video_meta_transform_matrix::*;
1437
1438#[cfg(test)]
1439mod tests {
1440    use super::*;
1441
1442    #[test]
1443    fn test_add_get_meta() {
1444        gst::init().unwrap();
1445
1446        let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1447        {
1448            let meta = VideoMeta::add(
1449                buffer.get_mut().unwrap(),
1450                crate::VideoFrameFlags::empty(),
1451                crate::VideoFormat::Argb,
1452                320,
1453                240,
1454            )
1455            .unwrap();
1456            assert_eq!(meta.id(), 0);
1457            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1458            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1459            assert_eq!(meta.width(), 320);
1460            assert_eq!(meta.height(), 240);
1461            assert_eq!(meta.n_planes(), 1);
1462            assert_eq!(meta.offset(), &[0]);
1463            assert_eq!(meta.stride(), &[320 * 4]);
1464            assert!(meta.has_tag::<gst::meta::tags::Memory>());
1465            assert!(meta.has_tag::<tags::Video>());
1466            assert!(meta.has_tag::<tags::Colorspace>());
1467            assert!(meta.has_tag::<tags::Size>());
1468        }
1469
1470        {
1471            let meta = buffer.meta::<VideoMeta>().unwrap();
1472            assert_eq!(meta.id(), 0);
1473            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1474            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1475            assert_eq!(meta.width(), 320);
1476            assert_eq!(meta.height(), 240);
1477            assert_eq!(meta.n_planes(), 1);
1478            assert_eq!(meta.offset(), &[0]);
1479            assert_eq!(meta.stride(), &[320 * 4]);
1480        }
1481    }
1482
1483    #[test]
1484    fn test_add_full_get_meta() {
1485        gst::init().unwrap();
1486
1487        let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1488        {
1489            let meta = VideoMeta::add_full(
1490                buffer.get_mut().unwrap(),
1491                crate::VideoFrameFlags::empty(),
1492                crate::VideoFormat::Argb,
1493                320,
1494                240,
1495                &[0],
1496                &[320 * 4],
1497            )
1498            .unwrap();
1499            assert_eq!(meta.id(), 0);
1500            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1501            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1502            assert_eq!(meta.width(), 320);
1503            assert_eq!(meta.height(), 240);
1504            assert_eq!(meta.n_planes(), 1);
1505            assert_eq!(meta.offset(), &[0]);
1506            assert_eq!(meta.stride(), &[320 * 4]);
1507        }
1508
1509        {
1510            let meta = buffer.meta::<VideoMeta>().unwrap();
1511            assert_eq!(meta.id(), 0);
1512            assert_eq!(meta.video_frame_flags(), crate::VideoFrameFlags::empty());
1513            assert_eq!(meta.format(), crate::VideoFormat::Argb);
1514            assert_eq!(meta.width(), 320);
1515            assert_eq!(meta.height(), 240);
1516            assert_eq!(meta.n_planes(), 1);
1517            assert_eq!(meta.offset(), &[0]);
1518            assert_eq!(meta.stride(), &[320 * 4]);
1519        }
1520    }
1521
1522    #[test]
1523    #[cfg(feature = "v1_16")]
1524    fn test_add_full_alternate_interlacing() {
1525        gst::init().unwrap();
1526        let mut buffer = gst::Buffer::with_size(320 * 120 * 4).unwrap();
1527        VideoMeta::add_full(
1528            buffer.get_mut().unwrap(),
1529            crate::VideoFrameFlags::TOP_FIELD,
1530            crate::VideoFormat::Argb,
1531            320,
1532            240,
1533            &[0],
1534            &[320 * 4],
1535        )
1536        .unwrap();
1537    }
1538
1539    #[test]
1540    #[cfg(feature = "v1_18")]
1541    fn test_video_meta_alignment() {
1542        gst::init().unwrap();
1543
1544        let mut buffer = gst::Buffer::with_size(115200).unwrap();
1545        let meta = VideoMeta::add(
1546            buffer.get_mut().unwrap(),
1547            crate::VideoFrameFlags::empty(),
1548            crate::VideoFormat::Nv12,
1549            320,
1550            240,
1551        )
1552        .unwrap();
1553
1554        let alig = meta.alignment();
1555        assert_eq!(alig, crate::VideoAlignment::new(0, 0, 0, 0, &[0, 0, 0, 0]));
1556
1557        assert_eq!(meta.plane_size().unwrap(), [76800, 38400, 0, 0]);
1558        assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1559
1560        /* horizontal padding */
1561        let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1562            .build()
1563            .expect("Failed to create VideoInfo");
1564        let mut alig = crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]);
1565        info.align(&mut alig).unwrap();
1566
1567        let mut meta = VideoMeta::add_full(
1568            buffer.get_mut().unwrap(),
1569            crate::VideoFrameFlags::empty(),
1570            crate::VideoFormat::Nv12,
1571            info.width(),
1572            info.height(),
1573            info.offset(),
1574            info.stride(),
1575        )
1576        .unwrap();
1577        meta.set_alignment(&alig).unwrap();
1578
1579        let alig = meta.alignment();
1580        assert_eq!(alig, crate::VideoAlignment::new(0, 0, 2, 6, &[0, 0, 0, 0]));
1581
1582        assert_eq!(meta.plane_size().unwrap(), [78720, 39360, 0, 0]);
1583        assert_eq!(meta.plane_height().unwrap(), [240, 120, 0, 0]);
1584
1585        /* vertical alignment */
1586        let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv12, 320, 240)
1587            .build()
1588            .expect("Failed to create VideoInfo");
1589        let mut alig = crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]);
1590        info.align(&mut alig).unwrap();
1591
1592        let mut meta = VideoMeta::add_full(
1593            buffer.get_mut().unwrap(),
1594            crate::VideoFrameFlags::empty(),
1595            crate::VideoFormat::Nv12,
1596            info.width(),
1597            info.height(),
1598            info.offset(),
1599            info.stride(),
1600        )
1601        .unwrap();
1602        meta.set_alignment(&alig).unwrap();
1603
1604        let alig = meta.alignment();
1605        assert_eq!(alig, crate::VideoAlignment::new(2, 6, 0, 0, &[0, 0, 0, 0]));
1606
1607        assert_eq!(meta.plane_size().unwrap(), [79360, 39680, 0, 0]);
1608        assert_eq!(meta.plane_height().unwrap(), [248, 124, 0, 0]);
1609    }
1610
1611    #[test]
1612    #[cfg(feature = "v1_22")]
1613    fn test_get_video_sei_user_data_unregistered_meta() {
1614        gst::init().unwrap();
1615
1616        const META_UUID: &[u8; 16] = &[
1617            0x4D, 0x49, 0x53, 0x50, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x65, 0x63, 0x74, 0x69,
1618            0x6D, 0x65,
1619        ];
1620
1621        const META_DATA: &[u8] = &[
1622            0x1f, 0x00, 0x05, 0xff, 0x21, 0x7e, 0xff, 0x29, 0xb5, 0xff, 0xdc, 0x13,
1623        ];
1624
1625        let buffer_data = &[
1626            &[0x00, 0x00, 0x00, 0x20, 0x06, 0x05, 0x1c],
1627            META_UUID as &[u8],
1628            META_DATA,
1629            &[
1630                0x80, 0x00, 0x00, 0x00, 0x14, 0x65, 0x88, 0x84, 0x00, 0x10, 0xff, 0xfe, 0xf6, 0xf0,
1631                0xfe, 0x05, 0x36, 0x56, 0x04, 0x50, 0x96, 0x7b, 0x3f, 0x53, 0xe1,
1632            ],
1633        ]
1634        .concat();
1635
1636        let mut harness = gst_check::Harness::new("h264parse");
1637        harness.set_src_caps_str(r#"
1638            video/x-h264, stream-format=(string)avc,
1639            width=(int)1920, height=(int)1080, framerate=(fraction)25/1,
1640            bit-depth-chroma=(uint)8, parsed=(boolean)true,
1641            alignment=(string)au, profile=(string)high, level=(string)4,
1642            codec_data=(buffer)01640028ffe1001a67640028acb200f0044fcb080000030008000003019478c1924001000568ebccb22c
1643        "#);
1644        let buffer = gst::Buffer::from_slice(buffer_data.clone());
1645        let buffer = harness.push_and_pull(buffer).unwrap();
1646
1647        let meta = buffer.meta::<VideoSeiUserDataUnregisteredMeta>().unwrap();
1648        assert_eq!(meta.uuid(), *META_UUID);
1649        assert_eq!(meta.data(), META_DATA);
1650        assert_eq!(meta.data().len(), META_DATA.len());
1651    }
1652
1653    #[test]
1654    fn test_meta_video_transform() {
1655        gst::init().unwrap();
1656
1657        let mut buffer = gst::Buffer::with_size(320 * 240 * 4).unwrap();
1658        let meta = VideoCropMeta::add(buffer.get_mut().unwrap(), (10, 10, 20, 20));
1659
1660        let mut buffer2 = gst::Buffer::with_size(640 * 480 * 4).unwrap();
1661
1662        let in_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 320, 240)
1663            .build()
1664            .unwrap();
1665        let out_video_info = crate::VideoInfo::builder(crate::VideoFormat::Rgba, 640, 480)
1666            .build()
1667            .unwrap();
1668
1669        meta.transform(
1670            buffer2.get_mut().unwrap(),
1671            &VideoMetaTransformScale::new(&in_video_info, &out_video_info),
1672        )
1673        .unwrap();
1674
1675        let meta2 = buffer2.meta::<VideoCropMeta>().unwrap();
1676
1677        assert_eq!(meta2.rect(), (20, 20, 40, 40));
1678    }
1679}