gstreamer_video/
video_format.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::str;
4
5use crate::ffi;
6use glib::translate::{from_glib, FromGlib, IntoGlib};
7use std::sync::LazyLock;
8
9/// List of all video formats, for use in template caps strings.
10///
11/// Formats are sorted by decreasing "quality", using these criteria by priority:
12///  - number of components
13///  - depth
14///  - subsampling factor of the width
15///  - subsampling factor of the height
16///  - number of planes
17///  - native endianness preferred
18///  - pixel stride
19///  - poffset
20///  - prefer non-complex formats
21///  - prefer YUV formats over RGB ones
22///  - prefer I420 over YV12
23///  - format name
24#[cfg(feature = "v1_18")]
25pub static VIDEO_FORMATS_ALL: LazyLock<Box<[crate::VideoFormat]>> = LazyLock::new(|| unsafe {
26    let mut len: u32 = 0;
27    let mut res = Vec::with_capacity(len as usize);
28    let formats = ffi::gst_video_formats_raw(&mut len);
29    for i in 0..len {
30        let format = formats.offset(i as isize);
31        res.push(from_glib(*format));
32    }
33    res.into_boxed_slice()
34});
35
36#[cfg(not(feature = "v1_18"))]
37pub static VIDEO_FORMATS_ALL: LazyLock<Box<[crate::VideoFormat]>> = LazyLock::new(|| {
38    #[cfg(target_endian = "little")]
39    {
40        Box::new([
41            crate::VideoFormat::Ayuv64,
42            crate::VideoFormat::Argb64,
43            crate::VideoFormat::Gbra12le,
44            crate::VideoFormat::Gbra12be,
45            crate::VideoFormat::A44410le,
46            crate::VideoFormat::Gbra10le,
47            crate::VideoFormat::A44410be,
48            crate::VideoFormat::Gbra10be,
49            crate::VideoFormat::A42210le,
50            crate::VideoFormat::A42210be,
51            crate::VideoFormat::A42010le,
52            crate::VideoFormat::A42010be,
53            #[cfg(feature = "v1_16")]
54            crate::VideoFormat::Bgr10a2Le,
55            #[cfg(feature = "v1_16")]
56            crate::VideoFormat::Y410,
57            crate::VideoFormat::Gbra,
58            crate::VideoFormat::Ayuv,
59            #[cfg(feature = "v1_16")]
60            crate::VideoFormat::Vuya,
61            crate::VideoFormat::Rgba,
62            crate::VideoFormat::Argb,
63            crate::VideoFormat::Bgra,
64            crate::VideoFormat::Abgr,
65            crate::VideoFormat::A420,
66            crate::VideoFormat::V216,
67            crate::VideoFormat::Y44412le,
68            crate::VideoFormat::Gbr12le,
69            crate::VideoFormat::Y44412be,
70            crate::VideoFormat::Gbr12be,
71            crate::VideoFormat::I42212le,
72            crate::VideoFormat::I42212be,
73            crate::VideoFormat::I42012le,
74            crate::VideoFormat::I42012be,
75            crate::VideoFormat::Y44410le,
76            crate::VideoFormat::Gbr10le,
77            crate::VideoFormat::Y44410be,
78            crate::VideoFormat::Gbr10be,
79            crate::VideoFormat::R210,
80            crate::VideoFormat::I42210le,
81            crate::VideoFormat::I42210be,
82            crate::VideoFormat::Nv1610le32,
83            #[cfg(feature = "v1_16")]
84            crate::VideoFormat::Y210,
85            crate::VideoFormat::Uyvp,
86            crate::VideoFormat::V210,
87            crate::VideoFormat::I42010le,
88            crate::VideoFormat::I42010be,
89            crate::VideoFormat::P01010le,
90            #[cfg(feature = "v1_16")]
91            crate::VideoFormat::Nv1210le40,
92            crate::VideoFormat::Nv1210le32,
93            crate::VideoFormat::P01010be,
94            crate::VideoFormat::Y444,
95            crate::VideoFormat::Gbr,
96            crate::VideoFormat::Nv24,
97            crate::VideoFormat::V308,
98            crate::VideoFormat::Iyu2,
99            crate::VideoFormat::Rgbx,
100            crate::VideoFormat::Xrgb,
101            crate::VideoFormat::Bgrx,
102            crate::VideoFormat::Xbgr,
103            crate::VideoFormat::Rgb,
104            crate::VideoFormat::Bgr,
105            crate::VideoFormat::Y42b,
106            crate::VideoFormat::Nv16,
107            crate::VideoFormat::Nv61,
108            crate::VideoFormat::Yuy2,
109            crate::VideoFormat::Yvyu,
110            crate::VideoFormat::Uyvy,
111            crate::VideoFormat::Vyuy,
112            crate::VideoFormat::I420,
113            crate::VideoFormat::Yv12,
114            crate::VideoFormat::Nv12,
115            crate::VideoFormat::Nv21,
116            crate::VideoFormat::Nv1264z32,
117            crate::VideoFormat::Y41b,
118            crate::VideoFormat::Iyu1,
119            crate::VideoFormat::Yuv9,
120            crate::VideoFormat::Yvu9,
121            crate::VideoFormat::Bgr16,
122            crate::VideoFormat::Rgb16,
123            crate::VideoFormat::Bgr15,
124            crate::VideoFormat::Rgb15,
125            crate::VideoFormat::Rgb8p,
126            crate::VideoFormat::Gray16Le,
127            crate::VideoFormat::Gray16Be,
128            crate::VideoFormat::Gray10Le32,
129            crate::VideoFormat::Gray8,
130        ])
131    }
132    #[cfg(target_endian = "big")]
133    {
134        Box::new([
135            crate::VideoFormat::Ayuv64,
136            crate::VideoFormat::Argb64,
137            crate::VideoFormat::Gbra12be,
138            crate::VideoFormat::Gbra12le,
139            crate::VideoFormat::A44410be,
140            crate::VideoFormat::Gbra10be,
141            crate::VideoFormat::A44410le,
142            crate::VideoFormat::Gbra10le,
143            crate::VideoFormat::A42210be,
144            crate::VideoFormat::A42210le,
145            crate::VideoFormat::A42010be,
146            crate::VideoFormat::A42010le,
147            #[cfg(feature = "v1_16")]
148            crate::VideoFormat::Bgr10a2Le,
149            #[cfg(feature = "v1_16")]
150            crate::VideoFormat::Y410,
151            crate::VideoFormat::Gbra,
152            crate::VideoFormat::Ayuv,
153            #[cfg(feature = "v1_16")]
154            crate::VideoFormat::Vuya,
155            crate::VideoFormat::Rgba,
156            crate::VideoFormat::Argb,
157            crate::VideoFormat::Bgra,
158            crate::VideoFormat::Abgr,
159            crate::VideoFormat::A420,
160            crate::VideoFormat::V216,
161            crate::VideoFormat::Y44412be,
162            crate::VideoFormat::Gbr12be,
163            crate::VideoFormat::Y44412le,
164            crate::VideoFormat::Gbr12le,
165            crate::VideoFormat::I42212be,
166            crate::VideoFormat::I42212le,
167            crate::VideoFormat::I42012be,
168            crate::VideoFormat::I42012le,
169            crate::VideoFormat::Y44410be,
170            crate::VideoFormat::Gbr10be,
171            crate::VideoFormat::Y44410le,
172            crate::VideoFormat::Gbr10le,
173            crate::VideoFormat::R210,
174            crate::VideoFormat::I42210be,
175            crate::VideoFormat::I42210le,
176            crate::VideoFormat::Nv1610le32,
177            #[cfg(feature = "v1_16")]
178            crate::VideoFormat::Y210,
179            crate::VideoFormat::Uyvp,
180            crate::VideoFormat::V210,
181            crate::VideoFormat::I42010be,
182            crate::VideoFormat::I42010le,
183            crate::VideoFormat::P01010be,
184            crate::VideoFormat::P01010le,
185            #[cfg(feature = "v1_16")]
186            crate::VideoFormat::Nv1210le40,
187            crate::VideoFormat::Nv1210le32,
188            crate::VideoFormat::Y444,
189            crate::VideoFormat::Gbr,
190            crate::VideoFormat::Nv24,
191            crate::VideoFormat::V308,
192            crate::VideoFormat::Iyu2,
193            crate::VideoFormat::Rgbx,
194            crate::VideoFormat::Xrgb,
195            crate::VideoFormat::Bgrx,
196            crate::VideoFormat::Xbgr,
197            crate::VideoFormat::Rgb,
198            crate::VideoFormat::Bgr,
199            crate::VideoFormat::Y42b,
200            crate::VideoFormat::Nv16,
201            crate::VideoFormat::Nv61,
202            crate::VideoFormat::Yuy2,
203            crate::VideoFormat::Yvyu,
204            crate::VideoFormat::Uyvy,
205            crate::VideoFormat::Vyuy,
206            crate::VideoFormat::I420,
207            crate::VideoFormat::Yv12,
208            crate::VideoFormat::Nv12,
209            crate::VideoFormat::Nv21,
210            crate::VideoFormat::Nv1264z32,
211            crate::VideoFormat::Y41b,
212            crate::VideoFormat::Iyu1,
213            crate::VideoFormat::Yuv9,
214            crate::VideoFormat::Yvu9,
215            crate::VideoFormat::Bgr16,
216            crate::VideoFormat::Rgb16,
217            crate::VideoFormat::Bgr15,
218            crate::VideoFormat::Rgb15,
219            crate::VideoFormat::Rgb8p,
220            crate::VideoFormat::Gray16Be,
221            crate::VideoFormat::Gray16Le,
222            crate::VideoFormat::Gray10Le32,
223            crate::VideoFormat::Gray8,
224        ])
225    }
226});
227
228/// This is similar to `GST_VIDEO_FORMATS_ALL` but includes formats like DMA_DRM
229/// that do not have a software converter. This should be used for passthrough
230/// template caps.
231#[cfg(feature = "v1_24")]
232pub static VIDEO_FORMATS_ANY: LazyLock<Box<[crate::VideoFormat]>> = LazyLock::new(|| unsafe {
233    let mut len: u32 = 0;
234    let mut res = Vec::with_capacity(len as usize);
235    let formats = ffi::gst_video_formats_any(&mut len);
236    for i in 0..len {
237        let format = formats.offset(i as isize);
238        res.push(from_glib(*format));
239    }
240    res.into_boxed_slice()
241});
242
243#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
244pub enum VideoEndianness {
245    Unknown,
246    LittleEndian = 1234,
247    BigEndian = 4321,
248}
249
250impl FromGlib<i32> for VideoEndianness {
251    #[inline]
252    unsafe fn from_glib(value: i32) -> Self {
253        skip_assert_initialized!();
254
255        match value {
256            1234 => Self::LittleEndian,
257            4321 => Self::BigEndian,
258            _ => Self::Unknown,
259        }
260    }
261}
262
263impl IntoGlib for VideoEndianness {
264    type GlibType = i32;
265
266    #[inline]
267    fn into_glib(self) -> i32 {
268        match self {
269            Self::LittleEndian => 1234,
270            Self::BigEndian => 4321,
271            _ => 0,
272        }
273    }
274}
275
276impl crate::VideoFormat {
277    #[doc(alias = "gst_video_format_from_masks")]
278    pub fn from_masks(
279        depth: u32,
280        bpp: u32,
281        endianness: crate::VideoEndianness,
282        red_mask: u32,
283        green_mask: u32,
284        blue_mask: u32,
285        alpha_mask: u32,
286    ) -> Self {
287        assert_initialized_main_thread!();
288
289        unsafe {
290            from_glib(ffi::gst_video_format_from_masks(
291                depth as i32,
292                bpp as i32,
293                endianness.into_glib(),
294                red_mask,
295                green_mask,
296                blue_mask,
297                alpha_mask,
298            ))
299        }
300    }
301
302    #[doc(alias = "gst_video_format_to_string")]
303    pub fn to_str<'a>(self) -> &'a glib::GStr {
304        if self == Self::Unknown {
305            return glib::gstr!("UNKNOWN");
306        }
307        unsafe {
308            glib::GStr::from_ptr(
309                ffi::gst_video_format_to_string(self.into_glib())
310                    .as_ref()
311                    .expect("gst_video_format_to_string returned NULL"),
312            )
313        }
314    }
315
316    pub fn iter_raw() -> VideoFormatIterator {
317        VideoFormatIterator::default()
318    }
319
320    #[cfg(feature = "v1_24")]
321    pub fn iter_any() -> impl Iterator<Item = crate::VideoFormat> {
322        VIDEO_FORMATS_ANY.iter().copied()
323    }
324}
325
326impl str::FromStr for crate::VideoFormat {
327    type Err = glib::BoolError;
328
329    fn from_str(s: &str) -> Result<Self, Self::Err> {
330        skip_assert_initialized!();
331
332        let fmt = Self::from_string(s);
333        if fmt == Self::Unknown {
334            Err(glib::bool_error!(
335                "Failed to parse video format from string"
336            ))
337        } else {
338            Ok(fmt)
339        }
340    }
341}
342
343impl PartialOrd for crate::VideoFormat {
344    #[inline]
345    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
346        Some(self.cmp(other))
347    }
348}
349
350impl Ord for crate::VideoFormat {
351    #[inline]
352    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
353        crate::VideoFormatInfo::from_format(*self).cmp(&crate::VideoFormatInfo::from_format(*other))
354    }
355}
356
357#[must_use = "iterators are lazy and do nothing unless consumed"]
358pub struct VideoFormatIterator {
359    idx: usize,
360    len: usize,
361}
362
363impl Default for VideoFormatIterator {
364    fn default() -> Self {
365        Self {
366            idx: 0,
367            len: VIDEO_FORMATS_ALL.len(),
368        }
369    }
370}
371
372impl Iterator for VideoFormatIterator {
373    type Item = crate::VideoFormat;
374
375    fn next(&mut self) -> Option<Self::Item> {
376        if self.idx >= self.len {
377            None
378        } else {
379            let fmt = VIDEO_FORMATS_ALL[self.idx];
380            self.idx += 1;
381            Some(fmt)
382        }
383    }
384
385    fn size_hint(&self) -> (usize, Option<usize>) {
386        if self.idx == self.len {
387            return (0, Some(0));
388        }
389
390        let remaining = self.len - self.idx;
391
392        (remaining, Some(remaining))
393    }
394
395    fn count(self) -> usize {
396        self.len - self.idx
397    }
398
399    fn nth(&mut self, n: usize) -> Option<Self::Item> {
400        let (end, overflow) = self.idx.overflowing_add(n);
401        if end >= self.len || overflow {
402            self.idx = self.len;
403            None
404        } else {
405            self.idx = end + 1;
406            Some(VIDEO_FORMATS_ALL[end])
407        }
408    }
409
410    fn last(self) -> Option<Self::Item> {
411        if self.idx == self.len {
412            None
413        } else {
414            Some(VIDEO_FORMATS_ALL[self.len - 1])
415        }
416    }
417}
418
419impl ExactSizeIterator for VideoFormatIterator {}
420
421impl std::iter::FusedIterator for VideoFormatIterator {}
422
423impl DoubleEndedIterator for VideoFormatIterator {
424    fn next_back(&mut self) -> Option<Self::Item> {
425        if self.idx >= self.len {
426            None
427        } else {
428            let fmt = VIDEO_FORMATS_ALL[self.len - 1];
429            self.len -= 1;
430            Some(fmt)
431        }
432    }
433
434    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
435        let (end, overflow) = self.len.overflowing_sub(n);
436        if end <= self.idx || overflow {
437            self.idx = self.len;
438            None
439        } else {
440            self.len = end - 1;
441            let fmt = VIDEO_FORMATS_ALL[self.len];
442            Some(fmt)
443        }
444    }
445}
446pub trait VideoFormatIteratorExt {
447    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
448}
449
450impl<T> VideoFormatIteratorExt for T
451where
452    T: Iterator<Item = crate::VideoFormat>,
453{
454    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
455        let formats: Vec<crate::VideoFormat> = self.collect();
456        if !formats.is_empty() {
457            Some(crate::functions::video_make_raw_caps(&formats))
458        } else {
459            None
460        }
461    }
462}
463
464pub trait VideoFormatIteratorExtRef {
465    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
466}
467
468impl<'a, T> VideoFormatIteratorExtRef for T
469where
470    T: Iterator<Item = &'a crate::VideoFormat>,
471{
472    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
473        let formats: Vec<crate::VideoFormat> = self.copied().collect();
474        if !formats.is_empty() {
475            Some(crate::functions::video_make_raw_caps(&formats))
476        } else {
477            None
478        }
479    }
480}
481
482#[cfg(test)]
483mod tests {
484
485    #[test]
486    fn enum_to_string() {
487        gst::init().unwrap();
488
489        assert_eq!(&format!("{}", crate::VideoFormat::Argb), "ARGB");
490        assert_eq!(&format!("{:?}", crate::VideoFormat::Argb), "Argb");
491        assert_eq!(crate::VideoFormat::Argb.to_str(), "ARGB");
492
493        assert_eq!(&format!("{}", crate::VideoFormat::Unknown), "UNKNOWN");
494        assert_eq!(&format!("{:?}", crate::VideoFormat::Unknown), "Unknown");
495        assert_eq!(crate::VideoFormat::Unknown.to_str(), "UNKNOWN");
496
497        assert_eq!(
498            &format!("{:?}", crate::VideoFormat::__Unknown(-1)),
499            "__Unknown(-1)"
500        );
501    }
502
503    #[test]
504    fn test_display() {
505        gst::init().unwrap();
506
507        assert_eq!(format!("{}", crate::VideoFormat::Nv16), "NV16");
508        assert_eq!(format!("{:?}", crate::VideoFormat::Nv16), "Nv16");
509    }
510
511    #[test]
512    fn iter() {
513        use super::*;
514        gst::init().unwrap();
515
516        assert!(crate::VideoFormat::iter_raw().count() > 0);
517        assert_eq!(
518            crate::VideoFormat::iter_raw().count(),
519            crate::VideoFormat::iter_raw().len()
520        );
521
522        let mut i = crate::VideoFormat::iter_raw();
523        let mut count = 0;
524        loop {
525            if i.next().is_none() {
526                break;
527            }
528            count += 1;
529            if i.next_back().is_none() {
530                break;
531            }
532            count += 1;
533        }
534        assert_eq!(count, crate::VideoFormat::iter_raw().len());
535
536        assert!(crate::VideoFormat::iter_raw().any(|f| f == crate::VideoFormat::Nv12));
537        assert!(!crate::VideoFormat::iter_raw().any(|f| f == crate::VideoFormat::Encoded));
538
539        let caps = crate::VideoFormat::iter_raw().into_video_caps();
540        assert!(caps.is_some());
541
542        let caps = crate::VideoFormat::iter_raw()
543            .filter(|f| crate::VideoFormatInfo::from_format(*f).is_gray())
544            .into_video_caps();
545        assert!(caps.is_some());
546
547        let caps = crate::VideoFormat::iter_raw().skip(1000).into_video_caps();
548        assert!(caps.is_none());
549
550        let caps = [crate::VideoFormat::Nv12, crate::VideoFormat::Nv16]
551            .iter()
552            .into_video_caps()
553            .unwrap()
554            .build();
555        assert_eq!(caps.to_string(), "video/x-raw, format=(string){ NV12, NV16 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]");
556    }
557
558    #[test]
559    fn sort() {
560        use itertools::Itertools;
561
562        gst::init().unwrap();
563
564        assert!(
565            crate::VideoFormatInfo::from_format(crate::VideoFormat::Nv16)
566                > crate::VideoFormatInfo::from_format(crate::VideoFormat::Nv12)
567        );
568        assert!(crate::VideoFormat::I420 > crate::VideoFormat::Yv12);
569        assert!(crate::VideoFormat::Nv12 > crate::VideoFormat::Nv21);
570        assert!(crate::VideoFormat::Xrgb > crate::VideoFormat::Rgb);
571
572        let sorted: Vec<crate::VideoFormat> =
573            crate::VideoFormat::iter_raw().sorted().rev().collect();
574        // FIXME: use is_sorted_by() once API is in stable
575        assert_eq!(
576            sorted,
577            crate::VideoFormat::iter_raw().collect::<Vec<crate::VideoFormat>>()
578        );
579    }
580}