1use crate::utils::{
5 result::{Error, SpaResult, SpaSuccess},
6 Fraction, Rectangle,
7};
8
9#[cfg(feature = "v0_3_65")]
10use convert_case::{Case, Casing};
11
12use std::{ffi::CStr, fmt::Debug};
13
14#[derive(Copy, Clone, PartialEq, Eq)]
15pub struct VideoFormat(pub spa_sys::spa_video_format);
16
17#[allow(non_upper_case_globals)]
18impl VideoFormat {
19 pub const Unknown: Self = Self(spa_sys::SPA_VIDEO_FORMAT_UNKNOWN);
20 pub const Encoded: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ENCODED);
21
22 pub const I420: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420);
23 pub const YV12: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YV12);
24 pub const YUY2: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YUY2);
25 pub const UYVY: Self = Self(spa_sys::SPA_VIDEO_FORMAT_UYVY);
26 pub const AYUV: Self = Self(spa_sys::SPA_VIDEO_FORMAT_AYUV);
27 pub const RGBx: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBx);
28 pub const BGRx: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRx);
29 pub const xRGB: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xRGB);
30 pub const xBGR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xBGR);
31 pub const RGBA: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA);
32 pub const BGRA: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRA);
33 pub const ARGB: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ARGB);
34 pub const ABGR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ABGR);
35 pub const RGB: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB);
36 pub const BGR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGR);
37 pub const Y41B: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y41B);
38 pub const Y42B: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y42B);
39 pub const YVYU: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YVYU);
40 pub const Y444: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444);
41 pub const v210: Self = Self(spa_sys::SPA_VIDEO_FORMAT_v210);
42 pub const v216: Self = Self(spa_sys::SPA_VIDEO_FORMAT_v216);
43 pub const NV12: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV12);
44 pub const NV21: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV21);
45 pub const GRAY8: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GRAY8);
46 pub const GRAY16_BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GRAY16_BE);
47 pub const GRAY16_LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GRAY16_LE);
48 pub const v308: Self = Self(spa_sys::SPA_VIDEO_FORMAT_v308);
49 pub const RGB16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB16);
50 pub const BGR16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGR16);
51 pub const RGB15: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB15);
52 pub const BGR15: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGR15);
53 pub const UYVP: Self = Self(spa_sys::SPA_VIDEO_FORMAT_UYVP);
54 pub const A420: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A420);
55 pub const RGB8P: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB8P);
56 pub const YUV9: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YUV9);
57 pub const YVU9: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YVU9);
58 pub const IYU1: Self = Self(spa_sys::SPA_VIDEO_FORMAT_IYU1);
59 pub const ARGB64: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ARGB64);
60 pub const AYUV64: Self = Self(spa_sys::SPA_VIDEO_FORMAT_AYUV64);
61 pub const r210: Self = Self(spa_sys::SPA_VIDEO_FORMAT_r210);
62 pub const I420_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_10BE);
63 pub const I420_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_10LE);
64 pub const I422_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_10BE);
65 pub const I422_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_10LE);
66 pub const Y444_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_10BE);
67 pub const Y444_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_10LE);
68 pub const GBR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR);
69 pub const GBR_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_10BE);
70 pub const GBR_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_10LE);
71 pub const NV16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV16);
72 pub const NV24: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV24);
73 pub const NV12_64Z32: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV12_64Z32);
74 pub const A420_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A420_10BE);
75 pub const A420_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A420_10LE);
76 pub const A422_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A422_10BE);
77 pub const A422_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A422_10LE);
78 pub const A444_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A444_10BE);
79 pub const A444_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A444_10LE);
80 pub const NV61: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV61);
81 pub const P010_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_P010_10BE);
82 pub const P010_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_P010_10LE);
83 pub const IYU2: Self = Self(spa_sys::SPA_VIDEO_FORMAT_IYU2);
84 pub const VYUY: Self = Self(spa_sys::SPA_VIDEO_FORMAT_VYUY);
85 pub const GBRA: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA);
86 pub const GBRA_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_10BE);
87 pub const GBRA_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_10LE);
88 pub const GBR_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_12BE);
89 pub const GBR_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_12LE);
90 pub const GBRA_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_12BE);
91 pub const GBRA_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_12LE);
92 pub const I420_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_12BE);
93 pub const I420_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_12LE);
94 pub const I422_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_12BE);
95 pub const I422_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_12LE);
96 pub const Y444_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_12BE);
97 pub const Y444_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_12LE);
98
99 pub const RGBA_F16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA_F16);
100 pub const RGBA_F32: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA_F32);
101
102 pub const xRGB_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xRGB_210LE);
104 pub const xBGR_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xBGR_210LE);
106 pub const RGBx_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBx_102LE);
108 pub const BGRx_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRx_102LE);
110 pub const ARGB_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ARGB_210LE);
112 pub const ABGR_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ABGR_210LE);
114 pub const RGBA_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA_102LE);
116 pub const BGRA_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRA_102LE);
118
119 pub const DSP_F32: Self = Self(spa_sys::SPA_VIDEO_FORMAT_DSP_F32);
121
122 pub fn from_raw(raw: spa_sys::spa_video_format) -> Self {
124 Self(raw)
125 }
126
127 pub fn as_raw(&self) -> spa_sys::spa_video_format {
129 self.0
130 }
131}
132
133impl Debug for VideoFormat {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 match *self {
136 VideoFormat::Unknown => f.write_str("VideoFormat::Unknown"),
137 _ => {
138 let c_str = unsafe {
139 let c_buf = spa_sys::spa_debug_type_find_short_name(
140 spa_sys::spa_type_video_format,
141 self.as_raw(),
142 );
143 if c_buf.is_null() {
144 return f.write_str("Unsupported");
145 }
146 CStr::from_ptr(c_buf)
147 };
148 let name = format!("VideoFormat::{}", c_str.to_string_lossy());
149 f.write_str(&name)
150 }
151 }
152 }
153}
154
155bitflags::bitflags! {
156 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
157 pub struct VideoFlags: u32 {
158 const NONE = spa_sys::SPA_VIDEO_FLAG_NONE;
160 const VARIABLE_FPS = spa_sys::SPA_VIDEO_FLAG_VARIABLE_FPS;
162 const PREMULTIPLIED_ALPHA = spa_sys::SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
164 #[cfg(feature = "v0_3_65")]
166 const MODIFIER = spa_sys::SPA_VIDEO_FLAG_MODIFIER;
167 #[cfg(feature = "v0_3_75")]
168 const MODIFIER_FIXATION_REQUIRED = spa_sys::SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED;
170 }
171}
172
173#[derive(Copy, Clone, PartialEq, Eq)]
174pub struct VideoInterlaceMode(pub spa_sys::spa_video_interlace_mode);
175
176#[allow(non_upper_case_globals)]
177impl VideoInterlaceMode {
178 pub const Progressive: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE);
180 pub const Interleaved: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_INTERLEAVED);
183 pub const Mixed: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_MIXED);
185 pub const Fields: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_FIELDS);
189
190 pub fn from_raw(raw: spa_sys::spa_video_interlace_mode) -> Self {
192 Self(raw)
193 }
194
195 pub fn as_raw(&self) -> spa_sys::spa_video_interlace_mode {
197 self.0
198 }
199}
200
201#[cfg(feature = "v0_3_65")]
202impl Debug for VideoInterlaceMode {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 let c_str = unsafe {
205 let c_buf = spa_sys::spa_debug_type_find_short_name(
206 spa_sys::spa_type_video_interlace_mode,
207 self.as_raw(),
208 );
209 if c_buf.is_null() {
210 return f.write_str("Unsupported");
211 }
212 CStr::from_ptr(c_buf)
213 };
214 let name = format!(
215 "VideoInterlaceMode::{}",
216 c_str.to_string_lossy().to_case(Case::Pascal)
217 );
218 f.write_str(&name)
219 }
220}
221
222#[repr(transparent)]
224#[derive(PartialEq, Eq, Clone, Copy)]
225pub struct VideoInfoRaw(spa_sys::spa_video_info_raw);
226
227impl VideoInfoRaw {
228 pub fn new() -> Self {
229 Self(spa_sys::spa_video_info_raw {
230 format: VideoFormat::Unknown.as_raw(),
231 flags: 0,
232 modifier: 0,
233 size: Rectangle {
234 width: 0,
235 height: 0,
236 },
237 framerate: Fraction { num: 0, denom: 0 },
238 max_framerate: Fraction { num: 0, denom: 0 },
239 views: 0,
240 interlace_mode: VideoInterlaceMode::Progressive.as_raw(),
241 pixel_aspect_ratio: Fraction { num: 0, denom: 0 },
242 multiview_mode: 0,
243 multiview_flags: 0,
244 chroma_site: 0,
245 color_range: 0,
246 color_matrix: 0,
247 transfer_function: 0,
248 color_primaries: 0,
249 })
250 }
251
252 pub fn set_format(&mut self, format: VideoFormat) {
253 self.0.format = format.as_raw();
254 }
255
256 pub fn format(self) -> VideoFormat {
257 VideoFormat::from_raw(self.0.format)
258 }
259
260 pub fn set_flags(&mut self, flags: VideoFlags) {
261 self.0.flags = flags.bits();
262 }
263
264 pub fn flags(self) -> VideoFlags {
265 VideoFlags::from_bits_retain(self.0.flags)
266 }
267
268 pub fn set_modifier(&mut self, modifier: u64) {
269 self.0.modifier = modifier;
270 }
271
272 pub fn modifier(self) -> u64 {
273 self.0.modifier
274 }
275
276 pub fn set_size(&mut self, size: Rectangle) {
277 self.0.size = size;
278 }
279
280 pub fn size(self) -> Rectangle {
281 self.0.size
282 }
283
284 pub fn set_framerate(&mut self, framerate: Fraction) {
285 self.0.framerate = framerate;
286 }
287
288 pub fn framerate(self) -> Fraction {
289 self.0.framerate
290 }
291
292 pub fn set_max_framerate(&mut self, max_framerate: Fraction) {
293 self.0.max_framerate = max_framerate;
294 }
295
296 pub fn max_framerate(self) -> Fraction {
297 self.0.max_framerate
298 }
299
300 pub fn set_views(&mut self, views: u32) {
301 self.0.views = views;
302 }
303
304 pub fn views(self) -> u32 {
305 self.0.views
306 }
307
308 pub fn set_interlace_mode(&mut self, interlace_mode: VideoInterlaceMode) {
309 self.0.interlace_mode = interlace_mode.as_raw();
310 }
311
312 pub fn interlace_mode(self) -> VideoInterlaceMode {
313 VideoInterlaceMode::from_raw(self.0.interlace_mode)
314 }
315
316 pub fn set_pixel_aspect_ratio(&mut self, pixel_aspect_ratio: Fraction) {
317 self.0.pixel_aspect_ratio = pixel_aspect_ratio;
318 }
319
320 pub fn pixel_aspect_ratio(self) -> Fraction {
321 self.0.pixel_aspect_ratio
322 }
323
324 pub fn set_multiview_mode(&mut self, multiview_mode: i32) {
325 self.0.multiview_mode = multiview_mode;
326 }
327
328 pub fn multiview_mode(self) -> i32 {
329 self.0.multiview_mode
330 }
331
332 pub fn set_multiview_flags(&mut self, multiview_flags: u32) {
333 self.0.multiview_flags = multiview_flags;
334 }
335
336 pub fn multiview_flags(self) -> u32 {
337 self.0.multiview_flags
338 }
339
340 pub fn set_chroma_site(&mut self, chroma_site: u32) {
341 self.0.chroma_site = chroma_site;
342 }
343
344 pub fn chroma_site(self) -> u32 {
345 self.0.chroma_site
346 }
347
348 pub fn set_color_range(&mut self, color_range: u32) {
349 self.0.color_range = color_range;
350 }
351
352 pub fn color_range(self) -> u32 {
353 self.0.color_range
354 }
355
356 pub fn set_color_matrix(&mut self, color_matrix: u32) {
357 self.0.color_matrix = color_matrix;
358 }
359
360 pub fn color_matrix(self) -> u32 {
361 self.0.color_matrix
362 }
363
364 pub fn set_transfer_function(&mut self, transfer_function: u32) {
365 self.0.transfer_function = transfer_function;
366 }
367
368 pub fn transfer_function(self) -> u32 {
369 self.0.transfer_function
370 }
371
372 pub fn set_color_primaries(&mut self, color_primaries: u32) {
373 self.0.color_primaries = color_primaries;
374 }
375
376 pub fn color_primaries(self) -> u32 {
377 self.0.color_primaries
378 }
379
380 pub fn parse(&mut self, format: &crate::pod::Pod) -> Result<SpaSuccess, Error> {
382 let res = unsafe { spa_sys::spa_format_video_raw_parse(format.as_raw_ptr(), &mut self.0) };
383 SpaResult::from_c(res).into_result()
384 }
385
386 pub fn from_raw(raw: spa_sys::spa_video_info_raw) -> Self {
388 Self(raw)
389 }
390
391 pub fn as_raw(&self) -> spa_sys::spa_video_info_raw {
393 self.0
394 }
395}
396
397impl Default for VideoInfoRaw {
398 fn default() -> Self {
399 Self::new()
400 }
401}
402
403impl Debug for VideoInfoRaw {
404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
405 #[cfg(feature = "v0_3_65")]
406 let interlace_mode = self.interlace_mode();
407 #[cfg(not(feature = "v0_3_65"))]
408 let interlace_mode = self.interlace_mode().as_raw();
409
410 f.debug_struct("VideoInfoRaw")
411 .field("format", &self.format())
412 .field("flags", &self.flags())
413 .field("modifier", &self.modifier())
414 .field("size", &self.size())
415 .field("framerate", &self.framerate())
416 .field("max_framerate", &self.max_framerate())
417 .field("views", &self.views())
418 .field("interlace_mode", &interlace_mode)
419 .field("pixel_aspect_ratio", &self.pixel_aspect_ratio())
420 .field("multiview_mode", &self.multiview_mode())
421 .field("multiview_flags", &self.multiview_flags())
422 .field("chroma_site", &self.chroma_site())
423 .field("color_range", &self.color_range())
424 .field("color_matrix", &self.color_matrix())
425 .field("transfer_function", &self.transfer_function())
426 .field("color_primaries", &self.color_primaries())
427 .finish()
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434
435 #[test]
436 #[cfg_attr(miri, ignore)]
437 fn debug_format() {
438 assert_eq!(
439 "VideoFormat::Unknown",
440 format!("{:?}", VideoFormat::Unknown)
441 );
442 assert_eq!("VideoFormat::YV12", format!("{:?}", VideoFormat::YV12));
443 assert_eq!("VideoFormat::RGBx", format!("{:?}", VideoFormat::RGBx));
444 assert_eq!("VideoFormat::xRGB", format!("{:?}", VideoFormat::xRGB));
445 assert_eq!(
446 "VideoFormat::GRAY16_BE",
447 format!("{:?}", VideoFormat::GRAY16_BE)
448 );
449 assert_eq!(
450 "VideoFormat::xRGB_210LE",
451 format!("{:?}", VideoFormat::xRGB_210LE)
452 );
453 #[cfg(feature = "v0_3_65")]
454 assert_eq!(
455 "VideoInterlaceMode::Progressive",
456 format!("{:?}", VideoInterlaceMode::Progressive)
457 );
458 }
459}