From 75eb959c80a6c4c1618c4ac9ee1ce8b68a11d0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 15 Jul 2019 19:27:00 +0300 Subject: [PATCH] Add support for all other video formats --- src/ndisys.rs | 15 +++--- src/ndivideosrc.rs | 130 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 13 deletions(-) diff --git a/src/ndisys.rs b/src/ndisys.rs index 25c9adde..9958c202 100644 --- a/src/ndisys.rs +++ b/src/ndisys.rs @@ -101,12 +101,15 @@ pub enum NDIlib_recv_color_format_e { #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum NDIlib_FourCC_type_e { - NDIlib_FourCC_type_UYVY = 1_498_831_189, - NDIlib_FourCC_type_BGRA = 1_095_911_234, - NDIlib_FourCC_type_BGRX = 1_481_787_202, - NDIlib_FourCC_type_RGBA = 1_094_862_674, - NDIlib_FourCC_type_RGBX = 1_480_738_642, - NDIlib_FourCC_type_UYVA = 1_096_178_005, + NDIlib_FourCC_type_UYVY = 0x59_56_59_55, + NDIlib_FourCC_type_YV12 = 0x32_31_56_59, + NDIlib_FourCC_type_NV12 = 0x32_31_56_4e, + NDIlib_FourCC_type_I420 = 0x30_32_34_49, + NDIlib_FourCC_type_BGRA = 0x41_52_47_42, + NDIlib_FourCC_type_BGRX = 0x58_52_47_42, + NDIlib_FourCC_type_RGBA = 0x41_42_47_52, + NDIlib_FourCC_type_RGBX = 0x58_42_47_52, + NDIlib_FourCC_type_UYVA = 0x41_56_56_55, } #[repr(u32)] diff --git a/src/ndivideosrc.rs b/src/ndivideosrc.rs index 2e2c22ce..f0e5ceb7 100644 --- a/src/ndivideosrc.rs +++ b/src/ndivideosrc.rs @@ -126,10 +126,14 @@ impl ObjectSubclass for NdiVideoSrc { ( "format", &gst::List::new(&[ - //TODO add all formats &gst_video::VideoFormat::Uyvy.to_string(), - //&gst_video::VideoFormat::Rgb.to_string(), - //&gst_video::VideoFormat::Gray8.to_string(), + &gst_video::VideoFormat::Yv12.to_string(), + &gst_video::VideoFormat::Nv12.to_string(), + &gst_video::VideoFormat::I420.to_string(), + &gst_video::VideoFormat::Bgra.to_string(), + &gst_video::VideoFormat::Bgrx.to_string(), + &gst_video::VideoFormat::Rgba.to_string(), + &gst_video::VideoFormat::Rgbx.to_string(), ]), ), ("width", &gst::IntRange::::new(0, i32::MAX)), @@ -375,11 +379,24 @@ impl BaseSrcImpl for NdiVideoSrc { video_frame ); + // YV12 and I420 are swapped in the NDI SDK compared to GStreamer + let format = match video_frame.fourcc() { + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_UYVY => gst_video::VideoFormat::Uyvy, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_YV12 => gst_video::VideoFormat::I420, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_NV12 => gst_video::VideoFormat::Nv12, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_I420 => gst_video::VideoFormat::Yv12, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_BGRA => gst_video::VideoFormat::Bgra, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_BGRX => gst_video::VideoFormat::Bgrx, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_RGBA => gst_video::VideoFormat::Rgba, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_RGBX => gst_video::VideoFormat::Rgbx, + ndisys::NDIlib_FourCC_type_e::NDIlib_FourCC_type_UYVA => gst_video::VideoFormat::Uyvy, + }; + let par = gst::Fraction::approximate_f32(video_frame.picture_aspect_ratio()).unwrap() * gst::Fraction::new(video_frame.yres(), video_frame.xres()); let info = gst_video::VideoInfo::new( - gst_video::VideoFormat::Uyvy, + format, video_frame.xres() as u32, video_frame.yres() as u32, ) @@ -415,11 +432,110 @@ impl BaseSrcImpl for NdiVideoSrc { let buffer = buffer.get_mut().unwrap(); buffer.set_pts(pts); buffer.set_duration(duration); - - // FIXME: This assumes that the strides match up - buffer.copy_from_slice(0, video_frame.data()).unwrap(); } + let buffer = { + let mut vframe = gst_video::VideoFrame::from_buffer_writable(buffer, &state.info.as_ref().unwrap()).unwrap(); + + match format { + gst_video::VideoFormat::Uyvy | + gst_video::VideoFormat::Bgra | + gst_video::VideoFormat::Bgrx | + gst_video::VideoFormat::Rgba | + gst_video::VideoFormat::Rgbx => { + let line_bytes = if format == gst_video::VideoFormat::Uyvy { + 2 * vframe.width() as usize + } else { + 4 * vframe.width() as usize + }; + let dest_stride = vframe.plane_stride()[0] as usize; + let dest = vframe.plane_data_mut(0).unwrap(); + let src_stride = video_frame.line_stride_in_bytes() as usize; + let src = video_frame.data(); + + for (dest, src) in dest.chunks_exact_mut(dest_stride).zip(src.chunks_exact(src_stride)) { + dest.copy_from_slice(src); + dest.copy_from_slice(&src[..line_bytes]); + } + }, + gst_video::VideoFormat::Nv12 => { + // First plane + { + let line_bytes = vframe.width() as usize; + let dest_stride = vframe.plane_stride()[0] as usize; + let dest = vframe.plane_data_mut(0).unwrap(); + let src_stride = video_frame.line_stride_in_bytes() as usize; + let src = video_frame.data(); + + for (dest, src) in dest.chunks_exact_mut(dest_stride).zip(src.chunks_exact(src_stride)) { + dest.copy_from_slice(&src[..line_bytes]); + } + } + + // Second plane + { + let line_bytes = vframe.width() as usize; + let dest_stride = vframe.plane_stride()[1] as usize; + let dest = vframe.plane_data_mut(1).unwrap(); + let src_stride = video_frame.line_stride_in_bytes() as usize; + let src = &video_frame.data()[(video_frame.yres() as usize * src_stride)..]; + + for (dest, src) in dest.chunks_exact_mut(dest_stride).zip(src.chunks_exact(src_stride)) { + dest.copy_from_slice(&src[..line_bytes]); + } + } + + }, + gst_video::VideoFormat::Yv12 | + gst_video::VideoFormat::I420 => { + // First plane + { + let line_bytes = vframe.width() as usize; + let dest_stride = vframe.plane_stride()[0] as usize; + let dest = vframe.plane_data_mut(0).unwrap(); + let src_stride = video_frame.line_stride_in_bytes() as usize; + let src = video_frame.data(); + + for (dest, src) in dest.chunks_exact_mut(dest_stride).zip(src.chunks_exact(src_stride)) { + dest.copy_from_slice(&src[..line_bytes]); + } + } + + // Second plane + { + let line_bytes = (vframe.width() as usize + 1) / 2; + let dest_stride = vframe.plane_stride()[1] as usize; + let dest = vframe.plane_data_mut(1).unwrap(); + let src_stride = video_frame.line_stride_in_bytes() as usize; + let src_stride1 = video_frame.line_stride_in_bytes() as usize / 2; + let src = &video_frame.data()[(video_frame.yres() as usize * src_stride)..]; + + for (dest, src) in dest.chunks_exact_mut(dest_stride).zip(src.chunks_exact(src_stride1)) { + dest.copy_from_slice(&src[..line_bytes]); + } + } + + // Third plane + { + let line_bytes = (vframe.width() as usize + 1) / 2; + let dest_stride = vframe.plane_stride()[2] as usize; + let dest = vframe.plane_data_mut(2).unwrap(); + let src_stride = video_frame.line_stride_in_bytes() as usize; + let src_stride1 = video_frame.line_stride_in_bytes() as usize / 2; + let src = &video_frame.data()[(video_frame.yres() as usize * src_stride + + (video_frame.yres() as usize + 1) / 2 * src_stride1)..]; + + for (dest, src) in dest.chunks_exact_mut(dest_stride).zip(src.chunks_exact(src_stride1)) { + dest.copy_from_slice(&src[..line_bytes]); + } + } + }, + _ => unreachable!(), + } + + vframe.into_buffer() + }; + gst_log!(self.cat, obj: element, "Produced buffer {:?}", buffer); Ok(buffer)