1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use std::str; |
4 | |
5 | use crate::ffi; |
6 | use glib::translate::{from_glib, FromGlib, IntoGlib}; |
7 | use once_cell::sync::Lazy; |
8 | |
9 | #[cfg (feature = "v1_18" )] |
10 | pub 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" ))] |
22 | pub 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" )] |
214 | pub 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)] |
226 | pub enum VideoEndianness { |
227 | Unknown, |
228 | LittleEndian = 1234, |
229 | BigEndian = 4321, |
230 | } |
231 | |
232 | impl 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 | |
245 | impl 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 | |
258 | impl 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 | |
308 | impl 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 | |
325 | impl 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 | |
332 | impl 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 | pub struct VideoFormatIterator { |
340 | idx: usize, |
341 | len: usize, |
342 | } |
343 | |
344 | impl Default for VideoFormatIterator { |
345 | fn default() -> Self { |
346 | Self { |
347 | idx: 0, |
348 | len: VIDEO_FORMATS_ALL.len(), |
349 | } |
350 | } |
351 | } |
352 | |
353 | impl 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 | |
400 | impl ExactSizeIterator for VideoFormatIterator {} |
401 | |
402 | impl std::iter::FusedIterator for VideoFormatIterator {} |
403 | |
404 | impl 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 | } |
427 | pub trait VideoFormatIteratorExt { |
428 | fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>; |
429 | } |
430 | |
431 | impl<T> VideoFormatIteratorExt for T |
432 | where |
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 | |
445 | pub trait VideoFormatIteratorExtRef { |
446 | fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>; |
447 | } |
448 | |
449 | impl<'a, T> VideoFormatIteratorExtRef for T |
450 | where |
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)] |
464 | mod 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 | |