gstreamer-rs/gstreamer-video/src/video_format.rs
Bilal Elmoussaoui 4ebec84f5e Adapt to no longer renamed ffi crates
Allows us to set all the crates in the main workspace file, so changing
their versions or branch is much simpler and reduce the amount of noise
in the diff

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1450>
2024-06-02 11:20:55 +02:00

562 lines
17 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use std::str;
use crate::ffi;
use glib::translate::{from_glib, FromGlib, IntoGlib};
use once_cell::sync::Lazy;
#[cfg(feature = "v1_18")]
pub static VIDEO_FORMATS_ALL: Lazy<Box<[crate::VideoFormat]>> = Lazy::new(|| unsafe {
let mut len: u32 = 0;
let mut res = Vec::with_capacity(len as usize);
let formats = ffi::gst_video_formats_raw(&mut len);
for i in 0..len {
let format = formats.offset(i as isize);
res.push(from_glib(*format));
}
res.into_boxed_slice()
});
#[cfg(not(feature = "v1_18"))]
pub static VIDEO_FORMATS_ALL: Lazy<Box<[crate::VideoFormat]>> = Lazy::new(|| {
#[cfg(target_endian = "little")]
{
Box::new([
crate::VideoFormat::Ayuv64,
crate::VideoFormat::Argb64,
crate::VideoFormat::Gbra12le,
crate::VideoFormat::Gbra12be,
crate::VideoFormat::A44410le,
crate::VideoFormat::Gbra10le,
crate::VideoFormat::A44410be,
crate::VideoFormat::Gbra10be,
crate::VideoFormat::A42210le,
crate::VideoFormat::A42210be,
crate::VideoFormat::A42010le,
crate::VideoFormat::A42010be,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Bgr10a2Le,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Y410,
crate::VideoFormat::Gbra,
crate::VideoFormat::Ayuv,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Vuya,
crate::VideoFormat::Rgba,
crate::VideoFormat::Argb,
crate::VideoFormat::Bgra,
crate::VideoFormat::Abgr,
crate::VideoFormat::A420,
crate::VideoFormat::V216,
crate::VideoFormat::Y44412le,
crate::VideoFormat::Gbr12le,
crate::VideoFormat::Y44412be,
crate::VideoFormat::Gbr12be,
crate::VideoFormat::I42212le,
crate::VideoFormat::I42212be,
crate::VideoFormat::I42012le,
crate::VideoFormat::I42012be,
crate::VideoFormat::Y44410le,
crate::VideoFormat::Gbr10le,
crate::VideoFormat::Y44410be,
crate::VideoFormat::Gbr10be,
crate::VideoFormat::R210,
crate::VideoFormat::I42210le,
crate::VideoFormat::I42210be,
crate::VideoFormat::Nv1610le32,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Y210,
crate::VideoFormat::Uyvp,
crate::VideoFormat::V210,
crate::VideoFormat::I42010le,
crate::VideoFormat::I42010be,
crate::VideoFormat::P01010le,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Nv1210le40,
crate::VideoFormat::Nv1210le32,
crate::VideoFormat::P01010be,
crate::VideoFormat::Y444,
crate::VideoFormat::Gbr,
crate::VideoFormat::Nv24,
crate::VideoFormat::V308,
crate::VideoFormat::Iyu2,
crate::VideoFormat::Rgbx,
crate::VideoFormat::Xrgb,
crate::VideoFormat::Bgrx,
crate::VideoFormat::Xbgr,
crate::VideoFormat::Rgb,
crate::VideoFormat::Bgr,
crate::VideoFormat::Y42b,
crate::VideoFormat::Nv16,
crate::VideoFormat::Nv61,
crate::VideoFormat::Yuy2,
crate::VideoFormat::Yvyu,
crate::VideoFormat::Uyvy,
crate::VideoFormat::Vyuy,
crate::VideoFormat::I420,
crate::VideoFormat::Yv12,
crate::VideoFormat::Nv12,
crate::VideoFormat::Nv21,
crate::VideoFormat::Nv1264z32,
crate::VideoFormat::Y41b,
crate::VideoFormat::Iyu1,
crate::VideoFormat::Yuv9,
crate::VideoFormat::Yvu9,
crate::VideoFormat::Bgr16,
crate::VideoFormat::Rgb16,
crate::VideoFormat::Bgr15,
crate::VideoFormat::Rgb15,
crate::VideoFormat::Rgb8p,
crate::VideoFormat::Gray16Le,
crate::VideoFormat::Gray16Be,
crate::VideoFormat::Gray10Le32,
crate::VideoFormat::Gray8,
])
}
#[cfg(target_endian = "big")]
{
Box::new([
crate::VideoFormat::Ayuv64,
crate::VideoFormat::Argb64,
crate::VideoFormat::Gbra12be,
crate::VideoFormat::Gbra12le,
crate::VideoFormat::A44410be,
crate::VideoFormat::Gbra10be,
crate::VideoFormat::A44410le,
crate::VideoFormat::Gbra10le,
crate::VideoFormat::A42210be,
crate::VideoFormat::A42210le,
crate::VideoFormat::A42010be,
crate::VideoFormat::A42010le,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Bgr10a2Le,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Y410,
crate::VideoFormat::Gbra,
crate::VideoFormat::Ayuv,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Vuya,
crate::VideoFormat::Rgba,
crate::VideoFormat::Argb,
crate::VideoFormat::Bgra,
crate::VideoFormat::Abgr,
crate::VideoFormat::A420,
crate::VideoFormat::V216,
crate::VideoFormat::Y44412be,
crate::VideoFormat::Gbr12be,
crate::VideoFormat::Y44412le,
crate::VideoFormat::Gbr12le,
crate::VideoFormat::I42212be,
crate::VideoFormat::I42212le,
crate::VideoFormat::I42012be,
crate::VideoFormat::I42012le,
crate::VideoFormat::Y44410be,
crate::VideoFormat::Gbr10be,
crate::VideoFormat::Y44410le,
crate::VideoFormat::Gbr10le,
crate::VideoFormat::R210,
crate::VideoFormat::I42210be,
crate::VideoFormat::I42210le,
crate::VideoFormat::Nv1610le32,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Y210,
crate::VideoFormat::Uyvp,
crate::VideoFormat::V210,
crate::VideoFormat::I42010be,
crate::VideoFormat::I42010le,
crate::VideoFormat::P01010be,
crate::VideoFormat::P01010le,
#[cfg(feature = "v1_16")]
crate::VideoFormat::Nv1210le40,
crate::VideoFormat::Nv1210le32,
crate::VideoFormat::Y444,
crate::VideoFormat::Gbr,
crate::VideoFormat::Nv24,
crate::VideoFormat::V308,
crate::VideoFormat::Iyu2,
crate::VideoFormat::Rgbx,
crate::VideoFormat::Xrgb,
crate::VideoFormat::Bgrx,
crate::VideoFormat::Xbgr,
crate::VideoFormat::Rgb,
crate::VideoFormat::Bgr,
crate::VideoFormat::Y42b,
crate::VideoFormat::Nv16,
crate::VideoFormat::Nv61,
crate::VideoFormat::Yuy2,
crate::VideoFormat::Yvyu,
crate::VideoFormat::Uyvy,
crate::VideoFormat::Vyuy,
crate::VideoFormat::I420,
crate::VideoFormat::Yv12,
crate::VideoFormat::Nv12,
crate::VideoFormat::Nv21,
crate::VideoFormat::Nv1264z32,
crate::VideoFormat::Y41b,
crate::VideoFormat::Iyu1,
crate::VideoFormat::Yuv9,
crate::VideoFormat::Yvu9,
crate::VideoFormat::Bgr16,
crate::VideoFormat::Rgb16,
crate::VideoFormat::Bgr15,
crate::VideoFormat::Rgb15,
crate::VideoFormat::Rgb8p,
crate::VideoFormat::Gray16Be,
crate::VideoFormat::Gray16Le,
crate::VideoFormat::Gray10Le32,
crate::VideoFormat::Gray8,
])
}
});
#[cfg(feature = "v1_24")]
pub static VIDEO_FORMATS_ANY: Lazy<Box<[crate::VideoFormat]>> = Lazy::new(|| unsafe {
let mut len: u32 = 0;
let mut res = Vec::with_capacity(len as usize);
let formats = ffi::gst_video_formats_any(&mut len);
for i in 0..len {
let format = formats.offset(i as isize);
res.push(from_glib(*format));
}
res.into_boxed_slice()
});
#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
pub enum VideoEndianness {
Unknown,
LittleEndian = 1234,
BigEndian = 4321,
}
impl FromGlib<i32> for VideoEndianness {
#[inline]
unsafe fn from_glib(value: i32) -> Self {
skip_assert_initialized!();
match value {
1234 => Self::LittleEndian,
4321 => Self::BigEndian,
_ => Self::Unknown,
}
}
}
impl IntoGlib for VideoEndianness {
type GlibType = i32;
#[inline]
fn into_glib(self) -> i32 {
match self {
Self::LittleEndian => 1234,
Self::BigEndian => 4321,
_ => 0,
}
}
}
impl crate::VideoFormat {
#[doc(alias = "gst_video_format_from_masks")]
pub fn from_masks(
depth: u32,
bpp: u32,
endianness: crate::VideoEndianness,
red_mask: u32,
blue_mask: u32,
green_mask: u32,
alpha_mask: u32,
) -> Self {
assert_initialized_main_thread!();
unsafe {
from_glib(ffi::gst_video_format_from_masks(
depth as i32,
bpp as i32,
endianness.into_glib(),
red_mask,
blue_mask,
green_mask,
alpha_mask,
))
}
}
#[doc(alias = "gst_video_format_to_string")]
pub fn to_str<'a>(self) -> &'a glib::GStr {
if self == Self::Unknown {
return glib::gstr!("UNKNOWN");
}
unsafe {
glib::GStr::from_ptr(
ffi::gst_video_format_to_string(self.into_glib())
.as_ref()
.expect("gst_video_format_to_string returned NULL"),
)
}
}
pub fn iter_raw() -> VideoFormatIterator {
VideoFormatIterator::default()
}
#[cfg(feature = "v1_24")]
pub fn iter_any() -> impl Iterator<Item = crate::VideoFormat> {
VIDEO_FORMATS_ANY.iter().copied()
}
}
impl str::FromStr for crate::VideoFormat {
type Err = glib::BoolError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
skip_assert_initialized!();
let fmt = Self::from_string(s);
if fmt == Self::Unknown {
Err(glib::bool_error!(
"Failed to parse video format from string"
))
} else {
Ok(fmt)
}
}
}
impl PartialOrd for crate::VideoFormat {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for crate::VideoFormat {
#[inline]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
crate::VideoFormatInfo::from_format(*self).cmp(&crate::VideoFormatInfo::from_format(*other))
}
}
pub struct VideoFormatIterator {
idx: usize,
len: usize,
}
impl Default for VideoFormatIterator {
fn default() -> Self {
Self {
idx: 0,
len: VIDEO_FORMATS_ALL.len(),
}
}
}
impl Iterator for VideoFormatIterator {
type Item = crate::VideoFormat;
fn next(&mut self) -> Option<Self::Item> {
if self.idx >= self.len {
None
} else {
let fmt = VIDEO_FORMATS_ALL[self.idx];
self.idx += 1;
Some(fmt)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.idx == self.len {
return (0, Some(0));
}
let remaining = self.len - self.idx;
(remaining, Some(remaining))
}
fn count(self) -> usize {
self.len - self.idx
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
let (end, overflow) = self.idx.overflowing_add(n);
if end >= self.len || overflow {
self.idx = self.len;
None
} else {
self.idx = end + 1;
Some(VIDEO_FORMATS_ALL[end])
}
}
fn last(self) -> Option<Self::Item> {
if self.idx == self.len {
None
} else {
Some(VIDEO_FORMATS_ALL[self.len - 1])
}
}
}
impl ExactSizeIterator for VideoFormatIterator {}
impl std::iter::FusedIterator for VideoFormatIterator {}
impl DoubleEndedIterator for VideoFormatIterator {
fn next_back(&mut self) -> Option<Self::Item> {
if self.idx >= self.len {
None
} else {
let fmt = VIDEO_FORMATS_ALL[self.len - 1];
self.len -= 1;
Some(fmt)
}
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let (end, overflow) = self.len.overflowing_sub(n);
if end <= self.idx || overflow {
self.idx = self.len;
None
} else {
self.len = end - 1;
let fmt = VIDEO_FORMATS_ALL[self.len];
Some(fmt)
}
}
}
pub trait VideoFormatIteratorExt {
fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
}
impl<T> VideoFormatIteratorExt for T
where
T: Iterator<Item = crate::VideoFormat>,
{
fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
let formats: Vec<crate::VideoFormat> = self.collect();
if !formats.is_empty() {
Some(crate::functions::video_make_raw_caps(&formats))
} else {
None
}
}
}
pub trait VideoFormatIteratorExtRef {
fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>>;
}
impl<'a, T> VideoFormatIteratorExtRef for T
where
T: Iterator<Item = &'a crate::VideoFormat>,
{
fn into_video_caps(self) -> Option<crate::VideoCapsBuilder<gst::caps::NoFeature>> {
let formats: Vec<crate::VideoFormat> = self.copied().collect();
if !formats.is_empty() {
Some(crate::functions::video_make_raw_caps(&formats))
} else {
None
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn enum_to_string() {
gst::init().unwrap();
assert_eq!(&format!("{}", crate::VideoFormat::Argb), "ARGB");
assert_eq!(&format!("{:?}", crate::VideoFormat::Argb), "Argb");
assert_eq!(crate::VideoFormat::Argb.to_str(), "ARGB");
assert_eq!(&format!("{}", crate::VideoFormat::Unknown), "UNKNOWN");
assert_eq!(&format!("{:?}", crate::VideoFormat::Unknown), "Unknown");
assert_eq!(crate::VideoFormat::Unknown.to_str(), "UNKNOWN");
assert_eq!(
&format!("{:?}", crate::VideoFormat::__Unknown(-1)),
"__Unknown(-1)"
);
}
#[test]
fn test_display() {
gst::init().unwrap();
assert_eq!(format!("{}", crate::VideoFormat::Nv16), "NV16");
assert_eq!(format!("{:?}", crate::VideoFormat::Nv16), "Nv16");
}
#[test]
fn iter() {
use super::*;
gst::init().unwrap();
assert!(crate::VideoFormat::iter_raw().count() > 0);
assert_eq!(
crate::VideoFormat::iter_raw().count(),
crate::VideoFormat::iter_raw().len()
);
let mut i = crate::VideoFormat::iter_raw();
let mut count = 0;
loop {
if i.next().is_none() {
break;
}
count += 1;
if i.next_back().is_none() {
break;
}
count += 1;
}
assert_eq!(count, crate::VideoFormat::iter_raw().len());
assert!(crate::VideoFormat::iter_raw().any(|f| f == crate::VideoFormat::Nv12));
assert!(!crate::VideoFormat::iter_raw().any(|f| f == crate::VideoFormat::Encoded));
let caps = crate::VideoFormat::iter_raw().into_video_caps();
assert!(caps.is_some());
let caps = crate::VideoFormat::iter_raw()
.filter(|f| crate::VideoFormatInfo::from_format(*f).is_gray())
.into_video_caps();
assert!(caps.is_some());
let caps = crate::VideoFormat::iter_raw().skip(1000).into_video_caps();
assert!(caps.is_none());
let caps = [crate::VideoFormat::Nv12, crate::VideoFormat::Nv16]
.iter()
.into_video_caps()
.unwrap()
.build();
assert_eq!(caps.to_string(), "video/x-raw, format=(string){ NV12, NV16 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]");
}
#[test]
fn sort() {
use itertools::Itertools;
gst::init().unwrap();
assert!(
crate::VideoFormatInfo::from_format(crate::VideoFormat::Nv16)
> crate::VideoFormatInfo::from_format(crate::VideoFormat::Nv12)
);
assert!(crate::VideoFormat::I420 > crate::VideoFormat::Yv12);
assert!(crate::VideoFormat::Nv12 > crate::VideoFormat::Nv21);
assert!(crate::VideoFormat::Xrgb > crate::VideoFormat::Rgb);
let sorted: Vec<crate::VideoFormat> =
crate::VideoFormat::iter_raw().sorted().rev().collect();
// FIXME: use is_sorted_by() once API is in stable
assert_eq!(
sorted,
crate::VideoFormat::iter_raw().collect::<Vec<crate::VideoFormat>>()
);
}
}