Add support for all other video formats

This commit is contained in:
Sebastian Dröge 2019-07-15 19:27:00 +03:00
parent 5022ff412c
commit 75eb959c80
2 changed files with 132 additions and 13 deletions

View file

@ -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)]

View file

@ -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::<i32>::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)