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