mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2024-12-03 00:36:30 +00:00
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:
parent
8d2c025e47
commit
4d620cd737
4 changed files with 46 additions and 23 deletions
22
src/ndi.rs
22
src/ndi.rs
|
@ -182,7 +182,8 @@ impl<'a> PartialEq for Source<'a> {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RecvBuilder<'a> {
|
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,
|
allow_video_fields: bool,
|
||||||
bandwidth: NDIlib_recv_bandwidth_e,
|
bandwidth: NDIlib_recv_bandwidth_e,
|
||||||
color_format: NDIlib_recv_color_format_e,
|
color_format: NDIlib_recv_color_format_e,
|
||||||
|
@ -211,15 +212,20 @@ impl<'a> RecvBuilder<'a> {
|
||||||
pub fn build(self) -> Option<RecvInstance> {
|
pub fn build(self) -> Option<RecvInstance> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ndi_recv_name = ffi::CString::new(self.ndi_recv_name).unwrap();
|
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
|
let url_address = self
|
||||||
.source_to_connect_to
|
.url_address
|
||||||
.1
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| ffi::CString::new(*s).unwrap());
|
.map(|s| ffi::CString::new(*s).unwrap());
|
||||||
let ptr = NDIlib_recv_create_v3(&NDIlib_recv_create_v3_t {
|
let ptr = NDIlib_recv_create_v3(&NDIlib_recv_create_v3_t {
|
||||||
source_to_connect_to: NDIlib_source_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
|
p_url_address: url_address
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| s.as_ptr())
|
.map(|s| s.as_ptr())
|
||||||
|
@ -258,11 +264,13 @@ unsafe impl Sync for RecvInstanceInner {}
|
||||||
|
|
||||||
impl RecvInstance {
|
impl RecvInstance {
|
||||||
pub fn builder<'a>(
|
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,
|
ndi_recv_name: &'a str,
|
||||||
) -> RecvBuilder<'a> {
|
) -> RecvBuilder<'a> {
|
||||||
RecvBuilder {
|
RecvBuilder {
|
||||||
source_to_connect_to,
|
ndi_name,
|
||||||
|
url_address,
|
||||||
allow_video_fields: true,
|
allow_video_fields: true,
|
||||||
bandwidth: NDIlib_recv_bandwidth_highest,
|
bandwidth: NDIlib_recv_bandwidth_highest,
|
||||||
color_format: NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA,
|
color_format: NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA,
|
||||||
|
|
|
@ -60,7 +60,7 @@ static PROPERTIES: [subclass::Property; 7] = [
|
||||||
glib::ParamSpec::string(
|
glib::ParamSpec::string(
|
||||||
name,
|
name,
|
||||||
"URL/Address",
|
"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,
|
None,
|
||||||
glib::ParamFlags::READWRITE,
|
glib::ParamFlags::READWRITE,
|
||||||
)
|
)
|
||||||
|
@ -401,17 +401,17 @@ impl BaseSrcImpl for NdiAudioSrc {
|
||||||
*self.state.lock().unwrap() = Default::default();
|
*self.state.lock().unwrap() = Default::default();
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
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!(
|
return Err(gst_error_msg!(
|
||||||
gst::LibraryError::Settings,
|
gst::LibraryError::Settings,
|
||||||
["No IP address or NDI name given"]
|
["No NDI name or URL/address given"]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let receiver = connect_ndi(
|
let receiver = connect_ndi(
|
||||||
self.cat,
|
self.cat,
|
||||||
element,
|
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.url_address.as_ref().map(String::as_str),
|
||||||
&settings.receiver_ndi_name,
|
&settings.receiver_ndi_name,
|
||||||
settings.connect_timeout,
|
settings.connect_timeout,
|
||||||
|
|
|
@ -61,7 +61,7 @@ static PROPERTIES: [subclass::Property; 7] = [
|
||||||
glib::ParamSpec::string(
|
glib::ParamSpec::string(
|
||||||
name,
|
name,
|
||||||
"URL/Address",
|
"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,
|
None,
|
||||||
glib::ParamFlags::READWRITE,
|
glib::ParamFlags::READWRITE,
|
||||||
)
|
)
|
||||||
|
@ -436,17 +436,17 @@ impl BaseSrcImpl for NdiVideoSrc {
|
||||||
*self.state.lock().unwrap() = Default::default();
|
*self.state.lock().unwrap() = Default::default();
|
||||||
let settings = self.settings.lock().unwrap().clone();
|
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!(
|
return Err(gst_error_msg!(
|
||||||
gst::LibraryError::Settings,
|
gst::LibraryError::Settings,
|
||||||
["No NDI name given"]
|
["No NDI name or URL/address given"]
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let receiver = connect_ndi(
|
let receiver = connect_ndi(
|
||||||
self.cat,
|
self.cat,
|
||||||
element,
|
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.url_address.as_ref().map(String::as_str),
|
||||||
&settings.receiver_ndi_name,
|
&settings.receiver_ndi_name,
|
||||||
settings.connect_timeout,
|
settings.connect_timeout,
|
||||||
|
@ -502,6 +502,8 @@ impl BaseSrcImpl for NdiVideoSrc {
|
||||||
|
|
||||||
let max = 5 * state.current_latency;
|
let max = 5 * state.current_latency;
|
||||||
|
|
||||||
|
println!("Returning latency min {} max {}", min, max,);
|
||||||
|
|
||||||
gst_debug!(
|
gst_debug!(
|
||||||
self.cat,
|
self.cat,
|
||||||
obj: element,
|
obj: element,
|
||||||
|
|
|
@ -17,7 +17,7 @@ use super::*;
|
||||||
|
|
||||||
pub struct ReceiverInfo {
|
pub struct ReceiverInfo {
|
||||||
id: usize,
|
id: usize,
|
||||||
ndi_name: String,
|
ndi_name: Option<String>,
|
||||||
url_address: Option<String>,
|
url_address: Option<String>,
|
||||||
recv: RecvInstance,
|
recv: RecvInstance,
|
||||||
video: Option<Weak<ReceiverInner<VideoReceiver>>>,
|
video: Option<Weak<ReceiverInner<VideoReceiver>>>,
|
||||||
|
@ -521,7 +521,7 @@ impl<T: ReceiverType> Drop for ReceiverInner<T> {
|
||||||
pub fn connect_ndi<T: ReceiverType>(
|
pub fn connect_ndi<T: ReceiverType>(
|
||||||
cat: gst::DebugCategory,
|
cat: gst::DebugCategory,
|
||||||
element: &gst_base::BaseSrc,
|
element: &gst_base::BaseSrc,
|
||||||
ndi_name: &str,
|
ndi_name: Option<&str>,
|
||||||
url_address: Option<&str>,
|
url_address: Option<&str>,
|
||||||
receiver_ndi_name: &str,
|
receiver_ndi_name: &str,
|
||||||
connect_timeout: u32,
|
connect_timeout: u32,
|
||||||
|
@ -534,12 +534,24 @@ where
|
||||||
{
|
{
|
||||||
gst_debug!(cat, obj: element, "Starting NDI connection...");
|
gst_debug!(cat, obj: element, "Starting NDI connection...");
|
||||||
|
|
||||||
|
assert!(ndi_name.is_some() || url_address.is_some());
|
||||||
|
|
||||||
let mut receivers = HASHMAP_RECEIVERS.lock().unwrap();
|
let mut receivers = HASHMAP_RECEIVERS.lock().unwrap();
|
||||||
|
|
||||||
// Check if we already have a receiver for this very stream
|
// Check if we already have a receiver for this very stream
|
||||||
for receiver in receivers.values_mut() {
|
for receiver in receivers.values_mut() {
|
||||||
if receiver.ndi_name == ndi_name
|
// If both are provided they both must match, if only one is provided
|
||||||
&& receiver.url_address.as_ref().map(String::as_str) == url_address
|
// 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)
|
if (receiver.video.is_some() || !T::IS_VIDEO)
|
||||||
&& (receiver.audio.is_some() || T::IS_VIDEO)
|
&& (receiver.audio.is_some() || T::IS_VIDEO)
|
||||||
|
@ -548,8 +560,9 @@ where
|
||||||
element,
|
element,
|
||||||
gst::ResourceError::OpenRead,
|
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.ndi_name,
|
||||||
|
receiver.url_address,
|
||||||
if T::IS_VIDEO { "video" } else { "audio" }
|
if T::IS_VIDEO { "video" } else { "audio" }
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -572,14 +585,14 @@ where
|
||||||
gst_debug!(
|
gst_debug!(
|
||||||
cat,
|
cat,
|
||||||
obj: element,
|
obj: element,
|
||||||
"Connecting to NDI source with ndi-name '{}' and URL/Address {:?}",
|
"Connecting to NDI source with NDI name '{:?}' and URL/Address {:?}",
|
||||||
ndi_name,
|
ndi_name,
|
||||||
url_address,
|
url_address,
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: Ideally we would use NDIlib_recv_color_format_fastest here but that seems to be
|
// FIXME: Ideally we would use NDIlib_recv_color_format_fastest here but that seems to be
|
||||||
// broken with interlaced content currently
|
// 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)
|
.bandwidth(bandwidth)
|
||||||
.color_format(NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA)
|
.color_format(NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA)
|
||||||
.allow_video_fields(true)
|
.allow_video_fields(true)
|
||||||
|
@ -604,7 +617,7 @@ where
|
||||||
let id_receiver = ID_RECEIVER.fetch_add(1, Ordering::SeqCst);
|
let id_receiver = ID_RECEIVER.fetch_add(1, Ordering::SeqCst);
|
||||||
let mut info = ReceiverInfo {
|
let mut info = ReceiverInfo {
|
||||||
id: id_receiver,
|
id: id_receiver,
|
||||||
ndi_name: String::from(ndi_name),
|
ndi_name: ndi_name.map(String::from),
|
||||||
url_address: url_address.map(String::from),
|
url_address: url_address.map(String::from),
|
||||||
recv,
|
recv,
|
||||||
video: None,
|
video: None,
|
||||||
|
|
Loading…
Reference in a new issue