video: manually order VideoFormat and VideoFormatInfo

This commit is contained in:
Guillaume Desmottes 2020-06-05 11:57:29 +02:00
parent bb065be349
commit ae57524502
4 changed files with 122 additions and 2 deletions

View file

@ -19,7 +19,6 @@ external_libraries = [
generate = [ generate = [
"GstVideo.VideoCodecFrameFlags", "GstVideo.VideoCodecFrameFlags",
"GstVideo.VideoFormat",
"GstVideo.VideoFormatFlags", "GstVideo.VideoFormatFlags",
"GstVideo.VideoTileMode", "GstVideo.VideoTileMode",
"GstVideo.VideoInterlaceMode", "GstVideo.VideoInterlaceMode",
@ -242,3 +241,10 @@ manual_traits = ["VideoEncoderExtManual"]
name = "allocate_output_buffer" name = "allocate_output_buffer"
[object.function.return] [object.function.return]
nullable_return_is_error = "Failed to allocate output buffer" nullable_return_is_error = "Failed to allocate output buffer"
[[object]]
name = "GstVideo.VideoFormat"
status = "generate"
[[object.derive]]
name = "Debug, Eq, PartialEq, Hash"

View file

@ -678,7 +678,7 @@ impl SetValue for VideoFieldOrder {
} }
} }
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] #[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
#[non_exhaustive] #[non_exhaustive]
pub enum VideoFormat { pub enum VideoFormat {
Unknown, Unknown,

View file

@ -232,6 +232,19 @@ impl fmt::Display for ::VideoFormat {
f.write_str((*self).to_str()) f.write_str((*self).to_str())
} }
} }
impl PartialOrd for ::VideoFormat {
fn partial_cmp(&self, other: &::VideoFormat) -> Option<std::cmp::Ordering> {
::VideoFormatInfo::from_format(*self).partial_cmp(&::VideoFormatInfo::from_format(*other))
}
}
impl Ord for ::VideoFormat {
fn cmp(&self, other: &::VideoFormat) -> std::cmp::Ordering {
::VideoFormatInfo::from_format(*self).cmp(&::VideoFormatInfo::from_format(*other))
}
}
pub struct VideoFormatIterator { pub struct VideoFormatIterator {
idx: usize, idx: usize,
len: usize, len: usize,
@ -372,4 +385,15 @@ mod tests {
.build(); .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 ]"); 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() {
gst::init().unwrap();
assert!(
::VideoFormatInfo::from_format(::VideoFormat::Nv16)
> ::VideoFormatInfo::from_format(::VideoFormat::Nv12)
);
assert!(::VideoFormat::I420 > ::VideoFormat::Yv12);
}
} }

View file

@ -8,6 +8,7 @@
use gst_video_sys; use gst_video_sys;
use std::cmp::Ordering;
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt; use std::fmt;
use std::str; use std::str;
@ -311,6 +312,95 @@ impl PartialEq for VideoFormatInfo {
impl Eq for VideoFormatInfo {} impl Eq for VideoFormatInfo {}
impl PartialOrd for VideoFormatInfo {
fn partial_cmp(&self, other: &VideoFormatInfo) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for VideoFormatInfo {
// See GST_VIDEO_FORMATS_ALL for the sorting algorithm
fn cmp(&self, other: &VideoFormatInfo) -> Ordering {
self.n_components()
.cmp(&other.n_components())
.then_with(|| self.depth().cmp(&other.depth()))
.then_with(|| self.w_sub().cmp(&other.w_sub()).reverse())
.then_with(|| self.h_sub().cmp(&other.h_sub()).reverse())
.then_with(|| self.n_planes().cmp(&other.n_planes()))
.then_with(|| {
// Format using native endianess is considered as bigger
match (
self.flags().contains(::VideoFormatFlags::LE),
other.flags().contains(::VideoFormatFlags::LE),
) {
(true, false) => {
// a LE, b BE
#[cfg(target_endian = "little")]
{
Ordering::Greater
}
#[cfg(target_endian = "big")]
{
Ordering::Less
}
}
(false, true) => {
// a BE, b LE
#[cfg(target_endian = "little")]
{
Ordering::Less
}
#[cfg(target_endian = "big")]
{
Ordering::Greater
}
}
_ => Ordering::Equal,
}
})
.then_with(|| self.pixel_stride().cmp(&other.pixel_stride()))
.then_with(|| self.poffset().cmp(&other.poffset()))
.then_with(|| {
// Prefer non-complex formats
match (
self.flags().contains(::VideoFormatFlags::COMPLEX),
other.flags().contains(::VideoFormatFlags::COMPLEX),
) {
(true, false) => Ordering::Less,
(false, true) => Ordering::Greater,
_ => Ordering::Equal,
}
})
.then_with(|| {
// tiebreaker: YUV > RGB
if self.flags().contains(::VideoFormatFlags::RGB)
&& other.flags().contains(::VideoFormatFlags::YUV)
{
Ordering::Less
} else if self.flags().contains(::VideoFormatFlags::YUV)
&& other.flags().contains(::VideoFormatFlags::RGB)
{
Ordering::Greater
} else {
Ordering::Equal
}
})
.then_with(|| {
// Manual tiebreaker
match (self.format(), other.format()) {
// I420 is more commonly used in GStreamer
(::VideoFormat::I420, ::VideoFormat::Yv12) => Ordering::Greater,
(::VideoFormat::Yv12, ::VideoFormat::I420) => Ordering::Less,
_ => Ordering::Equal,
}
})
.then_with(|| {
// tie, sort by name
self.name().cmp(&other.name())
})
}
}
impl fmt::Debug for VideoFormatInfo { impl fmt::Debug for VideoFormatInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("VideoFormatInfo") f.debug_struct("VideoFormatInfo")