diff --git a/gst-plugin-ndi/src/lib.rs b/gst-plugin-ndi/src/lib.rs index f9f68f0c..61853636 100644 --- a/gst-plugin-ndi/src/lib.rs +++ b/gst-plugin-ndi/src/lib.rs @@ -19,6 +19,8 @@ extern crate gstreamer_video as gst_video; extern crate byte_slice_cast; extern crate num_traits; +#[macro_use] +extern crate lazy_static; mod ndivideosrc; mod ndiaudiosrc; @@ -31,6 +33,8 @@ use std::ffi::{CStr, CString}; use ndilib::*; use gst_plugin::base_src::*; +use std::collections::HashMap; +use std::sync::Mutex; // Plugin entry point that should register all elements provided by this plugin, // and everything else that this plugin might provide (e.g. typefinders or device providers). @@ -40,7 +44,6 @@ fn plugin_init(plugin: &gst::Plugin) -> bool { true } - struct Ndi{ recv: Option, start_pts: u64, @@ -51,16 +54,23 @@ static mut ndi_struct: Ndi = Ndi{ start_pts: 0, }; +lazy_static! { + static ref hashmap_receivers: Mutex> = { + let mut m = HashMap::new(); + Mutex::new(m) + }; +} + fn connect_ndi(cat: gst::DebugCategory , element: &BaseSrc, ip: String, stream_name: String) -> bool{ unsafe { gst_debug!(cat, obj: element, "Starting NDI connection..."); - match ndi_struct.recv { - None => { - //gst_element_error!(element, gst::CoreError::Negotiation, ["Have no caps yet"]); - //return true; - } - _ => return true, - }; + + let mut map = hashmap_receivers.lock().unwrap(); + if (map.contains_key(&stream_name) || map.contains_key(&ip)){ + println!("Already connected to {}{}", ip, stream_name); + return false; + } + if !NDIlib_initialize() { gst_element_error!(element, gst::CoreError::Negotiation, ["Cannot run NDI: NDIlib_initialize error"]); return false; @@ -73,7 +83,6 @@ fn connect_ndi(cat: gst::DebugCategory , element: &BaseSrc, ip: String, stream let NDI_find_create_desc: NDIlib_find_create_t = Default::default(); let pNDI_find = NDIlib_find_create_v2(&NDI_find_create_desc); let ip_ptr = CString::new(ip.clone()).unwrap(); - if ip_ptr == CString::new("").unwrap(){ if pNDI_find.is_null() { gst_element_error!(element, gst::CoreError::Negotiation, ["Cannot run NDI: NDIlib_find_create_v2 error"]); return false; @@ -94,9 +103,8 @@ fn connect_ndi(cat: gst::DebugCategory , element: &BaseSrc, ip: String, stream let mut no_source: isize = -1; for i in 0..total_sources as isize{ - if CStr::from_ptr((*p_sources.offset(i)).p_ndi_name) - .to_string_lossy() - .into_owned() == stream_name{ + if (CStr::from_ptr((*p_sources.offset(i)).p_ndi_name).to_string_lossy().into_owned() == stream_name || + CStr::from_ptr((*p_sources.offset(i)).p_ip_address).to_string_lossy().into_owned() == ip){ no_source = i; break; } @@ -115,14 +123,9 @@ fn connect_ndi(cat: gst::DebugCategory , element: &BaseSrc, ip: String, stream .into_owned()); source = *p_sources.offset(no_source).clone(); - } - else{ - source.p_ip_address = ip_ptr.as_ptr(); - gst_debug!(cat, obj: element, "Connecting to NDI source with address '{}'", CStr::from_ptr(source.p_ip_address) - .to_string_lossy() - .into_owned() - ); - } + + let source_ip = CStr::from_ptr(source.p_ip_address).to_string_lossy().into_owned(); + let source_name = CStr::from_ptr(source.p_ndi_name).to_string_lossy().into_owned(); // We now have at least one source, so we create a receiver to look at it. // We tell it that we prefer YCbCr video since it is more efficient for us. If the source has an alpha channel @@ -159,7 +162,9 @@ fn connect_ndi(cat: gst::DebugCategory , element: &BaseSrc, ip: String, stream }; NDIlib_recv_send_metadata(pNDI_recv, &enable_hw_accel); - ndi_struct.recv = Some(NdiInstance{recv: pNDI_recv}); + + map.insert(source_name.clone(), NdiInstance{recv: pNDI_recv}); + map.insert(source_ip.clone(), NdiInstance{recv: pNDI_recv}); // let start = SystemTime::now(); // let since_the_epoch = start.duration_since(UNIX_EPOCH) diff --git a/gst-plugin-ndi/src/ndiaudiosrc.rs b/gst-plugin-ndi/src/ndiaudiosrc.rs index 92df9e60..12287076 100644 --- a/gst-plugin-ndi/src/ndiaudiosrc.rs +++ b/gst-plugin-ndi/src/ndiaudiosrc.rs @@ -18,9 +18,11 @@ use std::ptr; use ndilib::*; use connect_ndi; -use ndi_struct; +// use ndi_struct; use stop_ndi; +use hashmap_receivers; + // Property value storage #[derive(Debug, Clone)] struct Settings { @@ -318,26 +320,27 @@ impl NdiAudioSrc { fn fixate(&self, element: &BaseSrc, caps: gst::Caps) -> gst::Caps { //We need to set the correct caps resolution and framerate unsafe{ - let recv = match ndi_struct.recv{ - None => { - //TODO Update gst_element_error with one more descriptive - //println!("pNDI_recv no encontrado"); - gst_element_error!(element, gst::CoreError::Negotiation, ["No encontramos ndi recv"]); - return caps; - } - Some(ref recv) => recv.clone(), - }; + let map = hashmap_receivers.lock().unwrap(); + let settings = self.settings.lock().unwrap(); + + let mut id = &settings.stream_name; + if (&settings.ip != ""){ + id = &settings.ip; + } + let recv = map.get(id).unwrap(); let pNDI_recv = recv.recv; let mut timestamp_data = self.timestamp_data.lock().unwrap(); let audio_frame: NDIlib_audio_frame_v2_t = Default::default(); + let mut frame_type: NDIlib_frame_type_e = NDIlib_frame_type_e::NDIlib_frame_type_none; while frame_type != NDIlib_frame_type_e::NDIlib_frame_type_audio{ frame_type = NDIlib_recv_capture_v2(pNDI_recv, ptr::null(), &audio_frame, ptr::null(), 1000); } - ndi_struct.start_pts = audio_frame.timecode as u64; - //timestamp_data.pts = audio_frame.timecode as u64; + + //ndi_struct.start_pts = audio_frame.timecode as u64; + timestamp_data.pts = audio_frame.timecode as u64; let mut caps = gst::Caps::truncate(caps); { @@ -377,22 +380,22 @@ impl NdiAudioSrc { Some(ref info) => info.clone(), }; unsafe{ - let recv = match ndi_struct.recv{ - None => { - //TODO Update gst_element_error with one more descriptive - //println!("pNDI_recv no encontrado"); - gst_element_error!(element, gst::CoreError::Negotiation, ["No encontramos ndi recv"]); - return Err(gst::FlowReturn::NotNegotiated); - } - Some(ref recv) => recv.clone(), - }; - let pNDI_recv = recv.recv; - let pts: u64; + let map = hashmap_receivers.lock().unwrap(); + let mut id = &_settings.stream_name; + if (&_settings.ip != ""){ + id = &_settings.ip; + } + let recv = map.get(id).unwrap(); + + let pNDI_recv = recv.recv; + + let pts: u64; let audio_frame: NDIlib_audio_frame_v2_t = Default::default(); NDIlib_recv_capture_v2(pNDI_recv, ptr::null(), &audio_frame, ptr::null(), 1000,); - //pts = (audio_frame.timecode as u64) - timestamp_data.pts; - pts = (audio_frame.timecode as u64) - ndi_struct.start_pts; + + pts = (audio_frame.timecode as u64) - timestamp_data.pts; + //pts = (audio_frame.timecode as u64) - ndi_struct.start_pts; let buff_size = ((audio_frame.channel_stride_in_bytes)) as usize; let mut buffer = gst::Buffer::with_size(buff_size).unwrap(); diff --git a/gst-plugin-ndi/src/ndivideosrc.rs b/gst-plugin-ndi/src/ndivideosrc.rs index 2e5c5391..1b6f99bb 100644 --- a/gst-plugin-ndi/src/ndivideosrc.rs +++ b/gst-plugin-ndi/src/ndivideosrc.rs @@ -19,9 +19,11 @@ use std::ptr; use ndilib::*; use connect_ndi; -use ndi_struct; +// use ndi_struct; use stop_ndi; +use hashmap_receivers; + // Property value storage #[derive(Debug, Clone)] struct Settings { @@ -324,16 +326,14 @@ impl NdiVideoSrc { fn fixate(&self, element: &BaseSrc, caps: gst::Caps) -> gst::Caps { //We need to set the correct caps resolution and framerate unsafe{ - let recv = match ndi_struct.recv{ - None => { - //TODO Update gst_element_error with one more descriptive - //println!("pNDI_recv no encontrado"); - gst_element_error!(element, gst::CoreError::Negotiation, ["No encontramos ndi recv"]); - //TODO if none not return anything - return caps; - } - Some(ref recv) => recv.clone(), - }; + let map = hashmap_receivers.lock().unwrap(); + let settings = self.settings.lock().unwrap(); + + let mut id = &settings.stream_name; + if (&settings.ip != ""){ + id = &settings.ip; + } + let recv = map.get(id).unwrap(); let pNDI_recv = recv.recv; let mut timestamp_data = self.timestamp_data.lock().unwrap(); @@ -345,8 +345,9 @@ impl NdiVideoSrc { frame_type = NDIlib_recv_capture_v2(pNDI_recv, &video_frame, ptr::null(), ptr::null(), 1000); } - //timestamp_data.pts = video_frame.timecode as u64; - ndi_struct.start_pts = video_frame.timecode as u64; + //TODO Check that this is working + timestamp_data.pts = video_frame.timecode as u64; + //ndi_struct.start_pts = video_frame.timecode as u64; let mut caps = gst::Caps::truncate(caps); { @@ -386,23 +387,23 @@ impl NdiVideoSrc { Some(ref info) => info.clone(), }; unsafe{ - let recv = match ndi_struct.recv{ - None => { - //TODO Update gst_element_error with one more descriptive - //println!("pNDI_recv no encontrado"); - gst_element_error!(element, gst::CoreError::Negotiation, ["No encontramos ndi recv"]); - return Err(gst::FlowReturn::NotNegotiated); - } - Some(ref recv) => recv.clone(), - }; + let map = hashmap_receivers.lock().unwrap(); + let mut id = &_settings.stream_name; + + if (&_settings.ip != ""){ + id = &_settings.ip; + } + let recv = map.get(id).unwrap(); + let pNDI_recv = recv.recv; let pts: u64; let video_frame: NDIlib_video_frame_v2_t = Default::default(); NDIlib_recv_capture_v2(pNDI_recv, &video_frame, ptr::null(), ptr::null(), 1000,); - //pts = (video_frame.timecode as u64) - timestamp_data.pts; - pts = (video_frame.timecode as u64) - ndi_struct.start_pts; + pts = (video_frame.timecode as u64) - timestamp_data.pts; + //pts = (video_frame.timecode as u64) - ndi_struct.start_pts; + let buff_size = (video_frame.yres * video_frame.line_stride_in_bytes) as usize; //println!("{:?}", buff_size); let mut buffer = gst::Buffer::with_size(buff_size).unwrap();