1use std::str;
4
5use crate::ffi;
6use glib::translate::{from_glib, FromGlib, IntoGlib};
7use std::sync::LazyLock;
8
9#[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#[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 assert_eq!(
576 sorted,
577 crate::VideoFormat::iter_raw().collect::<Vec<crate::VideoFormat>>()
578 );
579 }
580}