libspa/param/video/
raw.rs

1// Copyright The pipewire-rs Contributors.
2// SPDX-License-Identifier: MIT
3
4use 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    /// 32-bit x:R:G:B 2:10:10:10 little endian
103    pub const xRGB_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xRGB_210LE);
104    ///32-bit x:B:G:R 2:10:10:10 little endian
105    pub const xBGR_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xBGR_210LE);
106    ///32-bit R:G:B:x 10:10:10:2 little endian
107    pub const RGBx_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBx_102LE);
108    /// 32-bit B:G:R:x 10:10:10:2 little endian
109    pub const BGRx_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRx_102LE);
110    /// 32-bit A:R:G:B 2:10:10:10 little endian
111    pub const ARGB_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ARGB_210LE);
112    /// 32-bit A:B:G:R 2:10:10:10 little endian
113    pub const ABGR_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ABGR_210LE);
114    /// 32-bit R:G:B:A 10:10:10:2 little endian
115    pub const RGBA_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA_102LE);
116    /// 32-bit B:G:R:A 10:10:10:2 little endian
117    pub const BGRA_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRA_102LE);
118
119    /* Aliases */
120    pub const DSP_F32: Self = Self(spa_sys::SPA_VIDEO_FORMAT_DSP_F32);
121
122    /// Obtain a [`VideoFormat`] from a raw `spa_video_format` variant.
123    pub fn from_raw(raw: spa_sys::spa_video_format) -> Self {
124        Self(raw)
125    }
126
127    /// Get the raw [`spa_sys::spa_video_format`] representing this `VideoFormat`.
128    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        /// no flags
159        const NONE = spa_sys::SPA_VIDEO_FLAG_NONE;
160        /// a variable fps is selected, fps_n and fps_d denote the maximum fps of the video
161        const VARIABLE_FPS = spa_sys::SPA_VIDEO_FLAG_VARIABLE_FPS;
162        /// Each color has been scaled by the alpha value.
163        const PREMULTIPLIED_ALPHA = spa_sys::SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
164        /// use the format modifier
165        #[cfg(feature = "v0_3_65")]
166        const MODIFIER = spa_sys::SPA_VIDEO_FLAG_MODIFIER;
167        #[cfg(feature = "v0_3_75")]
168        /// format modifier was not fixated yet
169        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    /// all frames are progressive
179    pub const Progressive: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE);
180    /// 2 fields are interleaved in one video frame.
181    /// Extra buffer flags describe the field order.
182    pub const Interleaved: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_INTERLEAVED);
183    /// frames contains both interlaced and progressive video, the buffer flags describe the frame fields.
184    pub const Mixed: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_MIXED);
185    /// 2 fields are stored in one buffer, use the frame ID to get access to the required field. For multiview (the 'views'
186    /// property > 1) the fields of view N can be found at frame ID (N * 2) and (N * 2) + 1. Each field has only half the
187    /// amount of lines as noted in the height property. This mode requires multiple spa_data to describe the fields.
188    pub const Fields: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_FIELDS);
189
190    /// Obtain a [`VideoInterlaceMode`] from a raw `spa_video_interlace_mode` variant.
191    pub fn from_raw(raw: spa_sys::spa_video_interlace_mode) -> Self {
192        Self(raw)
193    }
194
195    /// Get the raw [`spa_sys::spa_video_interlace_mode`] representing this `VideoInterlaceMode`.
196    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/// Rust representation of [`spa_sys::spa_video_info_raw`].
223#[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    /// helper function to parse format properties type
381    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    /// Obtain a [`VideoInfoRaw`] from a raw `spa_video_info_raw` variant.
387    pub fn from_raw(raw: spa_sys::spa_video_info_raw) -> Self {
388        Self(raw)
389    }
390
391    /// Get the raw [`spa_sys::spa_video_info_raw`] representing this `VideoInfoRaw`.
392    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}