From afc301de3a1bd575ee8602844a53fb9719170564 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 2 Jan 2020 14:00:47 +0200 Subject: [PATCH] Port to NDI SDK v4 Most notably this allows the video line stride to be set to 0, in which case a default value is to be used, and it deprecates selecting NDI sources by their IP address and because of that we remove the relevant properties. Usually the SDK will give an URL instead of an IP address now, so usage would've been broken anyway. --- README.md | 2 +- src/ndi.rs | 65 +++++++++++++++++++++---------- src/ndiaudiosrc.rs | 38 +++--------------- src/ndisys.rs | 37 +++++++++--------- src/ndivideosrc.rs | 38 +++--------------- src/receiver.rs | 96 +++++++++++++++++++++------------------------- 6 files changed, 119 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index 9344ffab9..5704660ea 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ GStreamer NDI Plugin for Linux ==================== -*Compiled and tested with Ubuntu 16.04.5, GStreamer 1.12 and NDI SDK 3.5.1* +*Compiled and tested with NDI SDK 3.5, 3.8, 4.0 and 4.1* This is a plugin for the [GStreamer](https://gstreamer.freedesktop.org/) multimedia framework that allows GStreamer to receive a stream from a [NDI](https://www.newtek.com/ndi/) source. This plugin has been developed by [Teltek](http://teltek.es/) and was funded by the [University of the Arts London](https://www.arts.ac.uk/) and [The University of Manchester](https://www.manchester.ac.uk/). diff --git a/src/ndi.rs b/src/ndi.rs index 6f04ad452..f17170b88 100644 --- a/src/ndi.rs +++ b/src/ndi.rs @@ -1,3 +1,4 @@ +use crate::ndisys; use crate::ndisys::*; use std::ffi; use std::mem; @@ -135,15 +136,15 @@ impl<'a> Source<'a> { } } - pub fn ip_address(&self) -> &str { + pub fn url_address(&self) -> &str { unsafe { let ptr = match *self { Source::Borrowed(ptr, _) => &*ptr.as_ptr(), Source::Owned(ref source, _, _) => source, }; - assert!(!ptr.p_ip_address.is_null()); - ffi::CStr::from_ptr(ptr.p_ip_address).to_str().unwrap() + assert!(!ptr.p_url_address.is_null()); + ffi::CStr::from_ptr(ptr.p_url_address).to_str().unwrap() } } @@ -156,34 +157,35 @@ impl<'a> Source<'a> { } } - fn ip_address_ptr(&self) -> *const ::std::os::raw::c_char { + fn url_address_ptr(&self) -> *const ::std::os::raw::c_char { unsafe { match *self { - Source::Borrowed(ptr, _) => ptr.as_ref().p_ip_address, - Source::Owned(_, _, ref ip_address) => ip_address.as_ptr(), + Source::Borrowed(ptr, _) => ptr.as_ref().p_url_address, + Source::Owned(_, _, ref url_address) => url_address.as_ptr(), } } } pub fn to_owned<'b>(&self) -> Source<'b> { unsafe { - let (ndi_name, ip_address) = match *self { - Source::Borrowed(ptr, _) => (ptr.as_ref().p_ndi_name, ptr.as_ref().p_ip_address), - Source::Owned(_, ref ndi_name, ref ip_address) => { - (ndi_name.as_ptr(), ip_address.as_ptr()) + let (ndi_name, url_address) = match *self { + Source::Borrowed(ptr, _) => (ptr.as_ref().p_ndi_name, ptr.as_ref().p_url_address), + Source::Owned(_, ref ndi_name, ref url_address) => { + (ndi_name.as_ptr(), url_address.as_ptr()) } }; let ndi_name = ffi::CString::new(ffi::CStr::from_ptr(ndi_name).to_bytes()).unwrap(); - let ip_address = ffi::CString::new(ffi::CStr::from_ptr(ip_address).to_bytes()).unwrap(); + let url_address = + ffi::CString::new(ffi::CStr::from_ptr(url_address).to_bytes()).unwrap(); Source::Owned( NDIlib_source_t { p_ndi_name: ndi_name.as_ptr(), - p_ip_address: ip_address.as_ptr(), + p_url_address: url_address.as_ptr(), }, ndi_name, - ip_address, + url_address, ) } } @@ -223,12 +225,12 @@ impl<'a> RecvBuilder<'a> { let ptr = NDIlib_recv_create_v3(&NDIlib_recv_create_v3_t { source_to_connect_to: NDIlib_source_t { p_ndi_name: self.source_to_connect_to.ndi_name_ptr(), - p_ip_address: self.source_to_connect_to.ip_address_ptr(), + p_url_address: self.source_to_connect_to.url_address_ptr(), }, allow_video_fields: self.allow_video_fields, bandwidth: self.bandwidth, color_format: self.color_format, - p_ndi_name: ndi_name.as_ptr(), + p_ndi_recv_name: ndi_name.as_ptr(), }); if ptr.is_null() { @@ -410,7 +412,7 @@ impl<'a> VideoFrame<'a> { } } - pub fn fourcc(&self) -> NDIlib_FourCC_type_e { + pub fn fourcc(&self) -> NDIlib_FourCC_video_type_e { match self { VideoFrame::Borrowed(ref frame, _) => frame.FourCC, } @@ -448,9 +450,9 @@ impl<'a> VideoFrame<'a> { || self.frame_format_type() == NDIlib_frame_format_type_e::NDIlib_frame_format_type_field_1 { - self.yres() * self.line_stride_in_bytes() / 2 + self.yres() * self.line_stride_or_data_size_in_bytes() / 2 } else { - self.yres() * self.line_stride_in_bytes() + self.yres() * self.line_stride_or_data_size_in_bytes() }; unsafe { @@ -463,9 +465,32 @@ impl<'a> VideoFrame<'a> { } } - pub fn line_stride_in_bytes(&self) -> i32 { + pub fn line_stride_or_data_size_in_bytes(&self) -> i32 { match self { - VideoFrame::Borrowed(ref frame, _) => frame.line_stride_in_bytes, + VideoFrame::Borrowed(ref frame, _) => { + let stride = frame.line_stride_or_data_size_in_bytes; + + if stride != 0 { + return stride; + } + + let xres = frame.xres; + + match frame.FourCC { + ndisys::NDIlib_FourCC_video_type_UYVY + | ndisys::NDIlib_FourCC_video_type_UYVA + | ndisys::NDIlib_FourCC_video_type_YV12 + | ndisys::NDIlib_FourCC_video_type_NV12 + | ndisys::NDIlib_FourCC_video_type_I420 + | ndisys::NDIlib_FourCC_video_type_BGRA + | ndisys::NDIlib_FourCC_video_type_BGRX + | ndisys::NDIlib_FourCC_video_type_RGBA + | ndisys::NDIlib_FourCC_video_type_RGBX => xres, + ndisys::NDIlib_FourCC_video_type_P216 + | ndisys::NDIlib_FourCC_video_type_PA16 => 2 * xres, + _ => 0, + } + } } } diff --git a/src/ndiaudiosrc.rs b/src/ndiaudiosrc.rs index 2d06bb34f..47a41fdc7 100644 --- a/src/ndiaudiosrc.rs +++ b/src/ndiaudiosrc.rs @@ -24,7 +24,6 @@ use crate::DEFAULT_RECEIVER_NDI_NAME; #[derive(Debug, Clone)] struct Settings { ndi_name: Option, - ip_address: Option, connect_timeout: u32, timeout: u32, receiver_ndi_name: String, @@ -36,7 +35,6 @@ impl Default for Settings { fn default() -> Self { Settings { ndi_name: None, - ip_address: None, receiver_ndi_name: DEFAULT_RECEIVER_NDI_NAME.clone(), connect_timeout: 10000, timeout: 5000, @@ -46,7 +44,7 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 7] = [ +static PROPERTIES: [subclass::Property; 6] = [ subclass::Property("ndi-name", |name| { glib::ParamSpec::string( name, @@ -56,15 +54,6 @@ static PROPERTIES: [subclass::Property; 7] = [ glib::ParamFlags::READWRITE, ) }), - subclass::Property("ip-address", |name| { - glib::ParamSpec::string( - name, - "IP Address", - "IP address and port of the sender, e.g. 127.0.0.1:5961", - None, - glib::ParamFlags::READWRITE, - ) - }), subclass::Property("receiver-ndi-name", |name| { glib::ParamSpec::string( name, @@ -227,18 +216,6 @@ impl ObjectImpl for NdiAudioSrc { ); settings.ndi_name = ndi_name; } - subclass::Property("ip-address", ..) => { - let mut settings = self.settings.lock().unwrap(); - let ip_address = value.get().unwrap(); - gst_debug!( - self.cat, - obj: basesrc, - "Changing ip from {:?} to {:?}", - settings.ip_address, - ip_address, - ); - settings.ip_address = ip_address; - } subclass::Property("receiver-ndi-name", ..) => { let mut settings = self.settings.lock().unwrap(); let receiver_ndi_name = value.get().unwrap(); @@ -316,10 +293,6 @@ impl ObjectImpl for NdiAudioSrc { let settings = self.settings.lock().unwrap(); Ok(settings.ndi_name.to_value()) } - subclass::Property("ip-address", ..) => { - let settings = self.settings.lock().unwrap(); - Ok(settings.ip_address.to_value()) - } subclass::Property("receiver-ndi-name", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.receiver_ndi_name.to_value()) @@ -401,18 +374,19 @@ impl BaseSrcImpl for NdiAudioSrc { *self.state.lock().unwrap() = Default::default(); let settings = self.settings.lock().unwrap().clone(); - if settings.ip_address.is_none() && settings.ndi_name.is_none() { + let ndi_name = if let Some(ref ndi_name) = settings.ndi_name { + ndi_name + } else { return Err(gst_error_msg!( gst::LibraryError::Settings, ["No IP address or NDI name given"] )); - } + }; let receiver = connect_ndi( self.cat, element, - settings.ip_address.as_ref().map(String::as_str), - settings.ndi_name.as_ref().map(String::as_str), + ndi_name, &settings.receiver_ndi_name, settings.connect_timeout, settings.bandwidth, diff --git a/src/ndisys.rs b/src/ndisys.rs index 90bff4952..ddadd43dc 100644 --- a/src/ndisys.rs +++ b/src/ndisys.rs @@ -78,7 +78,7 @@ pub struct NDIlib_find_create_t { #[derive(Debug, Copy, Clone)] pub struct NDIlib_source_t { pub p_ndi_name: *const ::std::os::raw::c_char, - pub p_ip_address: *const ::std::os::raw::c_char, + pub p_url_address: *const ::std::os::raw::c_char, } #[repr(i32)] @@ -107,21 +107,21 @@ pub enum NDIlib_recv_color_format_e { NDIlib_recv_color_format_RGBX_RGBA = 2, NDIlib_recv_color_format_UYVY_RGBA = 3, NDIlib_recv_color_format_fastest = 100, + NDIlib_recv_color_format_best = 101, } -#[repr(u32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum NDIlib_FourCC_type_e { - 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, -} +pub type NDIlib_FourCC_video_type_e = u32; +pub const NDIlib_FourCC_video_type_UYVY: NDIlib_FourCC_video_type_e = 0x59_56_59_55; +pub const NDIlib_FourCC_video_type_UYVA: NDIlib_FourCC_video_type_e = 0x41_56_56_55; +pub const NDIlib_FourCC_video_type_P216: NDIlib_FourCC_video_type_e = 0x36_31_32_50; +pub const NDIlib_FourCC_video_type_PA16: NDIlib_FourCC_video_type_e = 0x36_31_41_50; +pub const NDIlib_FourCC_video_type_YV12: NDIlib_FourCC_video_type_e = 0x32_31_56_59; +pub const NDIlib_FourCC_video_type_I420: NDIlib_FourCC_video_type_e = 0x30_32_34_49; +pub const NDIlib_FourCC_video_type_NV12: NDIlib_FourCC_video_type_e = 0x32_31_56_4e; +pub const NDIlib_FourCC_video_type_BGRA: NDIlib_FourCC_video_type_e = 0x41_52_47_42; +pub const NDIlib_FourCC_video_type_BGRX: NDIlib_FourCC_video_type_e = 0x58_52_47_42; +pub const NDIlib_FourCC_video_type_RGBA: NDIlib_FourCC_video_type_e = 0x41_42_47_52; +pub const NDIlib_FourCC_video_type_RGBX: NDIlib_FourCC_video_type_e = 0x58_42_47_52; #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -133,7 +133,6 @@ pub enum NDIlib_frame_format_type_e { } pub const NDIlib_send_timecode_synthesize: i64 = ::std::i64::MAX; -pub const NDIlib_send_timecode_empty: i64 = 0; pub const NDIlib_recv_timestamp_undefined: i64 = ::std::i64::MAX; #[repr(C)] @@ -143,7 +142,7 @@ pub struct NDIlib_recv_create_v3_t { pub color_format: NDIlib_recv_color_format_e, pub bandwidth: NDIlib_recv_bandwidth_e, pub allow_video_fields: bool, - pub p_ndi_name: *const ::std::os::raw::c_char, + pub p_ndi_recv_name: *const ::std::os::raw::c_char, } pub type NDIlib_recv_instance_t = *mut ::std::os::raw::c_void; @@ -176,14 +175,14 @@ pub struct NDIlib_metadata_frame_t { pub struct NDIlib_video_frame_v2_t { pub xres: ::std::os::raw::c_int, pub yres: ::std::os::raw::c_int, - pub FourCC: NDIlib_FourCC_type_e, + pub FourCC: NDIlib_FourCC_video_type_e, pub frame_rate_N: ::std::os::raw::c_int, pub frame_rate_D: ::std::os::raw::c_int, pub picture_aspect_ratio: ::std::os::raw::c_float, pub frame_format_type: NDIlib_frame_format_type_e, pub timecode: i64, pub p_data: *const ::std::os::raw::c_char, - pub line_stride_in_bytes: ::std::os::raw::c_int, + pub line_stride_or_data_size_in_bytes: ::std::os::raw::c_int, pub p_metadata: *const ::std::os::raw::c_char, pub timestamp: i64, } @@ -221,5 +220,5 @@ pub struct NDIlib_audio_frame_interleaved_16s_t { pub no_samples: ::std::os::raw::c_int, pub timecode: i64, pub reference_level: ::std::os::raw::c_int, - pub p_data: *mut ::std::os::raw::c_short, + pub p_data: *mut i16, } diff --git a/src/ndivideosrc.rs b/src/ndivideosrc.rs index 790385bc8..359ede6f3 100644 --- a/src/ndivideosrc.rs +++ b/src/ndivideosrc.rs @@ -25,7 +25,6 @@ use crate::DEFAULT_RECEIVER_NDI_NAME; #[derive(Debug, Clone)] struct Settings { ndi_name: Option, - ip_address: Option, connect_timeout: u32, timeout: u32, receiver_ndi_name: String, @@ -37,7 +36,6 @@ impl Default for Settings { fn default() -> Self { Settings { ndi_name: None, - ip_address: None, receiver_ndi_name: DEFAULT_RECEIVER_NDI_NAME.clone(), connect_timeout: 10000, timeout: 5000, @@ -47,7 +45,7 @@ impl Default for Settings { } } -static PROPERTIES: [subclass::Property; 7] = [ +static PROPERTIES: [subclass::Property; 6] = [ subclass::Property("ndi-name", |name| { glib::ParamSpec::string( name, @@ -57,15 +55,6 @@ static PROPERTIES: [subclass::Property; 7] = [ glib::ParamFlags::READWRITE, ) }), - subclass::Property("ip-address", |name| { - glib::ParamSpec::string( - name, - "IP Address", - "IP address and port of the sender, e.g. 127.0.0.1:5961", - None, - glib::ParamFlags::READWRITE, - ) - }), subclass::Property("receiver-ndi-name", |name| { glib::ParamSpec::string( name, @@ -262,18 +251,6 @@ impl ObjectImpl for NdiVideoSrc { ); settings.ndi_name = ndi_name; } - subclass::Property("ip-address", ..) => { - let mut settings = self.settings.lock().unwrap(); - let ip_address = value.get().unwrap(); - gst_debug!( - self.cat, - obj: basesrc, - "Changing ip from {:?} to {:?}", - settings.ip_address, - ip_address, - ); - settings.ip_address = ip_address; - } subclass::Property("receiver-ndi-name", ..) => { let mut settings = self.settings.lock().unwrap(); let receiver_ndi_name = value.get().unwrap(); @@ -351,10 +328,6 @@ impl ObjectImpl for NdiVideoSrc { let settings = self.settings.lock().unwrap(); Ok(settings.ndi_name.to_value()) } - subclass::Property("ip-address", ..) => { - let settings = self.settings.lock().unwrap(); - Ok(settings.ip_address.to_value()) - } subclass::Property("receiver-ndi-name", ..) => { let settings = self.settings.lock().unwrap(); Ok(settings.receiver_ndi_name.to_value()) @@ -436,18 +409,19 @@ impl BaseSrcImpl for NdiVideoSrc { *self.state.lock().unwrap() = Default::default(); let settings = self.settings.lock().unwrap().clone(); - if settings.ip_address.is_none() && settings.ndi_name.is_none() { + let ndi_name = if let Some(ref ndi_name) = settings.ndi_name { + ndi_name + } else { return Err(gst_error_msg!( gst::LibraryError::Settings, ["No IP address or NDI name given"] )); - } + }; let receiver = connect_ndi( self.cat, element, - settings.ip_address.as_ref().map(String::as_str), - settings.ndi_name.as_ref().map(String::as_str), + ndi_name, &settings.receiver_ndi_name, settings.connect_timeout, settings.bandwidth, diff --git a/src/receiver.rs b/src/receiver.rs index 7b9b0a5c9..3b8dab30e 100644 --- a/src/receiver.rs +++ b/src/receiver.rs @@ -18,8 +18,7 @@ use super::*; enum ReceiverInfo { Connecting { id: usize, - ndi_name: Option, - ip_address: Option, + ndi_name: String, video: Option>>, audio: Option>>, observations: Observations, @@ -27,7 +26,6 @@ enum ReceiverInfo { Connected { id: usize, ndi_name: String, - ip_address: String, recv: RecvInstance, video: Option>>, audio: Option>>, @@ -557,8 +555,7 @@ impl Drop for ReceiverInner { pub fn connect_ndi( cat: gst::DebugCategory, element: &gst_base::BaseSrc, - ip_address: Option<&str>, - ndi_name: Option<&str>, + ndi_name: &str, receiver_ndi_name: &str, connect_timeout: u32, bandwidth: NDIlib_recv_bandwidth_e, @@ -570,45 +567,33 @@ where { gst_debug!(cat, obj: element, "Starting NDI connection..."); - let ip_address = ip_address.map(str::to_lowercase); - let mut receivers = HASHMAP_RECEIVERS.lock().unwrap(); // Check if we already have a receiver for this very stream for val in receivers.values_mut() { - let (val_audio, val_video, val_ip_address, val_ndi_name) = match val { + let (val_audio, val_video, val_ndi_name) = match val { ReceiverInfo::Connecting { ref mut audio, ref mut video, - ref ip_address, ref ndi_name, .. - } => ( - audio, - video, - ip_address.as_ref(), - ndi_name.as_ref().map(String::as_ref), - ), + } => (audio, video, ndi_name.as_str()), ReceiverInfo::Connected { ref mut audio, ref mut video, - ref ip_address, ref ndi_name, .. - } => (audio, video, Some(ip_address), Some(ndi_name.as_str())), + } => (audio, video, ndi_name.as_str()), }; - if (val_ip_address.is_some() && val_ip_address == ip_address.as_ref()) - || (val_ip_address.is_none() && val_ndi_name == ndi_name) - { + if val_ndi_name == ndi_name { if (val_video.is_some() || !T::IS_VIDEO) && (val_audio.is_some() || T::IS_VIDEO) { gst_element_error!( element, gst::ResourceError::OpenRead, [ - "Source with ndi-name '{:?}' and ip-address '{:?}' already in use for {}", + "Source with ndi-name '{}' already in use for {}", val_ndi_name, - val_ip_address, if T::IS_VIDEO { "video" } else { "audio" } ] ); @@ -624,8 +609,7 @@ where let id_receiver = ID_RECEIVER.fetch_add(1, Ordering::SeqCst); let mut info = ReceiverInfo::Connecting { id: id_receiver, - ndi_name: ndi_name.map(String::from), - ip_address, + ndi_name: String::from(ndi_name), video: None, audio: None, observations: Observations::new(), @@ -746,9 +730,9 @@ fn connect_ndi_async( gst_debug!( cat, obj: element, - "Found source '{}' with IP {}", + "Found source '{}' with URL {}", source.ndi_name(), - source.ip_address(), + source.url_address(), ); } @@ -758,24 +742,20 @@ fn connect_ndi_async( Some(val) => val, }; - let (ndi_name, ip_address) = match info { + let ndi_name = match info { ReceiverInfo::Connecting { ref ndi_name, - ref ip_address, ref audio, ref video, .. } => { assert!(audio.is_some() || video.is_some()); - (ndi_name, ip_address) + ndi_name } ReceiverInfo::Connected { .. } => unreachable!(), }; - let source = sources.iter().find(|s| { - Some(s.ndi_name()) == ndi_name.as_ref().map(String::as_str) - || Some(&s.ip_address().to_lowercase()) == ip_address.as_ref() - }); + let source = sources.iter().find(|s| s.ndi_name() == ndi_name.as_str()); if let Some(source) = source { break source.to_owned(); @@ -793,9 +773,9 @@ fn connect_ndi_async( gst_debug!( cat, obj: element, - "Connecting to NDI source with ndi-name '{}' and ip-address '{}'", + "Connecting to NDI source with ndi-name '{}' and URL {}", source.ndi_name(), - source.ip_address(), + source.url_address(), ); // FIXME: Ideally we would use NDIlib_recv_color_format_fastest here but that seems to be @@ -841,7 +821,6 @@ fn connect_ndi_async( *info = ReceiverInfo::Connected { id: id_receiver, ndi_name: source.ndi_name().to_owned(), - ip_address: source.ip_address().to_lowercase(), recv: recv.clone(), video: video.clone(), audio: audio.clone(), @@ -1252,15 +1231,26 @@ impl Receiver { ) -> Result { // 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, + ndisys::NDIlib_FourCC_video_type_UYVY => gst_video::VideoFormat::Uyvy, + // FIXME: This drops the alpha plane! + ndisys::NDIlib_FourCC_video_type_UYVA => gst_video::VideoFormat::Uyvy, + ndisys::NDIlib_FourCC_video_type_YV12 => gst_video::VideoFormat::I420, + ndisys::NDIlib_FourCC_video_type_NV12 => gst_video::VideoFormat::Nv12, + ndisys::NDIlib_FourCC_video_type_I420 => gst_video::VideoFormat::Yv12, + ndisys::NDIlib_FourCC_video_type_BGRA => gst_video::VideoFormat::Bgra, + ndisys::NDIlib_FourCC_video_type_BGRX => gst_video::VideoFormat::Bgrx, + ndisys::NDIlib_FourCC_video_type_RGBA => gst_video::VideoFormat::Rgba, + ndisys::NDIlib_FourCC_video_type_RGBX => gst_video::VideoFormat::Rgbx, + _ => { + gst_element_error!( + element, + gst::StreamError::Format, + ["Unsupported video fourcc {:08x}", video_frame.fourcc()] + ); + + return Err(gst::FlowError::NotNegotiated); + } // TODO: NDIlib_FourCC_video_type_P216 and NDIlib_FourCC_video_type_PA16 not + // supported by GStreamer }; let par = gst::Fraction::approximate_f32(video_frame.picture_aspect_ratio()) @@ -1447,7 +1437,7 @@ impl Receiver { }; 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_stride = video_frame.line_stride_or_data_size_in_bytes() as usize; let src = video_frame.data(); for (dest, src) in dest @@ -1464,7 +1454,7 @@ impl Receiver { 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_stride = video_frame.line_stride_or_data_size_in_bytes() as usize; let src = video_frame.data(); for (dest, src) in dest @@ -1480,7 +1470,7 @@ impl Receiver { 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_stride = video_frame.line_stride_or_data_size_in_bytes() as usize; let src = &video_frame.data()[(video_frame.yres() as usize * src_stride)..]; for (dest, src) in dest @@ -1497,7 +1487,7 @@ impl Receiver { 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_stride = video_frame.line_stride_or_data_size_in_bytes() as usize; let src = video_frame.data(); for (dest, src) in dest @@ -1513,8 +1503,8 @@ impl Receiver { 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_stride = video_frame.line_stride_or_data_size_in_bytes() as usize; + let src_stride1 = video_frame.line_stride_or_data_size_in_bytes() as usize / 2; let src = &video_frame.data()[(video_frame.yres() as usize * src_stride)..]; for (dest, src) in dest @@ -1530,8 +1520,8 @@ impl Receiver { 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_stride = video_frame.line_stride_or_data_size_in_bytes() as usize; + let src_stride1 = video_frame.line_stride_or_data_size_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)..];