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                info.offset[..offset.len()].copy_from_slice(offset);
429            }
430
431            if let Some(stride) = self.stride {
432                info.stride[..stride.len()].copy_from_slice(stride);
433            }
434
435            if let Some(multiview_mode) = self.multiview_mode {
436                info.ABI.abi.multiview_mode = multiview_mode.into_glib();
437            }
438
439            if let Some(multiview_flags) = self.multiview_flags {
440                info.ABI.abi.multiview_flags = multiview_flags.into_glib();
441            }
442
443            if let Some(field_order) = self.field_order {
444                info.ABI.abi.field_order = field_order.into_glib();
445            }
446
447            Ok(VideoInfo(info))
448        }
449    }
450
451    pub fn interlace_mode(self, interlace_mode: crate::VideoInterlaceMode) -> VideoInfoBuilder<'a> {
452        Self {
453            interlace_mode: Some(interlace_mode),
454            ..self
455        }
456    }
457
458    pub fn interlace_mode_if(
459        self,
460        interlace_mode: crate::VideoInterlaceMode,
461        predicate: bool,
462    ) -> VideoInfoBuilder<'a> {
463        if predicate {
464            self.interlace_mode(interlace_mode)
465        } else {
466            self
467        }
468    }
469
470    pub fn interlace_mode_if_some(
471        self,
472        interlace_mode: Option<crate::VideoInterlaceMode>,
473    ) -> VideoInfoBuilder<'a> {
474        if let Some(interlace_mode) = interlace_mode {
475            self.interlace_mode(interlace_mode)
476        } else {
477            self
478        }
479    }
480
481    pub fn flags(self, flags: crate::VideoFlags) -> Self {
482        Self {
483            flags: Some(flags),
484            ..self
485        }
486    }
487
488    pub fn flags_if(self, flags: crate::VideoFlags, predicate: bool) -> Self {
489        if predicate {
490            self.flags(flags)
491        } else {
492            self
493        }
494    }
495
496    pub fn flags_if_some(self, flags: Option<crate::VideoFlags>) -> Self {
497        if let Some(flags) = flags {
498            self.flags(flags)
499        } else {
500            self
501        }
502    }
503
504    pub fn size(self, size: usize) -> Self {
505        Self {
506            size: Some(size),
507            ..self
508        }
509    }
510
511    pub fn size_if(self, size: usize, predicate: bool) -> Self {
512        if predicate {
513            self.size(size)
514        } else {
515            self
516        }
517    }
518
519    pub fn size_if_some(self, size: Option<usize>) -> Self {
520        if let Some(size) = size {
521            self.size(size)
522        } else {
523            self
524        }
525    }
526
527    pub fn views(self, views: u32) -> Self {
528        Self {
529            views: Some(views),
530            ..self
531        }
532    }
533
534    pub fn views_if(self, views: u32, predicate: bool) -> Self {
535        if predicate {
536            self.views(views)
537        } else {
538            self
539        }
540    }
541
542    pub fn views_if_some(self, views: Option<u32>) -> Self {
543        if let Some(views) = views {
544            self.views(views)
545        } else {
546            self
547        }
548    }
549
550    pub fn chroma_site(self, chroma_site: crate::VideoChromaSite) -> Self {
551        Self {
552            chroma_site: Some(chroma_site),
553            ..self
554        }
555    }
556
557    pub fn chroma_site_if(self, chroma_site: crate::VideoChromaSite, predicate: bool) -> Self {
558        if predicate {
559            self.chroma_site(chroma_site)
560        } else {
561            self
562        }
563    }
564
565    pub fn chroma_site_if_some(self, chroma_site: Option<crate::VideoChromaSite>) -> Self {
566        if let Some(chroma_site) = chroma_site {
567            self.chroma_site(chroma_site)
568        } else {
569            self
570        }
571    }
572
573    pub fn colorimetry(self, colorimetry: &crate::VideoColorimetry) -> VideoInfoBuilder<'a> {
574        Self {
575            colorimetry: Some(*colorimetry),
576            ..self
577        }
578    }
579
580    pub fn colorimetry_if(
581        self,
582        colorimetry: &crate::VideoColorimetry,
583        predicate: bool,
584    ) -> VideoInfoBuilder<'a> {
585        if predicate {
586            self.colorimetry(colorimetry)
587        } else {
588            self
589        }
590    }
591
592    pub fn colorimetry_if_some(
593        self,
594        colorimetry: Option<&crate::VideoColorimetry>,
595    ) -> VideoInfoBuilder<'a> {
596        if let Some(colorimetry) = colorimetry {
597            self.colorimetry(colorimetry)
598        } else {
599            self
600        }
601    }
602
603    pub fn par<T: Into<gst::Fraction>>(self, par: T) -> Self {
604        Self {
605            par: Some(par.into()),
606            ..self
607        }
608    }
609
610    pub fn par_if<T: Into<gst::Fraction>>(self, par: T, predicate: bool) -> Self {
611        if predicate {
612            self.par(par)
613        } else {
614            self
615        }
616    }
617
618    pub fn par_if_some<T: Into<gst::Fraction>>(self, par: Option<T>) -> Self {
619        if let Some(par) = par {
620            self.par(par)
621        } else {
622            self
623        }
624    }
625
626    pub fn fps<T: Into<gst::Fraction>>(self, fps: T) -> Self {
627        Self {
628            fps: Some(fps.into()),
629            ..self
630        }
631    }
632
633    pub fn fps_if<T: Into<gst::Fraction>>(self, fps: T, predicate: bool) -> Self {
634        if predicate {
635            self.fps(fps)
636        } else {
637            self
638        }
639    }
640
641    pub fn fps_if_some<T: Into<gst::Fraction>>(self, fps: Option<T>) -> Self {
642        if let Some(fps) = fps {
643            self.fps(fps)
644        } else {
645            self
646        }
647    }
648
649    pub fn offset(self, offset: &'a [usize]) -> VideoInfoBuilder<'a> {
650        Self {
651            offset: Some(offset),
652            ..self
653        }
654    }
655
656    pub fn offset_if(self, offset: &'a [usize], predicate: bool) -> VideoInfoBuilder<'a> {
657        if predicate {
658            self.offset(offset)
659        } else {
660            self
661        }
662    }
663
664    pub fn offset_if_some(self, offset: Option<&'a [usize]>) -> VideoInfoBuilder<'a> {
665        if let Some(offset) = offset {
666            self.offset(offset)
667        } else {
668            self
669        }
670    }
671
672    pub fn stride(self, stride: &'a [i32]) -> VideoInfoBuilder<'a> {
673        Self {
674            stride: Some(stride),
675            ..self
676        }
677    }
678
679    pub fn stride_if(self, stride: &'a [i32], predicate: bool) -> VideoInfoBuilder<'a> {
680        if predicate {
681            self.stride(stride)
682        } else {
683            self
684        }
685    }
686
687    pub fn stride_if_some(self, stride: Option<&'a [i32]>) -> VideoInfoBuilder<'a> {
688        if let Some(stride) = stride {
689            self.stride(stride)
690        } else {
691            self
692        }
693    }
694
695    pub fn multiview_mode(self, multiview_mode: crate::VideoMultiviewMode) -> Self {
696        Self {
697            multiview_mode: Some(multiview_mode),
698            ..self
699        }
700    }
701
702    pub fn multiview_mode_if(
703        self,
704        multiview_mode: crate::VideoMultiviewMode,
705        predicate: bool,
706    ) -> Self {
707        if predicate {
708            self.multiview_mode(multiview_mode)
709        } else {
710            self
711        }
712    }
713
714    pub fn multiview_mode_if_some(self, multiview_mode: Option<crate::VideoMultiviewMode>) -> Self {
715        if let Some(multiview_mode) = multiview_mode {
716            self.multiview_mode(multiview_mode)
717        } else {
718            self
719        }
720    }
721
722    pub fn multiview_flags(self, multiview_flags: crate::VideoMultiviewFlags) -> Self {
723        Self {
724            multiview_flags: Some(multiview_flags),
725            ..self
726        }
727    }
728
729    pub fn multiview_flags_if(
730        self,
731        multiview_flags: crate::VideoMultiviewFlags,
732        predicate: bool,
733    ) -> Self {
734        if predicate {
735            self.multiview_flags(multiview_flags)
736        } else {
737            self
738        }
739    }
740
741    pub fn multiview_flags_if_some(
742        self,
743        multiview_flags: Option<crate::VideoMultiviewFlags>,
744    ) -> Self {
745        if let Some(multiview_flags) = multiview_flags {
746            self.multiview_flags(multiview_flags)
747        } else {
748            self
749        }
750    }
751
752    pub fn field_order(self, field_order: crate::VideoFieldOrder) -> Self {
753        Self {
754            field_order: Some(field_order),
755            ..self
756        }
757    }
758
759    pub fn field_order_if(self, field_order: crate::VideoFieldOrder, predicate: bool) -> Self {
760        if predicate {
761            self.field_order(field_order)
762        } else {
763            self
764        }
765    }
766
767    pub fn field_order_if_some(self, field_order: Option<crate::VideoFieldOrder>) -> Self {
768        if let Some(field_order) = field_order {
769            self.field_order(field_order)
770        } else {
771            self
772        }
773    }
774}
775
776impl VideoInfo {
777    pub fn builder<'a>(
778        format: crate::VideoFormat,
779        width: u32,
780        height: u32,
781    ) -> VideoInfoBuilder<'a> {
782        assert_initialized_main_thread!();
783
784        VideoInfoBuilder {
785            format,
786            width,
787            height,
788            interlace_mode: None,
789            flags: None,
790            size: None,
791            views: None,
792            chroma_site: None,
793            colorimetry: None,
794            par: None,
795            fps: None,
796            offset: None,
797            stride: None,
798            multiview_mode: None,
799            multiview_flags: None,
800            field_order: None,
801        }
802    }
803
804    pub fn builder_from_info(info: &VideoInfo) -> VideoInfoBuilder<'_> {
805        assert_initialized_main_thread!();
806
807        VideoInfoBuilder {
808            format: info.format(),
809            width: info.width(),
810            height: info.height(),
811            interlace_mode: Some(info.interlace_mode()),
812            flags: Some(info.flags()),
813            size: Some(info.size()),
814            views: Some(info.views()),
815            chroma_site: Some(info.chroma_site()),
816            colorimetry: Some(info.colorimetry()),
817            par: Some(info.par()),
818            fps: Some(info.fps()),
819            offset: Some(info.offset()),
820            stride: Some(info.stride()),
821            multiview_mode: Some(info.multiview_mode()),
822            multiview_flags: Some(info.multiview_flags()),
823            field_order: Some(info.field_order()),
824        }
825    }
826
827    #[inline]
828    pub fn is_valid(&self) -> bool {
829        !self.0.finfo.is_null()
830            && self.0.width > 0
831            && self.0.height > 0
832            && (self.0.size > 0 || unsafe { (*self.0.finfo).n_planes } == 0)
833    }
834
835    /// Parse `caps` to generate a [`VideoInfo`][crate::VideoInfo].
836    /// ## `caps`
837    /// a [`gst::Caps`][crate::gst::Caps]
838    ///
839    /// # Returns
840    ///
841    /// A [`VideoInfo`][crate::VideoInfo], or [`None`] if `caps` couldn't be parsed
842    #[doc(alias = "gst_video_info_from_caps")]
843    pub fn from_caps(caps: &gst::CapsRef) -> Result<Self, glib::error::BoolError> {
844        skip_assert_initialized!();
845
846        unsafe {
847            let mut info = mem::MaybeUninit::uninit();
848            if from_glib(ffi::gst_video_info_from_caps(
849                info.as_mut_ptr(),
850                caps.as_ptr(),
851            )) {
852                Ok(Self(info.assume_init()))
853            } else {
854                Err(glib::bool_error!("Failed to create VideoInfo from caps"))
855            }
856        }
857    }
858
859    /// Convert the values of `self` into a [`gst::Caps`][crate::gst::Caps].
860    ///
861    /// # Returns
862    ///
863    /// a new [`gst::Caps`][crate::gst::Caps] containing the info of `self`.
864    #[doc(alias = "gst_video_info_to_caps")]
865    pub fn to_caps(&self) -> Result<gst::Caps, glib::error::BoolError> {
866        unsafe {
867            let result = from_glib_full(ffi::gst_video_info_to_caps(mut_override(&self.0)));
868            match result {
869                Some(c) => Ok(c),
870                None => Err(glib::bool_error!("Failed to create caps from VideoInfo")),
871            }
872        }
873    }
874
875    #[inline]
876    pub fn format(&self) -> crate::VideoFormat {
877        if self.0.finfo.is_null() {
878            return crate::VideoFormat::Unknown;
879        }
880
881        self.format_info().format()
882    }
883
884    #[inline]
885    pub fn format_info(&self) -> crate::VideoFormatInfo {
886        unsafe { crate::VideoFormatInfo::from_ptr(self.0.finfo) }
887    }
888
889    #[inline]
890    pub fn name<'a>(&self) -> &'a str {
891        self.format_info().name()
892    }
893
894    #[inline]
895    pub fn width(&self) -> u32 {
896        self.0.width as u32
897    }
898
899    #[inline]
900    pub fn height(&self) -> u32 {
901        self.0.height as u32
902    }
903
904    #[cfg(feature = "v1_16")]
905    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
906    #[inline]
907    pub fn field_height(&self) -> u32 {
908        if self.0.interlace_mode == ffi::GST_VIDEO_INTERLACE_MODE_ALTERNATE {
909            (self.0.height as u32).div_ceil(2)
910        } else {
911            self.0.height as u32
912        }
913    }
914
915    #[inline]
916    pub fn interlace_mode(&self) -> crate::VideoInterlaceMode {
917        unsafe { from_glib(self.0.interlace_mode) }
918    }
919
920    #[inline]
921    pub fn flags(&self) -> crate::VideoFlags {
922        unsafe { from_glib(self.0.flags) }
923    }
924
925    #[inline]
926    pub fn size(&self) -> usize {
927        self.0.size
928    }
929
930    #[inline]
931    pub fn views(&self) -> u32 {
932        self.0.views as u32
933    }
934
935    #[inline]
936    pub fn chroma_site(&self) -> crate::VideoChromaSite {
937        unsafe { from_glib(self.0.chroma_site) }
938    }
939
940    #[inline]
941    pub fn colorimetry(&self) -> VideoColorimetry {
942        unsafe { VideoColorimetry(ptr::read(&self.0.colorimetry)) }
943    }
944
945    #[inline]
946    pub fn comp_depth(&self, component: u8) -> u32 {
947        self.format_info().depth()[component as usize]
948    }
949
950    #[inline]
951    pub fn comp_height(&self, component: u8) -> u32 {
952        self.format_info().scale_height(component, self.height())
953    }
954
955    #[inline]
956    pub fn comp_width(&self, component: u8) -> u32 {
957        self.format_info().scale_width(component, self.width())
958    }
959
960    #[inline]
961    pub fn comp_offset(&self, component: u8) -> usize {
962        self.offset()[self.format_info().plane()[component as usize] as usize]
963            + self.format_info().poffset()[component as usize] as usize
964    }
965
966    #[inline]
967    pub fn comp_plane(&self, component: u8) -> u32 {
968        self.format_info().plane()[component as usize]
969    }
970
971    #[inline]
972    pub fn comp_poffset(&self, component: u8) -> u32 {
973        self.format_info().poffset()[component as usize]
974    }
975
976    #[inline]
977    pub fn comp_pstride(&self, component: u8) -> i32 {
978        self.format_info().pixel_stride()[component as usize]
979    }
980
981    #[inline]
982    pub fn comp_stride(&self, component: u8) -> i32 {
983        self.stride()[self.format_info().plane()[component as usize] as usize]
984    }
985
986    #[inline]
987    pub fn par(&self) -> gst::Fraction {
988        gst::Fraction::new(self.0.par_n, self.0.par_d)
989    }
990
991    #[inline]
992    pub fn fps(&self) -> gst::Fraction {
993        gst::Fraction::new(self.0.fps_n, self.0.fps_d)
994    }
995
996    #[cfg(feature = "v1_16")]
997    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
998    #[inline]
999    pub fn field_rate(&self) -> gst::Fraction {
1000        if self.interlace_mode() == crate::VideoInterlaceMode::Alternate {
1001            2 * self.fps()
1002        } else {
1003            self.fps()
1004        }
1005    }
1006
1007    #[inline]
1008    pub fn offset(&self) -> &[usize] {
1009        &self.0.offset[0..(self.format_info().n_planes() as usize)]
1010    }
1011
1012    #[inline]
1013    pub fn stride(&self) -> &[i32] {
1014        &self.0.stride[0..(self.format_info().n_planes() as usize)]
1015    }
1016
1017    #[inline]
1018    pub fn multiview_mode(&self) -> crate::VideoMultiviewMode {
1019        unsafe {
1020            let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
1021            from_glib(ptr::read(ptr.offset(0)))
1022        }
1023    }
1024
1025    #[inline]
1026    pub fn multiview_flags(&self) -> crate::VideoMultiviewFlags {
1027        unsafe {
1028            let ptr = &self.0.ABI._gst_reserved as *const _ as *const u32;
1029            from_glib(ptr::read(ptr.offset(1)))
1030        }
1031    }
1032
1033    #[inline]
1034    pub fn field_order(&self) -> crate::VideoFieldOrder {
1035        unsafe {
1036            let ptr = &self.0.ABI._gst_reserved as *const _ as *const i32;
1037            from_glib(ptr::read(ptr.offset(2)))
1038        }
1039    }
1040
1041    #[inline]
1042    pub fn has_alpha(&self) -> bool {
1043        self.format_info().has_alpha()
1044    }
1045
1046    #[inline]
1047    pub fn is_gray(&self) -> bool {
1048        self.format_info().is_gray()
1049    }
1050
1051    #[inline]
1052    pub fn is_rgb(&self) -> bool {
1053        self.format_info().is_rgb()
1054    }
1055
1056    #[inline]
1057    pub fn is_yuv(&self) -> bool {
1058        self.format_info().is_yuv()
1059    }
1060
1061    #[inline]
1062    pub fn is_interlaced(&self) -> bool {
1063        self.interlace_mode() != crate::VideoInterlaceMode::Progressive
1064    }
1065
1066    #[inline]
1067    pub fn n_planes(&self) -> u32 {
1068        self.format_info().n_planes()
1069    }
1070
1071    #[inline]
1072    pub fn n_components(&self) -> u32 {
1073        self.format_info().n_components()
1074    }
1075
1076    /// Converts among various [`gst::Format`][crate::gst::Format] types. This function handles
1077    /// GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT. For
1078    /// raw video, GST_FORMAT_DEFAULT corresponds to video frames. This
1079    /// function can be used to handle pad queries of the type GST_QUERY_CONVERT.
1080    /// ## `src_format`
1081    /// [`gst::Format`][crate::gst::Format] of the `src_value`
1082    /// ## `src_value`
1083    /// value to convert
1084    /// ## `dest_format`
1085    /// [`gst::Format`][crate::gst::Format] of the `dest_value`
1086    ///
1087    /// # Returns
1088    ///
1089    /// TRUE if the conversion was successful.
1090    ///
1091    /// ## `dest_value`
1092    /// pointer to destination value
1093    #[doc(alias = "gst_video_info_convert")]
1094    pub fn convert<U: gst::format::SpecificFormattedValueFullRange>(
1095        &self,
1096        src_val: impl gst::format::FormattedValue,
1097    ) -> Option<U> {
1098        skip_assert_initialized!();
1099        unsafe {
1100            let mut dest_val = mem::MaybeUninit::uninit();
1101            if from_glib(ffi::gst_video_info_convert(
1102                mut_override(&self.0),
1103                src_val.format().into_glib(),
1104                src_val.into_raw_value(),
1105                U::default_format().into_glib(),
1106                dest_val.as_mut_ptr(),
1107            )) {
1108                Some(U::from_raw(U::default_format(), dest_val.assume_init()))
1109            } else {
1110                None
1111            }
1112        }
1113    }
1114
1115    pub fn convert_generic(
1116        &self,
1117        src_val: impl gst::format::FormattedValue,
1118        dest_fmt: gst::Format,
1119    ) -> Option<gst::GenericFormattedValue> {
1120        skip_assert_initialized!();
1121        unsafe {
1122            let mut dest_val = mem::MaybeUninit::uninit();
1123            if from_glib(ffi::gst_video_info_convert(
1124                mut_override(&self.0),
1125                src_val.format().into_glib(),
1126                src_val.into_raw_value(),
1127                dest_fmt.into_glib(),
1128                dest_val.as_mut_ptr(),
1129            )) {
1130                Some(gst::GenericFormattedValue::new(
1131                    dest_fmt,
1132                    dest_val.assume_init(),
1133                ))
1134            } else {
1135                None
1136            }
1137        }
1138    }
1139
1140    /// Adjust the offset and stride fields in `self` so that the padding and
1141    /// stride alignment in `align` is respected.
1142    ///
1143    /// Extra padding will be added to the right side when stride alignment padding
1144    /// is required and `align` will be updated with the new padding values.
1145    /// ## `align`
1146    /// alignment parameters
1147    ///
1148    /// # Returns
1149    ///
1150    /// [`false`] if alignment could not be applied, e.g. because the
1151    ///  size of a frame can't be represented as a 32 bit integer (Since: 1.12)
1152    #[doc(alias = "gst_video_info_align")]
1153    pub fn align(&mut self, align: &mut crate::VideoAlignment) -> Result<(), glib::BoolError> {
1154        unsafe {
1155            glib::result_from_gboolean!(
1156                ffi::gst_video_info_align(&mut self.0, &mut align.0,),
1157                "Failed to align VideoInfo"
1158            )
1159        }
1160    }
1161
1162    /// Extra padding will be added to the right side when stride alignment padding
1163    /// is required and `align` will be updated with the new padding values.
1164    ///
1165    /// This variant of [`align()`][Self::align()] provides the updated size, in bytes,
1166    /// of each video plane after the alignment, including all horizontal and vertical
1167    /// paddings.
1168    ///
1169    /// In case of GST_VIDEO_INTERLACE_MODE_ALTERNATE info, the returned sizes are the
1170    /// ones used to hold a single field, not the full frame.
1171    /// ## `align`
1172    /// alignment parameters
1173    ///
1174    /// # Returns
1175    ///
1176    /// [`false`] if alignment could not be applied, e.g. because the
1177    ///  size of a frame can't be represented as a 32 bit integer
1178    ///
1179    /// ## `plane_size`
1180    /// array used to store the plane sizes
1181    #[cfg(feature = "v1_18")]
1182    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
1183    #[doc(alias = "gst_video_info_align_full")]
1184    pub fn align_full(
1185        &mut self,
1186        align: &mut crate::VideoAlignment,
1187    ) -> Result<[usize; crate::VIDEO_MAX_PLANES], glib::BoolError> {
1188        let mut plane_size = [0; crate::VIDEO_MAX_PLANES];
1189
1190        unsafe {
1191            glib::result_from_gboolean!(
1192                ffi::gst_video_info_align_full(&mut self.0, &mut align.0, plane_size.as_mut_ptr()),
1193                "Failed to align VideoInfo"
1194            )?;
1195        }
1196
1197        Ok(plane_size)
1198    }
1199
1200    #[doc(alias = "gst_video_color_range_offsets")]
1201    #[inline]
1202    pub fn range_offsets(&self, range: crate::VideoColorRange) -> ([i32; 4], [i32; 4]) {
1203        self.format_info().range_offsets(range)
1204    }
1205}
1206
1207impl PartialEq for VideoInfo {
1208    #[doc(alias = "gst_video_info_is_equal")]
1209    fn eq(&self, other: &Self) -> bool {
1210        unsafe { from_glib(ffi::gst_video_info_is_equal(&self.0, &other.0)) }
1211    }
1212}
1213
1214impl Eq for VideoInfo {}
1215
1216unsafe impl Send for VideoInfo {}
1217unsafe impl Sync for VideoInfo {}
1218
1219impl glib::types::StaticType for VideoInfo {
1220    #[inline]
1221    fn static_type() -> glib::types::Type {
1222        unsafe { glib::translate::from_glib(ffi::gst_video_info_get_type()) }
1223    }
1224}
1225
1226impl glib::value::ValueType for VideoInfo {
1227    type Type = Self;
1228}
1229
1230#[doc(hidden)]
1231unsafe impl<'a> glib::value::FromValue<'a> for VideoInfo {
1232    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
1233
1234    unsafe fn from_value(value: &'a glib::Value) -> Self {
1235        skip_assert_initialized!();
1236        from_glib_none(
1237            glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstVideoInfo
1238        )
1239    }
1240}
1241
1242#[doc(hidden)]
1243impl glib::value::ToValue for VideoInfo {
1244    fn to_value(&self) -> glib::Value {
1245        let mut value = glib::Value::for_value_type::<Self>();
1246        unsafe {
1247            glib::gobject_ffi::g_value_set_boxed(
1248                value.to_glib_none_mut().0,
1249                self.to_glib_none().0 as *mut _,
1250            )
1251        }
1252        value
1253    }
1254
1255    fn value_type(&self) -> glib::Type {
1256        Self::static_type()
1257    }
1258}
1259
1260#[doc(hidden)]
1261impl glib::value::ToValueOptional for VideoInfo {
1262    fn to_value_optional(s: Option<&Self>) -> glib::Value {
1263        skip_assert_initialized!();
1264        let mut value = glib::Value::for_value_type::<Self>();
1265        unsafe {
1266            glib::gobject_ffi::g_value_set_boxed(
1267                value.to_glib_none_mut().0,
1268                s.to_glib_none().0 as *mut _,
1269            )
1270        }
1271        value
1272    }
1273}
1274
1275#[doc(hidden)]
1276impl From<VideoInfo> for glib::Value {
1277    fn from(v: VideoInfo) -> glib::Value {
1278        skip_assert_initialized!();
1279        glib::value::ToValue::to_value(&v)
1280    }
1281}
1282
1283#[doc(hidden)]
1284impl glib::translate::Uninitialized for VideoInfo {
1285    #[inline]
1286    unsafe fn uninitialized() -> Self {
1287        mem::zeroed()
1288    }
1289}
1290
1291#[doc(hidden)]
1292impl glib::translate::GlibPtrDefault for VideoInfo {
1293    type GlibType = *mut ffi::GstVideoInfo;
1294}
1295
1296#[doc(hidden)]
1297impl<'a> glib::translate::ToGlibPtr<'a, *const ffi::GstVideoInfo> for VideoInfo {
1298    type Storage = PhantomData<&'a Self>;
1299
1300    #[inline]
1301    fn to_glib_none(&'a self) -> glib::translate::Stash<'a, *const ffi::GstVideoInfo, Self> {
1302        glib::translate::Stash(&self.0, PhantomData)
1303    }
1304
1305    fn to_glib_full(&self) -> *const ffi::GstVideoInfo {
1306        unimplemented!()
1307    }
1308}
1309
1310#[doc(hidden)]
1311impl glib::translate::FromGlibPtrNone<*const ffi::GstVideoInfo> for VideoInfo {
1312    #[inline]
1313    unsafe fn from_glib_none(ptr: *const ffi::GstVideoInfo) -> Self {
1314        Self(ptr::read(ptr))
1315    }
1316}
1317
1318#[doc(hidden)]
1319impl glib::translate::FromGlibPtrNone<*mut ffi::GstVideoInfo> for VideoInfo {
1320    #[inline]
1321    unsafe fn from_glib_none(ptr: *mut ffi::GstVideoInfo) -> Self {
1322        Self(ptr::read(ptr))
1323    }
1324}
1325
1326#[doc(hidden)]
1327impl glib::translate::FromGlibPtrFull<*mut ffi::GstVideoInfo> for VideoInfo {
1328    #[inline]
1329    unsafe fn from_glib_full(ptr: *mut ffi::GstVideoInfo) -> Self {
1330        let info = from_glib_none(ptr);
1331        glib::ffi::g_free(ptr as *mut _);
1332        info
1333    }
1334}
1335
1336impl crate::VideoFieldOrder {
1337    #[doc(alias = "gst_video_field_order_to_string")]
1338    pub fn to_str<'a>(self) -> &'a str {
1339        use std::ffi::CStr;
1340
1341        if self == Self::Unknown {
1342            return "UNKNOWN";
1343        }
1344        unsafe {
1345            CStr::from_ptr(
1346                ffi::gst_video_field_order_to_string(self.into_glib())
1347                    .as_ref()
1348                    .expect("gst_video_field_order_to_string returned NULL"),
1349            )
1350            .to_str()
1351            .expect("gst_video_field_order_to_string returned an invalid string")
1352        }
1353    }
1354}
1355
1356impl str::FromStr for crate::VideoFieldOrder {
1357    type Err = glib::error::BoolError;
1358
1359    fn from_str(s: &str) -> Result<Self, Self::Err> {
1360        skip_assert_initialized!();
1361
1362        let fmt = Self::from_string(s);
1363        if fmt == Self::Unknown {
1364            Err(glib::bool_error!(
1365                "Failed to parse video field order from string"
1366            ))
1367        } else {
1368            Ok(fmt)
1369        }
1370    }
1371}
1372
1373impl str::FromStr for crate::VideoInterlaceMode {
1374    type Err = glib::error::BoolError;
1375
1376    fn from_str(s: &str) -> Result<Self, Self::Err> {
1377        skip_assert_initialized!();
1378
1379        let fmt = Self::from_string(s);
1380        Ok(fmt)
1381    }
1382}
1383
1384#[cfg(test)]
1385mod tests {
1386    use super::*;
1387
1388    #[test]
1389    fn test_new() {
1390        gst::init().unwrap();
1391
1392        let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1393            .build()
1394            .unwrap();
1395        assert_eq!(info.format(), crate::VideoFormat::I420);
1396        assert_eq!(info.width(), 320);
1397        assert_eq!(info.height(), 240);
1398        assert_eq!(info.size(), 320 * 240 + 2 * 160 * 120);
1399        assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::None);
1400        assert_eq!(&info.offset(), &[0, 320 * 240, 320 * 240 + 160 * 120]);
1401        assert_eq!(&info.stride(), &[320, 160, 160]);
1402
1403        let offsets = [0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16];
1404        let strides = [640, 320, 320];
1405        let info = VideoInfo::builder(crate::VideoFormat::I420, 320, 240)
1406            .offset(&offsets)
1407            .stride(&strides)
1408            .size(640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16)
1409            .multiview_mode(crate::VideoMultiviewMode::SideBySide)
1410            .build()
1411            .unwrap();
1412        assert_eq!(info.format(), crate::VideoFormat::I420);
1413        assert_eq!(info.width(), 320);
1414        assert_eq!(info.height(), 240);
1415        assert_eq!(
1416            info.size(),
1417            640 * 240 + 16 + 320 * 120 + 16 + 320 * 120 + 16
1418        );
1419        assert_eq!(info.multiview_mode(), crate::VideoMultiviewMode::SideBySide);
1420        assert_eq!(
1421            &info.offset(),
1422            &[0, 640 * 240 + 16, 640 * 240 + 16 + 320 * 120 + 16]
1423        );
1424        assert_eq!(&info.stride(), &[640, 320, 320]);
1425    }
1426
1427    #[test]
1428    fn test_from_to_caps() {
1429        gst::init().unwrap();
1430
1431        let caps = crate::VideoCapsBuilder::new()
1432            .format(crate::VideoFormat::I420)
1433            .width(320)
1434            .height(240)
1435            .framerate((30, 1).into())
1436            .pixel_aspect_ratio((1, 1).into())
1437            .field("interlace-mode", "progressive")
1438            .field("chroma-site", "mpeg2")
1439            .field("colorimetry", "bt709")
1440            .build();
1441        let info = VideoInfo::from_caps(&caps).unwrap();
1442        assert_eq!(info.format(), crate::VideoFormat::I420);
1443        assert_eq!(info.width(), 320);
1444        assert_eq!(info.height(), 240);
1445        assert_eq!(info.fps(), gst::Fraction::new(30, 1));
1446        assert_eq!(
1447            info.interlace_mode(),
1448            crate::VideoInterlaceMode::Progressive
1449        );
1450        assert_eq!(info.chroma_site(), crate::VideoChromaSite::MPEG2);
1451        assert_eq!(info.colorimetry(), "bt709".parse().unwrap());
1452
1453        let caps2 = info.to_caps().unwrap();
1454        assert_eq!(caps, caps2);
1455
1456        let info2 = VideoInfo::from_caps(&caps2).unwrap();
1457        assert!(info == info2);
1458    }
1459
1460    #[test]
1461    fn test_video_align() {
1462        gst::init().unwrap();
1463
1464        let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1465            .build()
1466            .expect("Failed to create VideoInfo");
1467
1468        assert_eq!(info.stride(), [1920, 1920]);
1469        assert_eq!(info.offset(), [0, 2_073_600]);
1470
1471        let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1472        info.align(&mut align).unwrap();
1473
1474        assert_eq!(info.stride(), [1928, 1928]);
1475        assert_eq!(info.offset(), [0, 2_082_240]);
1476
1477        #[cfg(feature = "v1_18")]
1478        {
1479            let mut info = crate::VideoInfo::builder(crate::VideoFormat::Nv16, 1920, 1080)
1480                .build()
1481                .expect("Failed to create VideoInfo");
1482
1483            let mut align = crate::VideoAlignment::new(0, 0, 0, 8, &[0; VIDEO_MAX_PLANES]);
1484            let plane_size = info.align_full(&mut align).unwrap();
1485            assert_eq!(plane_size, [2082240, 2082240, 0, 0]);
1486        }
1487    }
1488
1489    #[test]
1490    fn test_display() {
1491        gst::init().unwrap();
1492
1493        let _ = format!("{}", "sRGB".parse::<crate::VideoColorimetry>().unwrap());
1494        let _ = format!("{}", crate::VideoFieldOrder::TopFieldFirst);
1495        let _ = format!("{}", crate::VideoInterlaceMode::Progressive);
1496    }
1497}