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: VideoFormat = Self::from_string(format: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: VideoFormat = 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: usize, overflow: bool) = 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: VideoFormat = 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}
562