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