diff --git a/gstreamer-video/src/lib.rs b/gstreamer-video/src/lib.rs index 5720e2130..23adff87d 100644 --- a/gstreamer-video/src/lib.rs +++ b/gstreamer-video/src/lib.rs @@ -12,6 +12,7 @@ pub use gst_base; macro_rules! assert_initialized_main_thread { () => { + #[allow(unused_unsafe)] if unsafe { gst::ffi::gst_is_initialized() } != glib::ffi::GTRUE { panic!("GStreamer has not been initialized. Call `gst::init` first."); } diff --git a/gstreamer-video/src/video_format_info.rs b/gstreamer-video/src/video_format_info.rs index 1e9247cfb..3aa018f7a 100644 --- a/gstreamer-video/src/video_format_info.rs +++ b/gstreamer-video/src/video_format_info.rs @@ -12,6 +12,12 @@ use glib::translate::{from_glib, IntoGlib, ToGlibPtr}; pub struct VideoFormatInfo(&'static ffi::GstVideoFormatInfo); impl VideoFormatInfo { + pub unsafe fn from_ptr(format_info: *const ffi::GstVideoFormatInfo) -> Self { + assert_initialized_main_thread!(); + assert!(!format_info.is_null()); + Self(&*format_info) + } + pub fn from_format(format: crate::VideoFormat) -> Self { assert_initialized_main_thread!(); diff --git a/gstreamer-video/src/video_frame.rs b/gstreamer-video/src/video_frame.rs index cad8c10ba..92c5ff42c 100644 --- a/gstreamer-video/src/video_frame.rs +++ b/gstreamer-video/src/video_frame.rs @@ -120,6 +120,16 @@ impl VideoFrame { self.flags().contains(crate::VideoFrameFlags::ONEFIELD) } + pub fn is_bottom_field(&self) -> bool { + self.flags().contains(crate::VideoFrameFlags::ONEFIELD) + && !self.flags().contains(crate::VideoFrameFlags::TFF) + } + + pub fn is_top_field(&self) -> bool { + self.flags().contains(crate::VideoFrameFlags::ONEFIELD) + && self.flags().contains(crate::VideoFrameFlags::TFF) + } + pub fn n_planes(&self) -> u32 { self.info().n_planes() } @@ -136,6 +146,43 @@ impl VideoFrame { self.info().offset() } + pub fn comp_data(&self, component: u32) -> Result<&[u8], glib::BoolError> { + let poffset = self.info().comp_poffset(component as u8) as usize; + Ok(&self.plane_data(self.format_info().plane()[component as usize])?[poffset..]) + } + + pub fn comp_depth(&self, component: u32) -> u32 { + self.info().comp_depth(component as u8) + } + + pub fn comp_height(&self, component: u32) -> u32 { + self.info().comp_height(component as u8) + } + + pub fn comp_width(&self, component: u32) -> u32 { + self.info().comp_width(component as u8) + } + + pub fn comp_offset(&self, component: u32) -> usize { + self.info().comp_offset(component as u8) + } + + pub fn comp_poffset(&self, component: u32) -> u32 { + self.info().comp_poffset(component as u8) + } + + pub fn comp_pstride(&self, component: u32) -> i32 { + self.info().comp_pstride(component as u8) + } + + pub fn comp_stride(&self, component: u32) -> i32 { + self.info().comp_stride(component as u8) + } + + pub fn comp_plane(&self, component: u32) -> u32 { + self.info().comp_plane(component as u8) + } + pub fn buffer(&self) -> &gst::BufferRef { unsafe { gst::BufferRef::from_ptr(self.frame.buffer) } } @@ -364,6 +411,11 @@ impl VideoFrame { unsafe { gst::BufferRef::from_mut_ptr(self.frame.buffer) } } + pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> { + let poffset = self.info().comp_poffset(component as u8) as usize; + Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..]) + } + pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> { if plane >= self.n_planes() { return Err(glib::bool_error!( @@ -510,6 +562,16 @@ impl VideoFrameRef { self.flags().contains(crate::VideoFrameFlags::ONEFIELD) } + pub fn is_bottom_field(&self) -> bool { + self.flags().contains(crate::VideoFrameFlags::ONEFIELD) + && !self.flags().contains(crate::VideoFrameFlags::TFF) + } + + pub fn is_top_field(&self) -> bool { + self.flags().contains(crate::VideoFrameFlags::ONEFIELD) + && self.flags().contains(crate::VideoFrameFlags::TFF) + } + pub fn n_planes(&self) -> u32 { self.info().n_planes() } @@ -526,6 +588,43 @@ impl VideoFrameRef { self.info().offset() } + pub fn comp_data(&self, component: u32) -> Result<&[u8], glib::BoolError> { + let poffset = self.info().comp_poffset(component as u8) as usize; + Ok(&self.plane_data(self.format_info().plane()[component as usize])?[poffset..]) + } + + pub fn comp_depth(&self, component: u32) -> u32 { + self.info().comp_depth(component as u8) + } + + pub fn comp_height(&self, component: u32) -> u32 { + self.info().comp_height(component as u8) + } + + pub fn comp_width(&self, component: u32) -> u32 { + self.info().comp_width(component as u8) + } + + pub fn comp_offset(&self, component: u32) -> usize { + self.info().comp_offset(component as u8) + } + + pub fn comp_poffset(&self, component: u32) -> u32 { + self.info().comp_poffset(component as u8) + } + + pub fn comp_pstride(&self, component: u32) -> i32 { + self.info().comp_pstride(component as u8) + } + + pub fn comp_stride(&self, component: u32) -> i32 { + self.info().comp_stride(component as u8) + } + + pub fn comp_plane(&self, component: u32) -> u32 { + self.info().comp_plane(component as u8) + } + pub fn plane_data(&self, plane: u32) -> Result<&[u8], glib::BoolError> { if plane >= self.n_planes() { return Err(glib::bool_error!( @@ -764,6 +863,11 @@ impl<'a> VideoFrameRef<&'a mut gst::BufferRef> { self.buffer.as_mut().unwrap() } + pub fn comp_data_mut(&mut self, component: u32) -> Result<&mut [u8], glib::BoolError> { + let poffset = self.info().comp_poffset(component as u8) as usize; + Ok(&mut self.plane_data_mut(self.format_info().plane()[component as usize])?[poffset..]) + } + pub fn plane_data_mut(&mut self, plane: u32) -> Result<&mut [u8], glib::BoolError> { if plane >= self.n_planes() { return Err(glib::bool_error!( diff --git a/gstreamer-video/src/video_info.rs b/gstreamer-video/src/video_info.rs index ba16adab2..23e53c57b 100644 --- a/gstreamer-video/src/video_info.rs +++ b/gstreamer-video/src/video_info.rs @@ -630,11 +630,15 @@ impl VideoInfo { return crate::VideoFormat::Unknown; } - unsafe { from_glib((*self.0.finfo).format) } + self.format_info().format() } pub fn format_info(&self) -> crate::VideoFormatInfo { - crate::VideoFormatInfo::from_format(self.format()) + unsafe { crate::VideoFormatInfo::from_ptr(self.0.finfo) } + } + + pub fn name<'a>(&self) -> &'a str { + self.format_info().name() } pub fn width(&self) -> u32 { @@ -679,6 +683,39 @@ impl VideoInfo { unsafe { VideoColorimetry(ptr::read(&self.0.colorimetry)) } } + pub fn comp_depth(&self, component: u8) -> u32 { + self.format_info().depth()[component as usize] + } + + pub fn comp_height(&self, component: u8) -> u32 { + self.format_info().scale_height(component, self.height()) + } + + pub fn comp_width(&self, component: u8) -> u32 { + self.format_info().scale_width(component, self.width()) + } + + pub fn comp_offset(&self, component: u8) -> usize { + self.offset()[self.format_info().plane()[component as usize] as usize] + + self.format_info().poffset()[component as usize] as usize + } + + pub fn comp_plane(&self, component: u8) -> u32 { + self.format_info().plane()[component as usize] + } + + pub fn comp_poffset(&self, component: u8) -> u32 { + self.format_info().poffset()[component as usize] + } + + pub fn comp_pstride(&self, component: u8) -> i32 { + self.format_info().pixel_stride()[component as usize] + } + + pub fn comp_stride(&self, component: u8) -> i32 { + self.stride()[self.format_info().plane()[component as usize] as usize] + } + pub fn par(&self) -> gst::Fraction { gst::Fraction::new(self.0.par_n, self.0.par_d) } @@ -687,6 +724,16 @@ impl VideoInfo { gst::Fraction::new(self.0.fps_n, self.0.fps_d) } + #[cfg(any(feature = "v1_16", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))] + pub fn field_rate(&self) -> gst::Fraction { + if self.interlace_mode() == crate::VideoInterlaceMode::Alternate { + 2 * self.fps() + } else { + self.fps() + } + } + pub fn offset(&self) -> &[usize] { &self.0.offset[0..(self.format_info().n_planes() as usize)] }