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