Allow connecting to either an NDI name or URL/address again

Apparently the SDK allows both but the documentation was a bit
confusing.
This commit is contained in:
Sebastian Dröge 2020-01-16 12:18:57 +02:00
parent 8d2c025e47
commit 4d620cd737
4 changed files with 46 additions and 23 deletions

View file

@ -182,7 +182,8 @@ impl<'a> PartialEq for Source<'a> {
#[derive(Debug)]
pub struct RecvBuilder<'a> {
source_to_connect_to: (&'a str, Option<&'a str>),
ndi_name: Option<&'a str>,
url_address: Option<&'a str>,
allow_video_fields: bool,
bandwidth: NDIlib_recv_bandwidth_e,
color_format: NDIlib_recv_color_format_e,
@ -211,15 +212,20 @@ impl<'a> RecvBuilder<'a> {
pub fn build(self) -> Option<RecvInstance> {
unsafe {
let ndi_recv_name = ffi::CString::new(self.ndi_recv_name).unwrap();
let ndi_name = ffi::CString::new(self.source_to_connect_to.0).unwrap();
let ndi_name = self
.ndi_name
.as_ref()
.map(|s| ffi::CString::new(*s).unwrap());
let url_address = self
.source_to_connect_to
.1
.url_address
.as_ref()
.map(|s| ffi::CString::new(*s).unwrap());
let ptr = NDIlib_recv_create_v3(&NDIlib_recv_create_v3_t {
source_to_connect_to: NDIlib_source_t {
p_ndi_name: ndi_name.as_ptr(),
p_ndi_name: ndi_name
.as_ref()
.map(|s| s.as_ptr())
.unwrap_or_else(|| ptr::null_mut()),
p_url_address: url_address
.as_ref()
.map(|s| s.as_ptr())
@ -258,11 +264,13 @@ unsafe impl Sync for RecvInstanceInner {}
impl RecvInstance {
pub fn builder<'a>(
source_to_connect_to: (&'a str, Option<&'a str>),
ndi_name: Option<&'a str>,
url_address: Option<&'a str>,
ndi_recv_name: &'a str,
) -> RecvBuilder<'a> {
RecvBuilder {
source_to_connect_to,
ndi_name,
url_address,
allow_video_fields: true,
bandwidth: NDIlib_recv_bandwidth_highest,
color_format: NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA,

View file

@ -60,7 +60,7 @@ static PROPERTIES: [subclass::Property; 7] = [
glib::ParamSpec::string(
name,
"URL/Address",
"URL/address and port of the sender, e.g. 127.0.0.1:5961. This is used as an additional filter together with the NDI name.",
"URL/address and port of the sender, e.g. 127.0.0.1:5961",
None,
glib::ParamFlags::READWRITE,
)
@ -401,17 +401,17 @@ impl BaseSrcImpl for NdiAudioSrc {
*self.state.lock().unwrap() = Default::default();
let settings = self.settings.lock().unwrap().clone();
if settings.ndi_name.is_none() {
if settings.ndi_name.is_none() && settings.url_address.is_none() {
return Err(gst_error_msg!(
gst::LibraryError::Settings,
["No IP address or NDI name given"]
["No NDI name or URL/address given"]
));
}
let receiver = connect_ndi(
self.cat,
element,
settings.ndi_name.as_ref().unwrap().as_str(),
settings.ndi_name.as_ref().map(String::as_str),
settings.url_address.as_ref().map(String::as_str),
&settings.receiver_ndi_name,
settings.connect_timeout,

View file

@ -61,7 +61,7 @@ static PROPERTIES: [subclass::Property; 7] = [
glib::ParamSpec::string(
name,
"URL/Address",
"URL/address and port of the sender, e.g. 127.0.0.1:5961. This is used as an additional filter together with the NDI name.",
"URL/address and port of the sender, e.g. 127.0.0.1:5961",
None,
glib::ParamFlags::READWRITE,
)
@ -436,17 +436,17 @@ impl BaseSrcImpl for NdiVideoSrc {
*self.state.lock().unwrap() = Default::default();
let settings = self.settings.lock().unwrap().clone();
if settings.ndi_name.is_none() {
if settings.ndi_name.is_none() && settings.url_address.is_none() {
return Err(gst_error_msg!(
gst::LibraryError::Settings,
["No NDI name given"]
["No NDI name or URL/address given"]
));
}
let receiver = connect_ndi(
self.cat,
element,
settings.ndi_name.as_ref().unwrap().as_str(),
settings.ndi_name.as_ref().map(String::as_str),
settings.url_address.as_ref().map(String::as_str),
&settings.receiver_ndi_name,
settings.connect_timeout,
@ -502,6 +502,8 @@ impl BaseSrcImpl for NdiVideoSrc {
let max = 5 * state.current_latency;
println!("Returning latency min {} max {}", min, max,);
gst_debug!(
self.cat,
obj: element,

View file

@ -17,7 +17,7 @@ use super::*;
pub struct ReceiverInfo {
id: usize,
ndi_name: String,
ndi_name: Option<String>,
url_address: Option<String>,
recv: RecvInstance,
video: Option<Weak<ReceiverInner<VideoReceiver>>>,
@ -521,7 +521,7 @@ impl<T: ReceiverType> Drop for ReceiverInner<T> {
pub fn connect_ndi<T: ReceiverType>(
cat: gst::DebugCategory,
element: &gst_base::BaseSrc,
ndi_name: &str,
ndi_name: Option<&str>,
url_address: Option<&str>,
receiver_ndi_name: &str,
connect_timeout: u32,
@ -534,12 +534,24 @@ where
{
gst_debug!(cat, obj: element, "Starting NDI connection...");
assert!(ndi_name.is_some() || url_address.is_some());
let mut receivers = HASHMAP_RECEIVERS.lock().unwrap();
// Check if we already have a receiver for this very stream
for receiver in receivers.values_mut() {
if receiver.ndi_name == ndi_name
&& receiver.url_address.as_ref().map(String::as_str) == url_address
// If both are provided they both must match, if only one is provided
// then that one has to match and the other one does not matter
if (ndi_name.is_some()
&& url_address.is_some()
&& receiver.ndi_name.as_ref().map(String::as_str) == ndi_name
&& receiver.url_address.as_ref().map(String::as_str) == url_address)
|| (ndi_name.is_some()
&& url_address.is_none()
&& receiver.ndi_name.as_ref().map(String::as_str) == ndi_name)
|| (ndi_name.is_none()
&& url_address.is_some()
&& receiver.url_address.as_ref().map(String::as_str) == url_address)
{
if (receiver.video.is_some() || !T::IS_VIDEO)
&& (receiver.audio.is_some() || T::IS_VIDEO)
@ -548,8 +560,9 @@ where
element,
gst::ResourceError::OpenRead,
[
"Source with ndi-name '{}' already in use for {}",
"Source with NDI name '{:?}' / URL/address '{:?}' already in use for {}",
receiver.ndi_name,
receiver.url_address,
if T::IS_VIDEO { "video" } else { "audio" }
]
);
@ -572,14 +585,14 @@ where
gst_debug!(
cat,
obj: element,
"Connecting to NDI source with ndi-name '{}' and URL/Address {:?}",
"Connecting to NDI source with NDI name '{:?}' and URL/Address {:?}",
ndi_name,
url_address,
);
// FIXME: Ideally we would use NDIlib_recv_color_format_fastest here but that seems to be
// broken with interlaced content currently
let recv = RecvInstance::builder((ndi_name, url_address), &receiver_ndi_name)
let recv = RecvInstance::builder(ndi_name, url_address, &receiver_ndi_name)
.bandwidth(bandwidth)
.color_format(NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA)
.allow_video_fields(true)
@ -604,7 +617,7 @@ where
let id_receiver = ID_RECEIVER.fetch_add(1, Ordering::SeqCst);
let mut info = ReceiverInfo {
id: id_receiver,
ndi_name: String::from(ndi_name),
ndi_name: ndi_name.map(String::from),
url_address: url_address.map(String::from),
recv,
video: None,