1use crate::utils::{
5 result::{Error, SpaResult, SpaSuccess},
6 Fraction, Rectangle,
7};
8
9use std::{ffi::CStr, fmt::Debug};
10
11#[cfg(feature = "v0_3_65")]
12use crate::utils::fmt_pascal_case;
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 f.write_str("VideoInterlaceMode::")?;
215 fmt_pascal_case(f, &c_str.to_string_lossy())
216 }
217}
218
219#[repr(transparent)]
221#[derive(PartialEq, Eq, Clone, Copy)]
222pub struct VideoInfoRaw(spa_sys::spa_video_info_raw);
223
224impl VideoInfoRaw {
225 pub fn new() -> Self {
226 Self(spa_sys::spa_video_info_raw {
227 format: VideoFormat::Unknown.as_raw(),
228 flags: 0,
229 modifier: 0,
230 size: Rectangle {
231 width: 0,
232 height: 0,
233 },
234 framerate: Fraction { num: 0, denom: 0 },
235 max_framerate: Fraction { num: 0, denom: 0 },
236 views: 0,
237 interlace_mode: VideoInterlaceMode::Progressive.as_raw(),
238 pixel_aspect_ratio: Fraction { num: 0, denom: 0 },
239 multiview_mode: 0,
240 multiview_flags: 0,
241 chroma_site: 0,
242 color_range: 0,
243 color_matrix: 0,
244 transfer_function: 0,
245 color_primaries: 0,
246 })
247 }
248
249 pub fn set_format(&mut self, format: VideoFormat) {
250 self.0.format = format.as_raw();
251 }
252
253 pub fn format(self) -> VideoFormat {
254 VideoFormat::from_raw(self.0.format)
255 }
256
257 pub fn set_flags(&mut self, flags: VideoFlags) {
258 self.0.flags = flags.bits();
259 }
260
261 pub fn flags(self) -> VideoFlags {
262 VideoFlags::from_bits_retain(self.0.flags)
263 }
264
265 pub fn set_modifier(&mut self, modifier: u64) {
266 self.0.modifier = modifier;
267 }
268
269 pub fn modifier(self) -> u64 {
270 self.0.modifier
271 }
272
273 pub fn set_size(&mut self, size: Rectangle) {
274 self.0.size = size;
275 }
276
277 pub fn size(self) -> Rectangle {
278 self.0.size
279 }
280
281 pub fn set_framerate(&mut self, framerate: Fraction) {
282 self.0.framerate = framerate;
283 }
284
285 pub fn framerate(self) -> Fraction {
286 self.0.framerate
287 }
288
289 pub fn set_max_framerate(&mut self, max_framerate: Fraction) {
290 self.0.max_framerate = max_framerate;
291 }
292
293 pub fn max_framerate(self) -> Fraction {
294 self.0.max_framerate
295 }
296
297 pub fn set_views(&mut self, views: u32) {
298 self.0.views = views;
299 }
300
301 pub fn views(self) -> u32 {
302 self.0.views
303 }
304
305 pub fn set_interlace_mode(&mut self, interlace_mode: VideoInterlaceMode) {
306 self.0.interlace_mode = interlace_mode.as_raw();
307 }
308
309 pub fn interlace_mode(self) -> VideoInterlaceMode {
310 VideoInterlaceMode::from_raw(self.0.interlace_mode)
311 }
312
313 pub fn set_pixel_aspect_ratio(&mut self, pixel_aspect_ratio: Fraction) {
314 self.0.pixel_aspect_ratio = pixel_aspect_ratio;
315 }
316
317 pub fn pixel_aspect_ratio(self) -> Fraction {
318 self.0.pixel_aspect_ratio
319 }
320
321 pub fn set_multiview_mode(&mut self, multiview_mode: i32) {
322 self.0.multiview_mode = multiview_mode;
323 }
324
325 pub fn multiview_mode(self) -> i32 {
326 self.0.multiview_mode
327 }
328
329 pub fn set_multiview_flags(&mut self, multiview_flags: u32) {
330 self.0.multiview_flags = multiview_flags;
331 }
332
333 pub fn multiview_flags(self) -> u32 {
334 self.0.multiview_flags
335 }
336
337 pub fn set_chroma_site(&mut self, chroma_site: u32) {
338 self.0.chroma_site = chroma_site;
339 }
340
341 pub fn chroma_site(self) -> u32 {
342 self.0.chroma_site
343 }
344
345 pub fn set_color_range(&mut self, color_range: u32) {
346 self.0.color_range = color_range;
347 }
348
349 pub fn color_range(self) -> u32 {
350 self.0.color_range
351 }
352
353 pub fn set_color_matrix(&mut self, color_matrix: u32) {
354 self.0.color_matrix = color_matrix;
355 }
356
357 pub fn color_matrix(self) -> u32 {
358 self.0.color_matrix
359 }
360
361 pub fn set_transfer_function(&mut self, transfer_function: u32) {
362 self.0.transfer_function = transfer_function;
363 }
364
365 pub fn transfer_function(self) -> u32 {
366 self.0.transfer_function
367 }
368
369 pub fn set_color_primaries(&mut self, color_primaries: u32) {
370 self.0.color_primaries = color_primaries;
371 }
372
373 pub fn color_primaries(self) -> u32 {
374 self.0.color_primaries
375 }
376
377 pub fn parse(&mut self, format: &crate::pod::Pod) -> Result<SpaSuccess, Error> {
379 let res = unsafe { spa_sys::spa_format_video_raw_parse(format.as_raw_ptr(), &mut self.0) };
380 SpaResult::from_c(res).into_result()
381 }
382
383 pub fn from_raw(raw: spa_sys::spa_video_info_raw) -> Self {
385 Self(raw)
386 }
387
388 pub fn as_raw(&self) -> spa_sys::spa_video_info_raw {
390 self.0
391 }
392}
393
394impl Default for VideoInfoRaw {
395 fn default() -> Self {
396 Self::new()
397 }
398}
399
400impl Debug for VideoInfoRaw {
401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402 #[cfg(feature = "v0_3_65")]
403 let interlace_mode = self.interlace_mode();
404 #[cfg(not(feature = "v0_3_65"))]
405 let interlace_mode = self.interlace_mode().as_raw();
406
407 f.debug_struct("VideoInfoRaw")
408 .field("format", &self.format())
409 .field("flags", &self.flags())
410 .field("modifier", &self.modifier())
411 .field("size", &self.size())
412 .field("framerate", &self.framerate())
413 .field("max_framerate", &self.max_framerate())
414 .field("views", &self.views())
415 .field("interlace_mode", &interlace_mode)
416 .field("pixel_aspect_ratio", &self.pixel_aspect_ratio())
417 .field("multiview_mode", &self.multiview_mode())
418 .field("multiview_flags", &self.multiview_flags())
419 .field("chroma_site", &self.chroma_site())
420 .field("color_range", &self.color_range())
421 .field("color_matrix", &self.color_matrix())
422 .field("transfer_function", &self.transfer_function())
423 .field("color_primaries", &self.color_primaries())
424 .finish()
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 #[test]
433 #[cfg_attr(miri, ignore)]
434 fn debug_format() {
435 assert_eq!(
436 "VideoFormat::Unknown",
437 format!("{:?}", VideoFormat::Unknown)
438 );
439 assert_eq!("VideoFormat::YV12", format!("{:?}", VideoFormat::YV12));
440 assert_eq!("VideoFormat::RGBx", format!("{:?}", VideoFormat::RGBx));
441 assert_eq!("VideoFormat::xRGB", format!("{:?}", VideoFormat::xRGB));
442 assert_eq!(
443 "VideoFormat::GRAY16_BE",
444 format!("{:?}", VideoFormat::GRAY16_BE)
445 );
446 assert_eq!(
447 "VideoFormat::xRGB_210LE",
448 format!("{:?}", VideoFormat::xRGB_210LE)
449 );
450 #[cfg(feature = "v0_3_65")]
451 assert_eq!(
452 "VideoInterlaceMode::Progressive",
453 format!("{:?}", VideoInterlaceMode::Progressive)
454 );
455 }
456}