mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-01-11 11:45:30 +00:00
Fix to use multiple NDI streams in the same pipeline
It's not possible to connect to the same stream twice. For example to audio and video from the same stream.
This commit is contained in:
parent
0baf7ee839
commit
8bf4f8f935
3 changed files with 79 additions and 70 deletions
|
@ -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<NdiInstance>,
|
||||
start_pts: u64,
|
||||
|
@ -51,16 +54,23 @@ static mut ndi_struct: Ndi = Ndi{
|
|||
start_pts: 0,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
static ref hashmap_receivers: Mutex<HashMap<String, NdiInstance>> = {
|
||||
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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue