use crate::utils::{
result::{Error, SpaResult, SpaSuccess},
Fraction, Rectangle,
};
#[cfg(feature = "v0_3_65")]
use convert_case::{Case, Casing};
use std::{ffi::CStr, fmt::Debug};
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct VideoFormat(pub spa_sys::spa_video_format);
#[allow(non_upper_case_globals)]
impl VideoFormat {
pub const Unknown: Self = Self(spa_sys::SPA_VIDEO_FORMAT_UNKNOWN);
pub const Encoded: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ENCODED);
pub const I420: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420);
pub const YV12: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YV12);
pub const YUY2: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YUY2);
pub const UYVY: Self = Self(spa_sys::SPA_VIDEO_FORMAT_UYVY);
pub const AYUV: Self = Self(spa_sys::SPA_VIDEO_FORMAT_AYUV);
pub const RGBx: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBx);
pub const BGRx: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRx);
pub const xRGB: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xRGB);
pub const xBGR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xBGR);
pub const RGBA: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA);
pub const BGRA: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRA);
pub const ARGB: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ARGB);
pub const ABGR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ABGR);
pub const RGB: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB);
pub const BGR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGR);
pub const Y41B: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y41B);
pub const Y42B: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y42B);
pub const YVYU: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YVYU);
pub const Y444: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444);
pub const v210: Self = Self(spa_sys::SPA_VIDEO_FORMAT_v210);
pub const v216: Self = Self(spa_sys::SPA_VIDEO_FORMAT_v216);
pub const NV12: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV12);
pub const NV21: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV21);
pub const GRAY8: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GRAY8);
pub const GRAY16_BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GRAY16_BE);
pub const GRAY16_LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GRAY16_LE);
pub const v308: Self = Self(spa_sys::SPA_VIDEO_FORMAT_v308);
pub const RGB16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB16);
pub const BGR16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGR16);
pub const RGB15: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB15);
pub const BGR15: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGR15);
pub const UYVP: Self = Self(spa_sys::SPA_VIDEO_FORMAT_UYVP);
pub const A420: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A420);
pub const RGB8P: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGB8P);
pub const YUV9: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YUV9);
pub const YVU9: Self = Self(spa_sys::SPA_VIDEO_FORMAT_YVU9);
pub const IYU1: Self = Self(spa_sys::SPA_VIDEO_FORMAT_IYU1);
pub const ARGB64: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ARGB64);
pub const AYUV64: Self = Self(spa_sys::SPA_VIDEO_FORMAT_AYUV64);
pub const r210: Self = Self(spa_sys::SPA_VIDEO_FORMAT_r210);
pub const I420_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_10BE);
pub const I420_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_10LE);
pub const I422_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_10BE);
pub const I422_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_10LE);
pub const Y444_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_10BE);
pub const Y444_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_10LE);
pub const GBR: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR);
pub const GBR_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_10BE);
pub const GBR_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_10LE);
pub const NV16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV16);
pub const NV24: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV24);
pub const NV12_64Z32: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV12_64Z32);
pub const A420_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A420_10BE);
pub const A420_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A420_10LE);
pub const A422_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A422_10BE);
pub const A422_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A422_10LE);
pub const A444_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A444_10BE);
pub const A444_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_A444_10LE);
pub const NV61: Self = Self(spa_sys::SPA_VIDEO_FORMAT_NV61);
pub const P010_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_P010_10BE);
pub const P010_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_P010_10LE);
pub const IYU2: Self = Self(spa_sys::SPA_VIDEO_FORMAT_IYU2);
pub const VYUY: Self = Self(spa_sys::SPA_VIDEO_FORMAT_VYUY);
pub const GBRA: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA);
pub const GBRA_10BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_10BE);
pub const GBRA_10LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_10LE);
pub const GBR_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_12BE);
pub const GBR_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBR_12LE);
pub const GBRA_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_12BE);
pub const GBRA_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_GBRA_12LE);
pub const I420_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_12BE);
pub const I420_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I420_12LE);
pub const I422_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_12BE);
pub const I422_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_I422_12LE);
pub const Y444_12BE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_12BE);
pub const Y444_12LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_Y444_12LE);
pub const RGBA_F16: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA_F16);
pub const RGBA_F32: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA_F32);
pub const xRGB_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xRGB_210LE);
pub const xBGR_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_xBGR_210LE);
pub const RGBx_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBx_102LE);
pub const BGRx_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRx_102LE);
pub const ARGB_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ARGB_210LE);
pub const ABGR_210LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_ABGR_210LE);
pub const RGBA_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_RGBA_102LE);
pub const BGRA_102LE: Self = Self(spa_sys::SPA_VIDEO_FORMAT_BGRA_102LE);
pub const DSP_F32: Self = Self(spa_sys::SPA_VIDEO_FORMAT_DSP_F32);
pub fn from_raw(raw: spa_sys::spa_video_format) -> Self {
Self(raw)
}
pub fn as_raw(&self) -> spa_sys::spa_video_format {
self.0
}
}
impl Debug for VideoFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
VideoFormat::Unknown => f.write_str("VideoFormat::Unknown"),
_ => {
let c_str = unsafe {
let c_buf = spa_sys::spa_debug_type_find_short_name(
spa_sys::spa_type_video_format,
self.as_raw(),
);
if c_buf.is_null() {
return f.write_str("Unsupported");
}
CStr::from_ptr(c_buf)
};
let name = format!("VideoFormat::{}", c_str.to_string_lossy());
f.write_str(&name)
}
}
}
}
bitflags::bitflags! {
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct VideoFlags: u32 {
const NONE = spa_sys::SPA_VIDEO_FLAG_NONE;
const VARIABLE_FPS = spa_sys::SPA_VIDEO_FLAG_VARIABLE_FPS;
const PREMULTIPLIED_ALPHA = spa_sys::SPA_VIDEO_FLAG_PREMULTIPLIED_ALPHA;
#[cfg(feature = "v0_3_65")]
const MODIFIER = spa_sys::SPA_VIDEO_FLAG_MODIFIER;
#[cfg(feature = "v0_3_75")]
const MODIFIER_FIXATION_REQUIRED = spa_sys::SPA_VIDEO_FLAG_MODIFIER_FIXATION_REQUIRED;
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct VideoInterlaceMode(pub spa_sys::spa_video_interlace_mode);
#[allow(non_upper_case_globals)]
impl VideoInterlaceMode {
pub const Progressive: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_PROGRESSIVE);
pub const Interleaved: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_INTERLEAVED);
pub const Mixed: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_MIXED);
pub const Fields: Self = Self(spa_sys::SPA_VIDEO_INTERLACE_MODE_FIELDS);
pub fn from_raw(raw: spa_sys::spa_video_interlace_mode) -> Self {
Self(raw)
}
pub fn as_raw(&self) -> spa_sys::spa_video_interlace_mode {
self.0
}
}
#[cfg(feature = "v0_3_65")]
impl Debug for VideoInterlaceMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let c_str = unsafe {
let c_buf = spa_sys::spa_debug_type_find_short_name(
spa_sys::spa_type_video_interlace_mode,
self.as_raw(),
);
if c_buf.is_null() {
return f.write_str("Unsupported");
}
CStr::from_ptr(c_buf)
};
let name = format!(
"VideoInterlaceMode::{}",
c_str.to_string_lossy().to_case(Case::Pascal)
);
f.write_str(&name)
}
}
#[repr(transparent)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct VideoInfoRaw(spa_sys::spa_video_info_raw);
impl VideoInfoRaw {
pub fn new() -> Self {
Self(spa_sys::spa_video_info_raw {
format: VideoFormat::Unknown.as_raw(),
flags: 0,
modifier: 0,
size: Rectangle {
width: 0,
height: 0,
},
framerate: Fraction { num: 0, denom: 0 },
max_framerate: Fraction { num: 0, denom: 0 },
views: 0,
interlace_mode: VideoInterlaceMode::Progressive.as_raw(),
pixel_aspect_ratio: Fraction { num: 0, denom: 0 },
multiview_mode: 0,
multiview_flags: 0,
chroma_site: 0,
color_range: 0,
color_matrix: 0,
transfer_function: 0,
color_primaries: 0,
})
}
pub fn set_format(&mut self, format: VideoFormat) {
self.0.format = format.as_raw();
}
pub fn format(self) -> VideoFormat {
VideoFormat::from_raw(self.0.format)
}
pub fn set_flags(&mut self, flags: VideoFlags) {
self.0.flags = flags.bits();
}
pub fn flags(self) -> VideoFlags {
VideoFlags::from_bits_retain(self.0.flags)
}
pub fn set_modifier(&mut self, modifier: u64) {
self.0.modifier = modifier;
}
pub fn modifier(self) -> u64 {
self.0.modifier
}
pub fn set_size(&mut self, size: Rectangle) {
self.0.size = size;
}
pub fn size(self) -> Rectangle {
self.0.size
}
pub fn set_framerate(&mut self, framerate: Fraction) {
self.0.framerate = framerate;
}
pub fn framerate(self) -> Fraction {
self.0.framerate
}
pub fn set_max_framerate(&mut self, max_framerate: Fraction) {
self.0.max_framerate = max_framerate;
}
pub fn max_framerate(self) -> Fraction {
self.0.max_framerate
}
pub fn set_views(&mut self, views: u32) {
self.0.views = views;
}
pub fn views(self) -> u32 {
self.0.views
}
pub fn set_interlace_mode(&mut self, interlace_mode: VideoInterlaceMode) {
self.0.interlace_mode = interlace_mode.as_raw();
}
pub fn interlace_mode(self) -> VideoInterlaceMode {
VideoInterlaceMode::from_raw(self.0.interlace_mode)
}
pub fn set_pixel_aspect_ratio(&mut self, pixel_aspect_ratio: Fraction) {
self.0.pixel_aspect_ratio = pixel_aspect_ratio;
}
pub fn pixel_aspect_ratio(self) -> Fraction {
self.0.pixel_aspect_ratio
}
pub fn set_multiview_mode(&mut self, multiview_mode: i32) {
self.0.multiview_mode = multiview_mode;
}
pub fn multiview_mode(self) -> i32 {
self.0.multiview_mode
}
pub fn set_multiview_flags(&mut self, multiview_flags: u32) {
self.0.multiview_flags = multiview_flags;
}
pub fn multiview_flags(self) -> u32 {
self.0.multiview_flags
}
pub fn set_chroma_site(&mut self, chroma_site: u32) {
self.0.chroma_site = chroma_site;
}
pub fn chroma_site(self) -> u32 {
self.0.chroma_site
}
pub fn set_color_range(&mut self, color_range: u32) {
self.0.color_range = color_range;
}
pub fn color_range(self) -> u32 {
self.0.color_range
}
pub fn set_color_matrix(&mut self, color_matrix: u32) {
self.0.color_matrix = color_matrix;
}
pub fn color_matrix(self) -> u32 {
self.0.color_matrix
}
pub fn set_transfer_function(&mut self, transfer_function: u32) {
self.0.transfer_function = transfer_function;
}
pub fn transfer_function(self) -> u32 {
self.0.transfer_function
}
pub fn set_color_primaries(&mut self, color_primaries: u32) {
self.0.color_primaries = color_primaries;
}
pub fn color_primaries(self) -> u32 {
self.0.color_primaries
}
pub fn parse(&mut self, format: &crate::pod::Pod) -> Result<SpaSuccess, Error> {
let res = unsafe { spa_sys::spa_format_video_raw_parse(format.as_raw_ptr(), &mut self.0) };
SpaResult::from_c(res).into_result()
}
pub fn from_raw(raw: spa_sys::spa_video_info_raw) -> Self {
Self(raw)
}
pub fn as_raw(&self) -> spa_sys::spa_video_info_raw {
self.0
}
}
impl Default for VideoInfoRaw {
fn default() -> Self {
Self::new()
}
}
impl Debug for VideoInfoRaw {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
#[cfg(feature = "v0_3_65")]
let interlace_mode = self.interlace_mode();
#[cfg(not(feature = "v0_3_65"))]
let interlace_mode = self.interlace_mode().as_raw();
f.debug_struct("VideoInfoRaw")
.field("format", &self.format())
.field("flags", &self.flags())
.field("modifier", &self.modifier())
.field("size", &self.size())
.field("framerate", &self.framerate())
.field("max_framerate", &self.max_framerate())
.field("views", &self.views())
.field("interlace_mode", &interlace_mode)
.field("pixel_aspect_ratio", &self.pixel_aspect_ratio())
.field("multiview_mode", &self.multiview_mode())
.field("multiview_flags", &self.multiview_flags())
.field("chroma_site", &self.chroma_site())
.field("color_range", &self.color_range())
.field("color_matrix", &self.color_matrix())
.field("transfer_function", &self.transfer_function())
.field("color_primaries", &self.color_primaries())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg_attr(miri, ignore)]
fn debug_format() {
assert_eq!(
"VideoFormat::Unknown",
format!("{:?}", VideoFormat::Unknown)
);
assert_eq!("VideoFormat::YV12", format!("{:?}", VideoFormat::YV12));
assert_eq!("VideoFormat::RGBx", format!("{:?}", VideoFormat::RGBx));
assert_eq!("VideoFormat::xRGB", format!("{:?}", VideoFormat::xRGB));
assert_eq!(
"VideoFormat::GRAY16_BE",
format!("{:?}", VideoFormat::GRAY16_BE)
);
assert_eq!(
"VideoFormat::xRGB_210LE",
format!("{:?}", VideoFormat::xRGB_210LE)
);
#[cfg(feature = "v0_3_65")]
assert_eq!(
"VideoInterlaceMode::Progressive",
format!("{:?}", VideoInterlaceMode::Progressive)
);
}
}