gstreamer_video/
video_info.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem, ptr, str};
4
5use crate::ffi;
6use glib::translate::*;
7use gst::prelude::*;
8
9#[doc(alias = "GST_VIDEO_MAX_PLANES")]
10pub const VIDEO_MAX_PLANES: usize = ffi::GST_VIDEO_MAX_PLANES as usize;
11
12/// Possible color range values. These constants are defined for 8 bit color
13/// values and can be scaled for other bit depths.
14#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)]
15#[non_exhaustive]
16#[doc(alias = "GstVideoColorRange")]
17pub enum VideoColorRange {
18    /// unknown range
19    #[doc(alias = "GST_VIDEO_COLOR_RANGE_UNKNOWN")]
20    Unknown,
21    #[doc(alias = "GST_VIDEO_COLOR_RANGE_0_255")]
22    Range0_255,
23    #[doc(alias = "GST_VIDEO_COLOR_RANGE_16_235")]
24    Range16_235,
25    #[doc(hidden)]
26    __Unknown(i32),
27}
28
29#[doc(hidden)]
30impl IntoGlib for VideoColorRange {
31    type GlibType = ffi::GstVideoColorRange;
32
33    #[inline]
34    fn into_glib(self) -> ffi::GstVideoColorRange {
35        match self {
36            Self::Unknown => ffi::GST_VIDEO_COLOR_RANGE_UNKNOWN,
37            Self::Range0_255 => ffi::GST_VIDEO_COLOR_RANGE_0_255,
38            Self::Range16_235 => ffi::GST_VIDEO_COLOR_RANGE_16_235,
39            Self::__Unknown(value) => value,
40        }
41    }
42}
43
44#[doc(hidden)]
45impl FromGlib<ffi::GstVideoColorRange> for VideoColorRange {
46    #[inline]
47    unsafe fn from_glib(value: ffi::GstVideoColorRange) -> Self {
48        skip_assert_initialized!();
49        match value {
50            0 => Self::Unknown,
51            1 => Self::Range0_255,
52            2 => Self::Range16_235,
53            value => Self::__Unknown(value),
54        }
55    }
56}
57
58impl StaticType for VideoColorRange {
59    #[inline]
60    fn static_type() -> glib::Type {
61        unsafe { from_glib(ffi::gst_video_color_range_get_type()) }
62    }
63}
64
65impl glib::value::ValueType for VideoColorRange {
66    type Type = Self;
67}
68
69unsafe impl<'a> glib::value::FromValue<'a> for VideoColorRange {
70    type Checker = glib::value::GenericValueTypeChecker<Self>;
71
72    unsafe fn from_value(value: &'a glib::Value) -> Self {
73        skip_assert_initialized!();
74        from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0))
75    }
76}
77
78impl ToValue for VideoColorRange {
79    fn to_value(&self) -> glib::Value {
80        let mut value = glib::Value::for_value_type::<Self>();
81        unsafe { glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()) }
82        value
83    }
84
85    fn value_type(&self) -> glib::Type {
86        Self::static_type()
87    }
88}
89
90impl From<VideoColorRange> for glib::Value {
91    fn from(v: VideoColorRange) -> glib::Value {
92        skip_assert_initialized!();
93        glib::value::ToValue::to_value(&v)
94    }
95}
96
97/// Structure describing the color info.
98#[doc(alias = "GstVideoColorimetry")]
99#[derive(Copy, Clone)]
100#[repr(transparent)]
101pub struct VideoColorimetry(ffi::GstVideoColorimetry);
102
103impl VideoColorimetry {
104    pub fn new(
105        range: crate::VideoColorRange,
106        matrix: crate::VideoColorMatrix,
107        transfer: crate::VideoTransferFunction,
108        primaries: crate::VideoColorPrimaries,
109    ) -> Self {
110        skip_assert_initialized!();
111
112        let colorimetry = ffi::GstVideoColorimetry {
113            range: range.into_glib(),
114            matrix: matrix.into_glib(),
115            transfer: transfer.into_glib(),
116            primaries: primaries.into_glib(),
117        };
118
119        Self(colorimetry)
120    }
121
122    #[inline]
123    pub fn range(&self) -> crate::VideoColorRange {
124        unsafe { from_glib(self.0.range) }
125    }
126
127    #[inline]
128    pub fn matrix(&self) -> crate::VideoColorMatrix {
129        unsafe { from_glib(self.0.matrix) }
130    }
131
132    #[inline]
133    pub fn transfer(&self) -> crate::VideoTransferFunction {
134        unsafe { from_glib(self.0.transfer) }
135    }
136
137    #[inline]
138    pub fn primaries(&self) -> crate::VideoColorPrimaries {
139        unsafe { from_glib(self.0.primaries) }
140    }
141
142    /// Compare the 2 colorimetry sets for functionally equality
143    /// ## `bitdepth`
144    /// bitdepth of a format associated with `self`
145    /// ## `other`
146    /// another [`VideoColorimetry`][crate::VideoColorimetry]
147    /// ## `other_bitdepth`
148    /// bitdepth of a format associated with `other`
149    ///
150    /// # Returns
151    ///
152    /// [`true`] if `self` and `other` are equivalent.
153    #[cfg(feature = "v1_22")]
154    #[cfg_attr(docsrs, doc(cfg(feature = "v1_22")))]
155    #[doc(alias = "gst_video_colorimetry_is_equivalent")]
156    pub fn is_equivalent(&self, bitdepth: u32, other: &Self, other_bitdepth: u32) -> bool {
157        unsafe {
158            from_glib(ffi::gst_video_colorimetry_is_equivalent(
159                &self.0,
160                bitdepth,
161                &other.0,
162                other_bitdepth,
163            ))
164        }
165    }
166}
167
168impl PartialEq for VideoColorimetry {
169    #[doc(alias = "gst_video_colorimetry_is_equal")]
170    fn eq(&self, other: &Self) -> bool {
171        unsafe { from_glib(ffi::gst_video_colorimetry_is_equal(&self.0, &other.0)) }
172    }
173}
174
175impl Eq for VideoColorimetry {}
176
177impl str::FromStr for crate::VideoColorimetry {
178    type Err = glib::error::BoolError;
179
180    #[doc(alias = "gst_video_colorimetry_from_string")]
181    fn from_str(s: &str) -> Result<Self, Self::Err> {
182        assert_initialized_main_thread!();
183
184        unsafe {
185            let mut colorimetry = mem::MaybeUninit::uninit();
186            let valid: bool = from_glib(ffi::gst_video_colorimetry_from_string(
187                colorimetry.as_mut_ptr(),
188                s.to_glib_none().0,
189            ));
190            if valid {
191                Ok(Self(colorimetry.assume_init()))
192            } else {
193                Err(glib::bool_error!("Invalid colorimetry info"))
194            }
195        }
196    }
197}
198
199impl fmt::Debug for crate::VideoColorimetry {
200    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201        f.debug_struct("VideoColorimetry")
202            .field("range", &self.0.range)
203            .field("matrix", &self.0.matrix)
204            .field("transfer", &self.0.transfer)
205            .field("primaries", &self.0.primaries)
206            .finish()
207    }
208}
209
210impl fmt::Display for crate::VideoColorimetry {
211    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212        let s =
213            unsafe { glib::GString::from_glib_full(ffi::gst_video_colorimetry_to_string(&self.0)) };
214        f.write_str(&s)
215    }
216}
217
218impl crate::VideoChromaSite {
219    #[doc(alias = "gst_video_chroma_site_to_string")]
220    #[doc(alias = "gst_video_chroma_to_string")]
221    pub fn to_str(self) -> glib::GString {
222        assert_initialized_main_thread!();
223
224        unsafe {
225            cfg_if::cfg_if! {
226                if #[cfg(feature = "v1_20")] {
227                    from_glib_full(ffi::gst_video_chroma_site_to_string(self.into_glib()))
228                } else {
229                    from_glib_none(ffi::gst_video_chroma_to_string(self.into_glib()))
230                }
231            }
232        }
233    }
234}
235
236impl str::FromStr for crate::VideoChromaSite {
237    type Err = glib::error::BoolError;
238
239    #[doc(alias = "gst_video_chroma_from_string")]
240    fn from_str(s: &str) -> Result<Self, Self::Err> {
241        skip_assert_initialized!();
242
243        cfg_if::cfg_if! {
244            if #[cfg(feature = "v1_20")] {
245                let chroma_site = Self::from_string(s);
246            } else {
247                assert_initialized_main_thread!();
248                let chroma_site: Self =
249                    unsafe { from_glib(ffi::gst_video_chroma_from_string(s.to_glib_none().0)) };
250            }
251        };
252
253        if chroma_site.is_empty() {
254            Err(glib::bool_error!("Invalid chroma site"))
255        } else {
256            Ok(chroma_site)
257        }
258    }
259}
260
261impl From<crate::VideoMultiviewFramePacking> for crate::VideoMultiviewMode {
262    #[inline]
263    fn from(v: crate::VideoMultiviewFramePacking) -> Self {
264        skip_assert_initialized!();
265        unsafe { from_glib(v.into_glib()) }
266    }
267}
268
269impl TryFrom<crate::VideoMultiviewMode> for crate::VideoMultiviewFramePacking {
270    type Error = glib::BoolError;
271
272    fn try_from(v: crate::VideoMultiviewMode) -> Result<Self, glib::BoolError> {
273        skip_assert_initialized!();
274
275        let v2 = unsafe { from_glib(v.into_glib()) };
276
277        if let Self::__Unknown(_) = v2 {
278            Err(glib::bool_error!("Invalid frame packing mode"))
279        } else {
280            Ok(v2)
281        }
282    }
283}
284
285/// Information describing image properties. This information can be filled
286/// in from GstCaps with [`from_caps()`][Self::from_caps()]. The information is also used
287/// to store the specific video info when mapping a video frame with
288/// [`VideoFrame::from_buffer_readable()`][crate::VideoFrame::from_buffer_readable()].
289///
290/// Use the provided macros to access the info in this structure.
291#[doc(alias = "GstVideoInfo")]
292#[derive(Clone)]
293#[repr(transparent)]
294pub struct VideoInfo(pub(crate) ffi::GstVideoInfo);
295
296impl fmt::Debug for VideoInfo {
297    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
298        f.debug_struct("VideoInfo")
299            .field("format", &self.format())
300            .field("format-info", &self.format_info())
301            .field("width", &self.width())
302            .field("height", &self.height())
303            .field("interlace_mode", &self.interlace_mode())
304            .field("flags", &self.flags())
305            .field("size", &self.size())
306            .field("views", &self.views())
307            .field("chroma_site", &self.chroma_site())
308            .field("colorimetry", &self.colorimetry())
309            .field("par", &self.par())
310            .field("fps", &self.fps())
311            .field("offset", &self.offset())
312            .field("stride", &self.stride())
313            .field("multiview_mode", &self.multiview_mode())
314            .field("multiview_flags", &self.multiview_flags())
315            .field("field_order", &self.field_order())
316            .finish()
317    }
318}
319
320#[derive(Debug)]
321#[must_use = "The builder must be built to be used"]
322pub struct VideoInfoBuilder<'a> {
323    format: crate::VideoFormat,
324    width: u32,
325    height: u32,
326    interlace_mode: Option<crate::VideoInterlaceMode>,
327    flags: Option<crate::VideoFlags>,
328    size: Option<usize>,
329    views: Option<u32>,
330    chroma_site: Option<crate::VideoChromaSite>,
331    colorimetry: Option<crate::VideoColorimetry>,
332    par: Option<gst::Fraction>,
333    fps: Option<gst::Fraction>,
334    offset: Option<&'a [usize]>,
335    stride: Option<&'a [i32]>,
336    multiview_mode: Option<crate::VideoMultiviewMode>,
337    multiview_flags: Option<crate::VideoMultiviewFlags>,
338    field_order: Option<crate::VideoFieldOrder>,
339}
340
341impl<'a> VideoInfoBuilder<'a> {
342    pub fn build(self) -> Result<VideoInfo, glib::error::BoolError> {
343        unsafe {
344            let mut info = mem::MaybeUninit::uninit();
345
346            cfg_if::cfg_if! {
347                if #[cfg(feature = "v1_16")] {
348                    let res: bool = {
349                        from_glib(if let Some(interlace_mode) = self.interlace_mode {
350                            ffi::gst_video_info_set_interlaced_format(
351                                info.as_mut_ptr(),
352                                self.format.into_glib(),
353                                interlace_mode.into_glib(),
354                                self.width,
355                                self.height,
356                            )
357                        } else {
358                            ffi::gst_video_info_set_format(
359                                info.as_mut_ptr(),
360                                self.format.into_glib(),
361                                self.width,
362                                self.height,
363                            )
364                        })
365                    };
366                } else {
367                    let res: bool = {
368                        let res = from_glib(ffi::gst_video_info_set_format(
369                            info.as_mut_ptr(),
370                            self.format.into_glib(),
371                            self.width,
372                            self.height,
373                        ));
374
375                        if res {
376                            if let Some(interlace_mode) = self.interlace_mode {
377                                let info = info.as_mut_ptr();
378                                (*info).interlace_mode = interlace_mode.into_glib();
379                            }
380                        }
381
382                        res
383                    };
384                }
385            }
386
387            if !res {
388                return Err(glib::bool_error!("Failed to build VideoInfo"));
389            }
390
391            let mut info = info.assume_init();
392
393            if info.finfo.is_null() || info.width <= 0 || info.height <= 0 {
394                return Err(glib::bool_error!("Failed to build VideoInfo"));
395            }
396
397            if let Some(flags) = self.flags {
398                info.flags = flags.into_glib();
399            }
400
401            if let Some(size) = self.size {
402                info.size = size;
403            }
404
405            if let Some(views) = self.views {
406                info.views = views as i32;
407            }
408
409            if let Some(chroma_site) = self.chroma_site {
410                info.chroma_site = chroma_site.into_glib();
411            }
412
413            if let Some(colorimetry) = self.colorimetry {
414                ptr::write(&mut info.colorimetry, ptr::read(&colorimetry.0));
415            }
416
417            if let Some(par) = self.par {
418                info.par_n = par.numer();
419                info.par_d = par.denom();
420            }
421
422            if let Some(fps) = self.fps {
423                info.fps_n = fps.numer();
424                info.fps_d = fps.denom();
425            }
426
427            if let Some(offset) = self.offset {
428                if offset.len() != ((*info.finfo).n_planes as usize) {
429                    return Err(glib::bool_error!("Failed to build VideoInfo"));
430                }
431
432                let n_planes = (*info.finfo).n_planes as usize;
433                info.offset[..n_planes].copy_from_slice(&offset[..n_planes]);
434            }
435
436            if let Some(stride) = self.stride {
437                if stride.len() != ((*info.finfo).n_planes as usize) {
438                    return Err(glib::bool_error!("Failed to build VideoInfo"));
439                }
440
441                let n_planes = (*info.finfo).n_planes as usize;
442                info.stride[..n_planes].copy_from_slice(&stride[..n_planes]);
443            }
444
445            if let Some(multiview_mode) = self.multiview_mode {
446                info.ABI.abi.multiview_mode = multiview_mode.into_glib();
447            }
448
449            if let Some(multiview_flags) = self.multiview_flags {
450                info.ABI.abi.multiview_flags = multiview_flags.into_glib();
451            }
452
453            if let Some(field_order) = self.field_order {
454                info.ABI.abi.field_order = field_order.into_glib();
455            }
456
457            Ok(VideoInfo(info))
458        }
459    }
460
461    pub fn interlace_mode(self, interlace_mode: crate::VideoInterlaceMode) -> VideoInfoBuilder<'a> {
462        Self {
463            interlace_mode: Some(interlace_mode),
464            ..self
465        }
466    }
467
468    pub fn interlace_mode_if(
469        self,
470        interlace_mode: crate::VideoInterlaceMode,
471        predicate: bool,
472    ) -> VideoInfoBuilder<'a> {
473        if predicate {
474            self.interlace_mode(interlace_mode)
475        } else {
476            self
477        }
478    }
479
480    pub fn interlace_mode_if_some(
481        self,
482        interlace_mode: Option<crate::VideoInterlaceMode>,
483    ) -> VideoInfoBuilder<'a> {
484        if let Some(interlace_mode) = interlace_mode {
485            self.interlace_mode(interlace_mode)
486        } else {
487            self
488        }
489    }
490
491    pub fn flags(self, flags: crate::VideoFlags) -> Self {
492        Self {
493            flags: Some(flags),
494            ..self
495        }
496    }
497
498    pub fn flags_if(self, flags: crate::VideoFlags, predicate: bool) -> Self {
499        if predicate {
500            self.flags(flags)
501        } else {
502            self
503        }
504    }
505
506    pub fn flags_if_some(self, flags: Option<crate::VideoFlags>) -> Self {
507        if let Some(flags) = flags {
508            self.flags(flags)
509        } else {
510            self
511        }
512    }
513
514    pub fn size(self, size: usize) -> Self {
515        Self {
516            size: Some(size),
517            ..self
518        }
519    }
520
521    pub fn size_if(self, size: usize, predicate: bool) -> Self {
522        if predicate {
523            self.size(size)
524        } else {
525            self
526        }
527    }
528
529    pub fn size_if_some(self, size: Option<usize>) -> Self {
530        if let Some(size) = size {
531            self.size(size)
532        } else {
533            self
534        }
535    }
536
537    pub fn views(self, views: u32) -> Self {
538        Self {
539            views: Some(views),
540            ..self
541        }
542    }
543
544    pub fn views_if(self, views: u32, predicate: bool) -> Self {
545        if predicate {
546            self.views(views)
547        } else {
548            self
549        }
550    }
551
552    pub fn views_if_some(self, views: Option<u32>) -> Self {
553        if let Some(views) = views {
554            self.views(views)
555        } else {
556            self
557        }
558    }
559
560    pub fn chroma_site(self, chroma_site: crate::VideoChromaSite) -> Self {
561        Self {
562            chroma_site: Some(chroma_site),
563            ..self
564        }
565    }
566
567    pub fn chroma_site_if(self, chroma_site: crate::VideoChromaSite, predicate: bool) -> Self {
568        if predicate {
569            self.chroma_site(chroma_site)
570        } else {
571            self
572        }
573    }
574
575    pub fn chroma_site_if_some(self, chroma_site: Option<crate::VideoChromaSite>) -> Self {
576        if let Some(chroma_site) = chroma_site {
577            self.chroma_site(chroma_site)
578        } else {
579            self
580        }
581    }
582
583    pub fn colorimetry(self, colorimetry: &crate::VideoColorimetry) -> VideoInfoBuilder<'a> {
584        Self {
585            colorimetry: Some(*colorimetry),
586            ..self
587        }
588    }
589
590    pub fn colorimetry_if(
591        self,
592        colorimetry: &crate::VideoColorimetry,
593        predicate: bool,
594    ) -> VideoInfoBuilder<'a> {
595        if predicate {
596            self.colorimetry(colorimetry)
597        } else {
598            self
599        }
600    }
601
602    pub fn colorimetry_if_some(
603        self,
604        colorimetry: Option<&crate::VideoColorimetry>,
605    ) -> VideoInfoBuilder<'a> {
606        if let Some(colorimetry) = colorimetry {
607            self.colorimetry(colorimetry)
608        } else {
609            self
610        }
611    }
612
613    pub fn par<T: Into<gst::Fraction>>(self, par: T) -> Self {
614        Self {
615            par: Some(par.into()),
616            ..self
617        }
618    }
619
620    pub fn par_if<T: Into<gst::Fraction>>(self, par: T, predicate: bool) -> Self {
621        if predicate {
622            self.par(par)
623        } else {
624            self
625        }
626    }
627
628    pub fn par_if_some<T: Into<gst::Fraction>>(self, par: Option<T>) -> Self {
629        if let Some(par) = par {
630            self.par(par)
631        } else {
632            self
633        }
634    }
635
636    pub fn fps<T: Into<gst::Fraction>>(self, fps: T) -> Self {
637        Self {
638            fps: Some(fps.into()),
639            ..self
640        }
641    }
642
643    pub fn fps_if<T: Into<gst::Fraction>>(self, fps: T, predicate: bool) -> Self {
644        if predicate {
645            self.fps(fps)
646        } else {
647            self
648        }
649    }
650
651    pub fn fps_if_some<T: Into<gst::Fraction>>(self, fps: Option<T>) -> Self {
652        if let Some(fps) = fps {
653            self.fps(fps)
654        } else {
655            self
656        }
657    }
658
659    pub fn offset(self, offset: &'a [usize]) -> VideoInfoBuilder<'a> {
660        Self {
661            offset: Some(offset),
662            ..self
663        }
664    }
665
666    pub fn offset_if(self, offset: &'a [usize], predicate: bool) -> VideoInfoBuilder<'a> {
667        if predicate {
668            self.offset(offset)
669        } else {
670            self
671        }
672    }
673
674    pub fn offset_if_some(self, offset: Option<&'a [usize]>) -> VideoInfoBuilder<'a> {
675        if let Some(offset) = offset {
676            self.offset(offset)
677        } else {
678            self
679        }
680    }
681
682    pub fn stride(self, stride: &'a [i32]) -> VideoInfoBuilder<'a> {
683        Self {
684            stride: Some(stride),
685            ..self
686        }
687    }
688
689    pub fn stride_if(self, stride: &'a [i32], predicate: bool) -> VideoInfoBuilder<'a> {
690        if predicate {
691            self.stride(stride)
692        } else {
693            self
694        }
695    }
696
697    pub fn stride_if_some(self, stride: Option<&'a [i32]>) -> VideoInfoBuilder<'a> {
698        if let Some(stride) = stride {
699            self.stride(stride)
700        } else {
701            self
702        }
703    }
704
705    pub fn multiview_mode(self, multiview_mode: crate::VideoMultiviewMode) -> Self {
706        Self {
707            multiview_mode: Some(multiview_mode),
708            ..self
709        }
710    }
711
712    pub fn multiview_mode_if(
713        self,
714        multiview_mode: crate::VideoMultiviewMode,
715        predicate: bool,
716    ) -> Self {
717        if predicate {
718            self.multiview_mode(multiview_mode)
719        } else {
720            self
721        }
722    }
723
724    pub fn multiview_mode_if_some(self, multiview_mode: Option<crate::VideoMultiviewMode>) -> Self {
725        if let Some(multiview_mode) = multiview_mode {
726            self.multiview_mode(multiview_mode)
727        } else {
728            self
729        }
730    }
731
732    pub fn multiview_flags(self, multiview_flags: crate::VideoMultiviewFlags) -> Self {
733        Self {
734            multiview_flags: Some(multiview_flags),
735            ..self
736        }
737    }
738
739    pub fn multiview_flags_if(
740        self,
741        multiview_flags: crate::VideoMultiviewFlags,
742        predicate: bool,
743    ) -> Self {
744        if predicate {
745            self.multiview_flags(multiview_flags)
746        } else {
747            self
748        }
749    }
750
751    pub fn multiview_flags_if_some(
752        self,
753        multiview_flags: Option<crate::VideoMultiviewFlags>,
754    ) -> Self {
755        if let Some(multiview_flags) = multiview_flags {
756            self.multiview_flags(multiview_flags)
757        } else {
758            self
759        }
760    }
761
762    pub fn field_order(self, field_order: crate::VideoFieldOrder) -> Self {
763        Self {
764            field_order: Some(field_order),
765            ..self
766        }
767    }
768
769    pub fn field_order_if(self, field_order: crate::VideoFieldOrder, predicate: bool) -> Self {
770        if predicate {
771            self.field_order(field_order)
772        } else {
773            self
774        }
775    }
776
777    pub fn field_order_if_some(self, field_order: Option<crate::VideoFieldOrder>) -> Self {
778        if let Some(field_order) = field_order {
779            self.field_order(field_order)
780        } else {
781            self
782        }
783    }
784}
785
786impl VideoInfo {
787    pub fn builder<'a>(
788        format: crate::VideoFormat,
789        width: u32,
790        height: u32,
791    ) -> VideoInfoBuilder<'a> {
792        assert_initialized_main_thread!();
793
794        VideoInfoBuilder {
795            format,
796            width,
797            height,
798            interlace_mode: None,
799            flags: None,
800            size: None,
801            views: None,
802            chroma_site: None,
803            colorimetry: None,
804            par: None,
805            fps: None,
806            offset: None,
807            stride: None,
808            multiview_mode: None,
809            multiview_flags: None,
810            field_order: None,
811        }
812    }
813
814    pub fn builder_from_info(info: &VideoInfo) -> VideoInfoBuilder<'_> {
815        assert_initialized_main_thread!();
816
817        VideoInfoBuilder {
818            format: info.format(),
819            width: info.width(),
820            height: info.height(),
821            interlace_mode: Some(info.interlace_mode()),
822            flags: Some(info.flags()),
823            size: Some(info.size()),
824            views: Some(info.views()),
825            chroma_site: Some(info.chroma_site()),
826            colorimetry: Some(info.colorimetry()),
827            par: Some(info.par()),
828            fps: Some(info.fps()),
829            offset: Some(info.offset()),
830            stride: Some(info.stride()),
831            multiview_mode: Some(info.multiview_mode()),
832            multiview_flags: Some(info.multiview_flags()),
833            field_order: Some(info.field_order()),
834        }
835    }
836
837    #[inline]
838    pub fn is_valid(&self) -> bool {
839        !self.0.finfo.is_null() && self.0.width > 0 && self.0.height > 0 && self.0.size > 0
840    }
841
842    /// Parse `caps` to generate a [`VideoInfo`][crate::VideoInfo].
843    /// ## `caps`
844    /// a [`gst::Caps`][crate::gst::Caps]
845    ///
846    /// # Returns
847    ///
848    /// A [`VideoInfo`][crate::VideoInfo], or [`None`] if `caps` couldn't be parsed
849    #[doc(alias = "gst_video_info_from_caps")]
850    pub fn from_caps(caps: &gst::CapsRef) -> Result<Self, glib::error::BoolError> {
851        skip_assert_initialized!();
852
853        unsafe {
854            let mut info = mem::MaybeUninit::uninit();
855            if from_glib(ffi::gst_video_info_from_caps(
856                info.as_mut_ptr(),
857                caps.as_ptr(),
858            )) {
859                Ok(Self(info.assume_init()))
860            } else {
861                Err(glib::bool_error!("Failed to create VideoInfo from caps"))
862            }
863        }
864    }
865
866    /// Convert the values of `self` into a [`gst::Caps`][crate::gst::Caps].
867    ///
868    /// # Returns
869    ///
870    /// a new [`gst::Caps`][crate::gst::Caps] containing the info of `self`.
871    #[doc(alias = "gst_video_info_to_caps")]
872    pub fn to_caps(&self) -> Result<gst::Caps, glib::error::BoolError> {
873        unsafe {
874            let result = from_glib_full(ffi::gst_video_info_to_caps(mut_override(&self.0)));
875            match result {
876                Some(c) => Ok(c),
877                None => Err(glib::bool_error!("Failed to create caps from VideoInfo")),
878            }
879        }
880    }
881
882    #[inline]
883    pub fn format(&self) -> crate::VideoFormat {
884        if self.0.finfo.is_null() {
885            return crate::VideoFormat::Unknown;
886        }
887
888        self.format_info().format()
889    }
890
891    #[inline]
892    pub fn format_info(&self) -> crate::VideoFormatInfo {
893        unsafe { crate::VideoFormatInfo::from_ptr(self.0.finfo) }
894    }
895
896    #[inline]
897    pub fn name<'a>(&self) -> &'a str {
898        self.format_info().name()
899    }
900
901    #[inline]
902    pub fn width(&self) -> u32 {
903        self.0.width as u32
904    }
905
906    #[inline]
907    pub fn height(&self) -> u32 {
908        self.0.height as u32
909    }
910
911    #[cfg(feature = "v1_16")]
912    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
913    #[inline]
914    pub fn field_height(&self) -> u32 {
915        if self.0.interlace_mode == ffi::GST_VIDEO_INTERLACE_MODE_ALTERNATE {
916            (self.0.height as u32).div_ceil(2)
917        } else {
918            self.0.height as u32
919        }
920    }
921
922    #[inline]
923    pub fn interlace_mode(&self) -> crate::VideoInterlaceMode {
924        unsafe { from_glib(self.0.interlace_mode) }
925    }
926
927    #[inline]
928    pub fn flags(&self) -> crate::VideoFlags {
929        unsafe { from_glib(self.0.flags) }
930    }
931
932    #[inline]
933    pub fn size(&self) -> usize {
934        self.0.size
935    }
936
937    #[inline]
938    pub fn views(&self) -> u32 {
939        self.0.views as u32
940    }
941
942    #[inline]
943    pub fn chroma_site(&self) -> crate::VideoChromaSite {
944        unsafe { from_glib(self.0.chroma_site) }
945    }
946
947    #[inline]
948    pub fn colorimetry(&self) -> VideoColorimetry {
949        unsafe { VideoColorimetry(ptr::read(&self.0.colorimetry)) }
950    }
951
952    #[inline]
953    pub fn comp_depth(&self, component: u8) -> u32 {
954        self.format_info().depth()[component as usize]
955    }
956
957    #[inline]
958    pub fn comp_height(&self, component: u8) -> u32 {
959        self.format_info().scale_height(component, self.height())
960    }
961
962    #[inline]
963    pub fn comp_width(&self, component: u8) -> u32 {
964        self.format_info().scale_width(component, self.width())
965    }
966
967    #[inline]
968    pub fn comp_offset(&self, component: u8) -> usize {
969        self.offset()[self.format_info().plane()[component as usize] as usize]
970            + self.format_info().poffset()[component as usize] as usize
971    }
972
973    #[inline]
974    pub fn comp_plane(&self, component: u8) -> u32 {
975        self.format_info().plane()[component as usize]
976    }
977
978    #[inline]
979    pub fn comp_poffset(&self, component: u8) -> u32 {
980        self.format_info().poffset()[component as usize]
981    }
982
983    #[inline]
984    pub fn comp_pstride(&self, component: u8) -> i32 {
985        self.format_info().pixel_stride()[component as usize]
986    }
987
988    #[inline]
989    pub fn comp_stride(&self, component: u8) -> i32 {
990        self.stride()[self.format_info().plane()[component as usize] as usize]
991    }
992
993    #[inline]
994    pub fn par(&self) -> gst::Fraction {
995        gst::Fraction::new(self.0.par_n, self.0.par_d)
996    }
997
998    #[inline]
999    pub fn fps(&self) -> gst::Fraction {
1000        gst::Fraction::new(self.0.fps_n, self.0.fps_d)
1001    }
1002
1003    #[cfg(feature = "v1_16")]
1004    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
1005    #[inline]
1006    pub fn field_rate(&self) -> gst::Fraction {
1007        if self.interlace_mode() == crate::VideoInterlaceMode::Alternate {
1008            2 * self.fps()
1009        } else {
1010            self.fps()
1011        }
1012    }
1013
1014    #[inline]
1015    pub fn offset(&self) -> &[usize] {
1016        &self.0.offset[0..(self.format_info().n_planes() as usize)]
1017    }
1018
1019    #[inline]
1020    pub fn stride(&self) -> &[i32] {
1021        &self.0.stride[0..(self.format_info().n_planes() as usize)]
1022    }
1023
1024    #[inline]
1025    pub fn multiview_mode(&self) -> crate::VideoMultiviewMode {
1026        unsafe {
1027            let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
1028            from_glib(ptr::read(ptr.offset(0)))
1029        }
1030    }
1031
1032    #[inline]
1033    pub fn multiview_flags(&self) -> crate::VideoMultiviewFlags {
1034        unsafe {
1035            let ptr = &self.0.ABI._gst_reserved as *const _ as *const u32;
1036            from_glib(ptr::read(ptr.offset(1)))
1037        }
1038    }
1039
1040    #[inline]
1041    pub fn field_order(&self) -> crate::VideoFieldOrder {
1042        unsafe {
1043            let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
1044            from_glib(ptr::read(ptr.offset(2)))
1045        }
1046    }
1047
1048    #[inline]
1049    pub fn has_alpha(&self) -> bool {
1050        self.format_info().has_alpha()
1051    }
1052
1053    #[inline]
1054    pub fn is_gray(&self) -> bool {
1055        self.format_info().is_gray()
1056    }
1057
1058    #[inline]
1059    pub fn is_rgb(&self) -> bool {
1060        self.format_info().is_rgb()
1061    }
1062
1063    #[inline]
1064    pub fn is_yuv(&self) -> bool {
1065        self.format_info().is_yuv()
1066    }
1067
1068    #[inline]
1069    pub fn is_interlaced(&self) -> bool {
1070        self.interlace_mode() != crate::VideoInterlaceMode::Progressive
1071    }
1072
1073    #[inline]
1074    pub fn n_planes(&self) -> u32 {
1075        self.format_info().n_planes()
1076    }
1077
1078    #[inline]
1079    pub fn n_components(&self) -> u32 {
1080        self.format_info().n_components()
1081    }
1082
1083    /// Converts among various [`gst::Format`][crate::gst::Format] types. This function handles
1084    /// GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT. For
1085    /// raw video, GST_FORMAT_DEFAULT corresponds to video frames. This
1086    /// function can be used to handle pad queries of the type GST_QUERY_CONVERT.
1087    /// ## `src_format`
1088    /// [`gst::Format`][crate::gst::Format] of the `src_value`
1089    /// ## `src_value`
1090    /// value to convert
1091    /// ## `dest_format`
1092    /// [`gst::Format`][crate::gst::Format] of the `dest_value`
1093    ///
1094    /// # Returns
1095    ///
1096    /// TRUE if the conversion was successful.
1097    ///
1098    /// ## `dest_value`
1099    /// pointer to destination value
1100    #[doc(alias = "gst_video_info_convert")]
1101    pub fn convert<U: gst::format::SpecificFormattedValueFullRange>(
1102        &self,
1103        src_val: impl gst::format::FormattedValue,
1104    ) -> Option<U> {
1105        skip_assert_initialized!();
1106        unsafe {
1107            let mut dest_val = mem::MaybeUninit::uninit();
1108            if from_glib(ffi::gst_video_info_convert(
1109                mut_override(&self.0),
1110                src_val.format().into_glib(),
1111                src_val.into_raw_value(),
1112                U::default_format().into_glib(),
1113                dest_val.as_mut_ptr(),
1114            )) {
1115                Some(U::from_raw(U::default_format(), dest_val.assume_init()))
1116            } else {
1117                None
1118            }
1119        }
1120    }
1121
1122    pub fn convert_generic(
1123        &self,
1124        src_val: impl gst::format::FormattedValue,
1125        dest_fmt: gst::Format,
1126    ) -> Option<gst::GenericFormattedValue> {
1127        skip_assert_initialized!();
1128        unsafe {
1129            let mut dest_val = mem::MaybeUninit::uninit();
1130            if from_glib(ffi::gst_video_info_convert(
1131                mut_override(&self.0),
1132                src_val.format().into_glib(),
1133                src_val.into_raw_value(),
1134                dest_fmt.into_glib(),
1135                dest_val.as_mut_ptr(),
1136            )) {
1137                Some(gst::GenericFormattedValue::new(
1138                    dest_fmt,
1139                    dest_val.assume_init(),
1140                ))
1141            } else {
1142                None
1143            }
1144        }
1145    }
1146
1147    /// Adjust the offset and stride fields in `self` so that the padding and
1148    /// stride alignment in `align` is respected.
1149    ///
1150    /// Extra padding will be added to the right side when stride alignment padding
1151    /// is required and `align` will be updated with the new padding values.
1152    /// ## `align`
1153    /// alignment parameters
1154    ///
1155    /// # Returns
1156    ///
1157    /// [`false`] if alignment could not be applied, e.g. because the
1158    ///  size of a frame can't be represented as a 32 bit integer (Since: 1.12)
1159    #[doc(alias = "gst_video_info_align")]
1160    pub fn align(&mut self, align: &mut crate::VideoAlignment) -> Result<(), glib::BoolError> {
1161        unsafe {
1162            glib::result_from_gboolean!(
1163                ffi::gst_video_info_align(&mut self.0, &mut align.0,),
1164                "Failed to align VideoInfo"
1165            )
1166        }
1167    }
1168
1169    /// Extra padding will be added to the right side when stride alignment padding
1170    /// is required and `align` will be updated with the new padding values.
1171    ///
1172    /// This variant of [`align()`][Self::align()] provides the updated size, in bytes,
1173    /// of each video plane after the alignment, including all horizontal and vertical
1174    /// paddings.
1175    ///
1176    /// In case of GST_VIDEO_INTERLACE_MODE_ALTERNATE info, the returned sizes are the
1177    /// ones used to hold a single field, not the full frame.
1178    /// ## `align`
1179    /// alignment parameters
1180    ///
1181    /// # Returns
1182    ///
1183    /// [`false`] if alignment could not be applied, e.g. because the
1184    ///  size of a frame can't be represented as a 32 bit integer
1185    ///
1186    /// ## `plane_size`
1187    /// array used to store the plane sizes
1188    #[cfg(feature = "v1_18")]
1189    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
1190    #[doc(alias = "gst_video_info_align_full")]
1191    pub fn align_full(
1192        &mut self,
1193        align: &mut crate::VideoAlignment,
1194    ) -> Result<[usize; crate::VIDEO_MAX_PLANES], glib::BoolError> {
1195        let mut plane_size = [0; crate::VIDEO_MAX_PLANES];
1196
1197        unsafe {
1198            glib::result_from_gboolean!(
1199                ffi::gst_video_info_align_full(&mut self.0, &mut align.0, plane_size.as_mut_ptr()),
1200                "Failed to align VideoInfo"
1201            )?;
1202        }
1203
1204        Ok(plane_size)
1205    }
1206
1207    #[doc(alias = "gst_video_color_range_offsets")]
1208    #[inline]
1209    pub fn range_offsets(&self, range: crate::VideoColorRange) -> ([i32; 4], [i32; 4]) {
1210        self.format_info().range_offsets(range)
1211    }
1212}
1213
1214impl PartialEq for VideoInfo {
1215    #[doc(alias = "gst_video_info_is_equal")]
1216    fn eq(&self, other: &Self) -> bool {
1217        unsafe { from_glib(ffi::gst_video_info_is_equal(&self.0, &other.0)) }
1218    }
1219}
1220
1221impl Eq for VideoInfo {}
1222
1223unsafe impl Send for VideoInfo {}
1224unsafe impl Sync for VideoInfo {}
1225
1226impl glib::types::StaticType for VideoInfo {
1227    #[inline]
1228    fn static_type() -> glib::types::Type {
1229        unsafe { glib::translate::from_glib(ffi::gst_video_info_get_type()) }
1230    }
1231}
1232
1233impl glib::value::ValueType for VideoInfo {
1234    type Type = Self;
1235}
1236
1237#[doc(hidden)]
1238unsafe impl<'a> glib::value::FromValue<'a> for VideoInfo {
1239    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
1240
1241    unsafe fn from_value(value: &'a glib::Value) -> Self {
1242        skip_assert_initialized!();
1243        from_glib_none(
1244            glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstVideoInfo
1245        )
1246    }
1247}
1248
1249#[doc(hidden)]
1250impl glib::value::ToValue for VideoInfo {
1251    fn to_value(&self) -> glib::Value {
1252        let mut value = glib::Value::for_value_type::<Self>();
1253        unsafe {
1254            glib::gobject_ffi::g_value_set_boxed(
1255                value.to_glib_none_mut().0,
1256                self.to_glib_none().0 as *mut _,
1257            )
1258        }
1259        value
1260    }
1261
1262    fn value_type(&self) -> glib::Type {
1263        Self::static_type()
1264    }
1265}
1266
1267#[doc(hidden)]
1268impl glib::value::ToValueOptional for VideoInfo {
1269    fn to_value_optional(s: Option<&Self>) -> glib::Value {
1270        skip_assert_initialized!();
1271        let mut value = glib::Value::for_value_type::<Self>();
1272        unsafe {
1273            glib::gobject_ffi::g_value_set_boxed(
1274                value.to_glib_none_mut().0,
1275                s.to_glib_none().0 as *mut _,
1276            )
1277        }
1278        value
1279    }
1280}
1281
1282#[doc(hidden)]
1283impl From<VideoInfo> for glib::Value {
1284    fn from(v: VideoInfo) -> glib::Value {
1285        skip_assert_initialized!();
1286        glib::value::ToValue::to_value(&v)
1287    }
1288}
1289
1290#[doc(hidden)]
1291impl glib::translate::Uninitialized for VideoInfo {
1292    #[inline]
1293    unsafe fn uninitialized() -> Self {
1294        mem::zeroed()
1295    }
1296}
1297
1298#[doc(hidden)]
1299impl glib::translate::GlibPtrDefault for VideoInfo {
1300    type GlibType = *mut ffi::GstVideoInfo;
1301}
1302
1303#[doc(hidden)]
1304impl<'a> glib::translate::ToGlibPtr<'a, *const ffi::GstVideoInfo> for VideoInfo {
1305    type Storage = PhantomData<&'a Self>;
1306
1307    #[inline]
1308    fn to_glib_none(&'a self) -> glib::translate::Stash<'a, *const ffi::GstVideoInfo, Self> {
1309        glib::translate::Stash(&self.0, PhantomData)
1310    }
1311
1312    fn to_glib_full(&self) -> *const ffi::GstVideoInfo {
1313        unimplemented!()
1314    }
1315}
1316
1317#[doc(hidden)]
1318impl glib::translate::FromGlibPtrNone<*const ffi::GstVideoInfo> for VideoInfo {
1319    #[inline]
1320    unsafe fn from_glib_none(ptr: *const ffi::GstVideoInfo) -> Self {
1321        Self(ptr::read(ptr))
1322    }
1323}
1324
1325#[doc(hidden)]
1326impl glib::translate::FromGlibPtrNone<*mut ffi::GstVideoInfo> for VideoInfo {
1327    #[inline]
1328    unsafe fn from_glib_none(ptr: *mut ffi::GstVideoInfo) -> Self {
1329        Self(ptr::read(ptr))
1330    }
1331}
1332
1333#[doc(hidden)]
1334impl glib::translate::FromGlibPtrFull<*mut ffi::GstVideoInfo> for VideoInfo {
1335    #[inline]
1336    unsafe fn from_glib_full(ptr: *mut ffi::GstVideoInfo) -> Self {
1337        let info = from_glib_none(ptr);
1338        glib::ffi::g_free(ptr as *mut _);
1339        info
1340    }
1341}
1342
1343impl crate::VideoFieldOrder {
1344    #[doc(alias = "gst_video_field_order_to_string")]
1345    pub fn to_str<'a>(self) -> &'a str {
1346        use std::ffi::CStr;
1347
1348        if self == Self::Unknown {
1349            return "UNKNOWN";
1350        }
1351        unsafe {
1352            CStr::from_ptr(
1353                ffi::gst_video_field_order_to_string(self.into_glib())
1354                    .as_ref()
1355                    .expect("gst_video_field_order_to_string returned NULL"),
1356            )
1357            .to_str()
1358            .expect("gst_video_field_order_to_string returned an invalid string")
1359        }
1360    }
1361}
1362
1363impl str::FromStr for crate::VideoFieldOrder {
1364    type Err = glib::error::BoolError;
1365
1366    fn from_str(s: &str) -> Result<Self, Self::Err> {
1367        skip_assert_initialized!();
1368
1369        let fmt = Self::from_string(s);
1370        if fmt == Self::Unknown {
1371            Err(glib::bool_error!(
1372                "Failed to parse video field order from string"
1373            ))
1374        } else {
1375            Ok(fmt)
1376        }
1377    }
1378}
1379
1380impl str::FromStr for crate::VideoInterlaceMode {
1381    type Err = glib::error::BoolError;
1382
1383    fn from_str(s: &str) -> Result<Self, Self::Err> {
1384        skip_assert_initialized!();
1385
1386        let fmt = Self::from_string(s);
1387        Ok(fmt)
1388    }
1389}
1390
1391#[cfg(test)]
1392mod tests {
1393    use super::*;
1394
1395    #[test]
1396    fn test_new() {
1397        gst::init().unwrap();
1398
1399        let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1400            .build()
1401            .unwrap();
1402        assert_eq!(info.format(), crate::VideoFormat::I420);
1403        assert_eq!(info.width(), 320);
1404        assert_eq!(info.height(), 240);
1405        assert_eq!(info.size(), 320 * 240 + 2 * 160 * 120);
1406        assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::None);
1407        assert_eq!(&info.offset(), &[0, 320 * 240, 320 * 240 + 160 * 120]);
1408        assert_eq!(&info.stride(), &[320, 160, 160]);
1409
1410        let offsets = [0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16];
1411        let strides = [640, 320, 320];
1412        let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1413            .offset(&offsets)
1414            .stride(&strides)
1415            .size(640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16)
1416            .multiview_mode(crate::VideoMultiviewMode::SideBySide)
1417            .build()
1418            .unwrap();
1419        assert_eq!(info.format(), crate::VideoFormat::I420);
1420        assert_eq!(info.width(), 320);
1421        assert_eq!(info.height(), 240);
1422        assert_eq!(
1423            info.size(),
1424            640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16
1425        );
1426        assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::SideBySide);
1427        assert_eq!(
1428            &info.offset(),
1429            &[0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16]
1430        );
1431        assert_eq!(&info.stride(), &[640, 320, 320]);
1432    }
1433
1434    #[test]
1435    fn test_from_to_caps() {
1436        gst::init().unwrap();
1437
1438        let caps = crate::VideoCapsBuilder::new()
1439            .format(crate::VideoFormat::I420)
1440            .width(320)
1441            .height(240)
1442            .framerate((30, 1).into())
1443            .pixel_aspect_ratio((1, 1).into())
1444            .field("interlace-mode", "progressive")
1445            .field("chroma-site", "mpeg2")
1446            .field("colorimetry", "bt709")
1447            .build();
1448        let info = VideoInfo::from_caps(&caps).unwrap();
1449        assert_eq!(info.format(), crate::VideoFormat::I420);
1450        assert_eq!(info.width(), 320);
1451        assert_eq!(info.height(), 240);
1452        assert_eq!(info.fps(), gst::Fraction::new(30, 1));
1453        assert_eq!(
1454            info.interlace_mode(),
1455            crate::VideoInterlaceMode::Progressive
1456        );
1457        assert_eq!(info.chroma_site(), crate::VideoChromaSite::MPEG2);
1458        assert_eq!(info.colorimetry(), "bt709".parse().unwrap());
1459
1460        let caps2 = info.to_caps().unwrap();
1461        assert_eq!(caps, caps2);
1462
1463        let info2 = VideoInfo::from_caps(&caps2).unwrap();
1464        assert!(info == info2);
1465    }
1466
1467    #[test]
1468    fn test_video_align() {
1469        gst::init().unwrap();
1470
1471        let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1472            .build()
1473            .expect("Failed to create VideoInfo");
1474
1475        assert_eq!(info.stride(), [1920, 1920]);
1476        assert_eq!(info.offset(), [0, 2_073_600]);
1477
1478        let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1479        info.align(&mut align).unwrap();
1480
1481        assert_eq!(info.stride(), [1928, 1928]);
1482        assert_eq!(info.offset(), [0, 2_082_240]);
1483
1484        #[cfg(feature = "v1_18")]
1485        {
1486            let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1487                .build()
1488                .expect("Failed to create VideoInfo");
1489
1490            let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1491            let plane_size = info.align_full(&mut align).unwrap();
1492            assert_eq!(plane_size, [2082240, 2082240, 0, 0]);
1493        }
1494    }
1495
1496    #[test]
1497    fn test_display() {
1498        gst::init().unwrap();
1499
1500        let _ = format!("{}", "sRGB".parse::<crate::VideoColorimetry>().unwrap());
1501        let _ = format!("{}", crate::VideoFieldOrder::TopFieldFirst);
1502        let _ = format!("{}", crate::VideoInterlaceMode::Progressive);
1503    }
1504}