diff --git a/Gir_GstVideo.toml b/Gir_GstVideo.toml index 5248768c5..5fc3a6350 100644 --- a/Gir_GstVideo.toml +++ b/Gir_GstVideo.toml @@ -19,7 +19,6 @@ external_libraries = [ generate = [ "GstVideo.VideoCodecFrameFlags", - "GstVideo.VideoFormat", "GstVideo.VideoFormatFlags", "GstVideo.VideoTileMode", "GstVideo.VideoInterlaceMode", @@ -242,3 +241,10 @@ manual_traits = ["VideoEncoderExtManual"] name = "allocate_output_buffer" [object.function.return] nullable_return_is_error = "Failed to allocate output buffer" + +[[object]] +name = "GstVideo.VideoFormat" +status = "generate" + + [[object.derive]] + name = "Debug, Eq, PartialEq, Hash" \ No newline at end of file diff --git a/gstreamer-video/src/auto/enums.rs b/gstreamer-video/src/auto/enums.rs index 1e84832df..75290d46f 100644 --- a/gstreamer-video/src/auto/enums.rs +++ b/gstreamer-video/src/auto/enums.rs @@ -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] pub enum VideoFormat { Unknown, diff --git a/gstreamer-video/src/video_format.rs b/gstreamer-video/src/video_format.rs index 0fc6ee2d4..2be5d052c 100644 --- a/gstreamer-video/src/video_format.rs +++ b/gstreamer-video/src/video_format.rs @@ -232,6 +232,19 @@ impl fmt::Display for ::VideoFormat { f.write_str((*self).to_str()) } } + +impl PartialOrd for ::VideoFormat { + fn partial_cmp(&self, other: &::VideoFormat) -> Option { + ::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 { idx: usize, len: usize, @@ -372,4 +385,15 @@ mod tests { .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() { + gst::init().unwrap(); + + assert!( + ::VideoFormatInfo::from_format(::VideoFormat::Nv16) + > ::VideoFormatInfo::from_format(::VideoFormat::Nv12) + ); + assert!(::VideoFormat::I420 > ::VideoFormat::Yv12); + } } diff --git a/gstreamer-video/src/video_format_info.rs b/gstreamer-video/src/video_format_info.rs index 5a544c865..cc25d03ff 100644 --- a/gstreamer-video/src/video_format_info.rs +++ b/gstreamer-video/src/video_format_info.rs @@ -8,6 +8,7 @@ use gst_video_sys; +use std::cmp::Ordering; use std::ffi::CStr; use std::fmt; use std::str; @@ -311,6 +312,95 @@ impl PartialEq for VideoFormatInfo { impl Eq for VideoFormatInfo {} +impl PartialOrd for VideoFormatInfo { + fn partial_cmp(&self, other: &VideoFormatInfo) -> Option { + 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 { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { f.debug_struct("VideoFormatInfo")