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