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 once_cell::sync::Lazy;
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: Lazy<Box<[crate::VideoFormat]>> = Lazy::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: Lazy<Box<[crate::VideoFormat]>> = Lazy::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: Lazy<Box<[crate::VideoFormat]>> = Lazy::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
357pub struct VideoFormatIterator {
358    idx: usize,
359    len: usize,
360}
361
362impl Default for VideoFormatIterator {
363    fn default() -> Self {
364        Self {
365            idx: 0,
366            len: VIDEO_FORMATS_ALL.len(),
367        }
368    }
369}
370
371impl Iterator for VideoFormatIterator {
372    type Item = crate::VideoFormat;
373
374    fn next(&mut self) -> Option<Self::Item> {
375        if self.idx >= self.len {
376            None
377        } else {
378            let fmt = VIDEO_FORMATS_ALL[self.idx];
379            self.idx += 1;
380            Some(fmt)
381        }
382    }
383
384    fn size_hint(&self) -> (usize, Option<usize>) {
385        if self.idx == self.len {
386            return (0, Some(0));
387        }
388
389        let remaining = self.len - self.idx;
390
391        (remaining, Some(remaining))
392    }
393
394    fn count(self) -> usize {
395        self.len - self.idx
396    }
397
398    fn nth(&mut self, n: usize) -> Option<Self::Item> {
399        let (end, overflow) = self.idx.overflowing_add(n);
400        if end >= self.len || overflow {
401            self.idx = self.len;
402            None
403        } else {
404            self.idx = end + 1;
405            Some(VIDEO_FORMATS_ALL[end])
406        }
407    }
408
409    fn last(self) -> Option<Self::Item> {
410        if self.idx == self.len {
411            None
412        } else {
413            Some(VIDEO_FORMATS_ALL[self.len - 1])
414        }
415    }
416}
417
418impl ExactSizeIterator for VideoFormatIterator {}
419
420impl std::iter::FusedIterator for VideoFormatIterator {}
421
422impl DoubleEndedIterator for VideoFormatIterator {
423    fn next_back(&mut self) -> Option<Self::Item> {
424        if self.idx >= self.len {
425            None
426        } else {
427            let fmt = VIDEO_FORMATS_ALL[self.len - 1];
428            self.len -= 1;
429            Some(fmt)
430        }
431    }
432
433    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
434        let (end, overflow) = self.len.overflowing_sub(n);
435        if end <= self.idx || overflow {
436            self.idx = self.len;
437            None
438        } else {
439            self.len = end - 1;
440            let fmt = VIDEO_FORMATS_ALL[self.len];
441            Some(fmt)
442        }
443    }
444}
445pub trait VideoFormatIteratorExt {
446    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
447}
448
449impl<T> VideoFormatIteratorExt for T
450where
451    T: Iterator<Item = crate::VideoFormat>,
452{
453    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
454        let formats: Vec<crate::VideoFormat> = self.collect();
455        if !formats.is_empty() {
456            Some(crate::functions::video_make_raw_caps(&formats))
457        } else {
458            None
459        }
460    }
461}
462
463pub trait VideoFormatIteratorExtRef {
464    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
465}
466
467impl<'a, T> VideoFormatIteratorExtRef for T
468where
469    T: Iterator<Item = &'a crate::VideoFormat>,
470{
471    fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
472        let formats: Vec<crate::VideoFormat> = self.copied().collect();
473        if !formats.is_empty() {
474            Some(crate::functions::video_make_raw_caps(&formats))
475        } else {
476            None
477        }
478    }
479}
480
481#[cfg(test)]
482mod tests {
483
484    #[test]
485    fn enum_to_string() {
486        gst::init().unwrap();
487
488        assert_eq!(&format!("{}", crate::VideoFormat::Argb), "ARGB");
489        assert_eq!(&format!("{:?}", crate::VideoFormat::Argb), "Argb");
490        assert_eq!(crate::VideoFormat::Argb.to_str(), "ARGB");
491
492        assert_eq!(&format!("{}", crate::VideoFormat::Unknown), "UNKNOWN");
493        assert_eq!(&format!("{:?}", crate::VideoFormat::Unknown), "Unknown");
494        assert_eq!(crate::VideoFormat::Unknown.to_str(), "UNKNOWN");
495
496        assert_eq!(
497            &format!("{:?}", crate::VideoFormat::__Unknown(-1)),
498            "__Unknown(-1)"
499        );
500    }
501
502    #[test]
503    fn test_display() {
504        gst::init().unwrap();
505
506        assert_eq!(format!("{}", crate::VideoFormat::Nv16), "NV16");
507        assert_eq!(format!("{:?}", crate::VideoFormat::Nv16), "Nv16");
508    }
509
510    #[test]
511    fn iter() {
512        use super::*;
513        gst::init().unwrap();
514
515        assert!(crate::VideoFormat::iter_raw().count() > 0);
516        assert_eq!(
517            crate::VideoFormat::iter_raw().count(),
518            crate::VideoFormat::iter_raw().len()
519        );
520
521        let mut i = crate::VideoFormat::iter_raw();
522        let mut count = 0;
523        loop {
524            if i.next().is_none() {
525                break;
526            }
527            count += 1;
528            if i.next_back().is_none() {
529                break;
530            }
531            count += 1;
532        }
533        assert_eq!(count, crate::VideoFormat::iter_raw().len());
534
535        assert!(crate::VideoFormat::iter_raw().any(|f| f == crate::VideoFormat::Nv12));
536        assert!(!crate::VideoFormat::iter_raw().any(|f| f == crate::VideoFormat::Encoded));
537
538        let caps = crate::VideoFormat::iter_raw().into_video_caps();
539        assert!(caps.is_some());
540
541        let caps = crate::VideoFormat::iter_raw()
542            .filter(|f| crate::VideoFormatInfo::from_format(*f).is_gray())
543            .into_video_caps();
544        assert!(caps.is_some());
545
546        let caps = crate::VideoFormat::iter_raw().skip(1000).into_video_caps();
547        assert!(caps.is_none());
548
549        let caps = [crate::VideoFormat::Nv12, crate::VideoFormat::Nv16]
550            .iter()
551            .into_video_caps()
552            .unwrap()
553            .build();
554        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 ]");
555    }
556
557    #[test]
558    fn sort() {
559        use itertools::Itertools;
560
561        gst::init().unwrap();
562
563        assert!(
564            crate::VideoFormatInfo::from_format(crate::VideoFormat::Nv16)
565                > crate::VideoFormatInfo::from_format(crate::VideoFormat::Nv12)
566        );
567        assert!(crate::VideoFormat::I420 > crate::VideoFormat::Yv12);
568        assert!(crate::VideoFormat::Nv12 > crate::VideoFormat::Nv21);
569        assert!(crate::VideoFormat::Xrgb > crate::VideoFormat::Rgb);
570
571        let sorted: Vec<crate::VideoFormat> =
572            crate::VideoFormat::iter_raw().sorted().rev().collect();
573        // FIXME: use is_sorted_by() once API is in stable
574        assert_eq!(
575            sorted,
576            crate::VideoFormat::iter_raw().collect::<Vec<crate::VideoFormat>>()
577        );
578    }
579}