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
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    /// 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        f.write_str("VideoInterlaceMode::")?;
215        fmt_pascal_case(f, &c_str.to_string_lossy())
216    }
217}
218
219/// Rust representation of [`spa_sys::spa_video_info_raw`].
220#[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    /// helper function to parse format properties type
378    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    /// Obtain a [`VideoInfoRaw`] from a raw `spa_video_info_raw` variant.
384    pub fn from_raw(raw: spa_sys::spa_video_info_raw) -> Self {
385        Self(raw)
386    }
387
388    /// Get the raw [`spa_sys::spa_video_info_raw`] representing this `VideoInfoRaw`.
389    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}