mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-06-05 06:58:58 +00:00
Publish code in Github
This commit is contained in:
parent
a41f33ae08
commit
440a353f93
13 changed files with 69 additions and 451 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,3 +1,2 @@
|
|||
target
|
||||
**/*.rs.bk
|
||||
*~
|
||||
Cargo.lock
|
||||
target/
|
67
README.md
Normal file
67
README.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
GStreamer NDI Plugin for Linux
|
||||
====================
|
||||
|
||||
*Compiled and tested with Ubuntu 16.04.5, GStreamer 1.8.3 and NDI SDK 3.0.9 and 3.5.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/).
|
||||
|
||||
Currently the plugin has two source elements, `ndivideosrc` to get video from the stream and `ndiaudiosrc` for audio. By just providing the name or the ip of the stream, all the information required from the stream is picked up automatically, such as resolution, framerate, audio channels, ...
|
||||
|
||||
Some examples of how to use these elements from the command line:
|
||||
|
||||
```
|
||||
#Information about the elements
|
||||
gst-inspect-1.0 ndi
|
||||
gst-inspect-1.0 ndivideosrc
|
||||
gst-inspect-1.0 ndiaudiosrc
|
||||
|
||||
#Video pipeline
|
||||
gst-launch-1.0 ndivideosrc stream-name="GC-DEV2 (OBS)" ! autovideosink
|
||||
#Audio pipeline
|
||||
gst-launch-1.0 ndiaudiosrc stream-name="GC-DEV2 (OBS)" ! autoaudiosink
|
||||
|
||||
#Video and audio pipeline
|
||||
gst-launch-1.0 ndivideosrc stream-name="GC-DEV2 (OBS)" ! autovideosink ndiaudiosrc stream-name="GC-DEV2 (OBS)" ! autoaudiosink
|
||||
```
|
||||
|
||||
Feel free to contribute to this project. Some ways you can contribute are:
|
||||
* Testing with more hardware and software and reporting bugs
|
||||
* Doing pull requests.
|
||||
|
||||
Compilation of the NDI element
|
||||
-------
|
||||
To compile the NDI element it's necessary to install Rust, the NDI SDK and the following packages for gstreamer:
|
||||
|
||||
```
|
||||
apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||
gstreamer1.0-libav libgstrtspserver-1.0-dev
|
||||
|
||||
```
|
||||
To install the required NDI library there are two options:
|
||||
1. Download NDI SDK from NDI website and move the library to the correct location.
|
||||
2. Use a [deb package](https://github.com/Palakis/obs-ndi/releases/download/4.5.2/libndi3_3.5.1-1_amd64.deb) made by the community. Thanks to [NDI plugin for OBS](https://github.com/Palakis/obs-ndi).
|
||||
|
||||
To install Rust, you can follow their documentation: https://www.rust-lang.org/en-US/install.html
|
||||
|
||||
Once all requirements are met, you can build the plugin by executing the following command from the project root folder:
|
||||
|
||||
```
|
||||
cargo build
|
||||
export GST_PLUGIN_PATH=`pwd`/target/debug
|
||||
gst-inspect-1.0 ndi
|
||||
```
|
||||
|
||||
If all went ok, you should see info related to the NDI element. To make the plugin available without using `GST_PLUGIN_PATH` it's necessary to copy the plugin to the gstreamer plugins folder.
|
||||
```
|
||||
cp target/debug/libgstndi.so /usr/lib/x86_64-linux-gnu/gstreamer-1.0/
|
||||
```
|
||||
|
||||
More info about GStreamer plugins written in Rust:
|
||||
----------------------------------
|
||||
https://github.com/sdroege/gstreamer-rs
|
||||
https://github.com/sdroege/gst-plugin-rs
|
||||
|
||||
https://coaxion.net/blog/2018/01/how-to-write-gstreamer-elements-in-rust-part-1-a-video-filter-for-converting-rgb-to-grayscale/
|
||||
https://coaxion.net/blog/2018/02/how-to-write-gstreamer-elements-in-rust-part-2-a-raw-audio-sine-wave-source/
|
4
example/Cargo.lock
generated
4
example/Cargo.lock
generated
|
@ -1,4 +0,0 @@
|
|||
[[package]]
|
||||
name = "ndi"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[package]
|
||||
name = "ndi"
|
||||
version = "0.1.0"
|
||||
authors = ["rubenrua <rubenrua@teltek.es>"]
|
||||
|
||||
[dependencies]
|
|
@ -1,128 +0,0 @@
|
|||
#![allow(non_upper_case_globals, non_snake_case)]
|
||||
|
||||
pub mod ndilib;
|
||||
|
||||
use std::ptr;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
use ndilib::*;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
if !NDIlib_initialize() {
|
||||
//TODO delete exits
|
||||
println!("Cannot run NDI: NDIlib_initialize error.");
|
||||
::std::process::exit(1);
|
||||
}
|
||||
|
||||
//TODO valores por defecto
|
||||
let NDI_find_create_desc: NDIlib_find_create_t = Default::default();
|
||||
let pNDI_find = NDIlib_find_create_v2(&NDI_find_create_desc);
|
||||
if pNDI_find.is_null() {
|
||||
println!("Cannot run NDI: NDIlib_find_create_v2 error.");
|
||||
::std::process::exit(1);
|
||||
}
|
||||
|
||||
let mut no_sources: u32 = 0;
|
||||
let mut p_sources = ptr::null();
|
||||
while no_sources == 0 {
|
||||
p_sources = NDIlib_find_get_current_sources(pNDI_find, &mut no_sources as *mut u32);
|
||||
}
|
||||
|
||||
// We need at least one source
|
||||
if p_sources.is_null() {
|
||||
println!("Error getting NDIlib_find_get_current_sources.");
|
||||
::std::process::exit(1);
|
||||
}
|
||||
|
||||
println!(
|
||||
"no_source {}: Name '{}' Address '{}'",
|
||||
no_sources,
|
||||
CStr::from_ptr((*p_sources).p_ndi_name)
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
CStr::from_ptr((*p_sources).p_ip_address)
|
||||
.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
|
||||
// it will still be provided in BGRA
|
||||
let p_ndi_name = CString::new("Galicaster NDI Receiver").unwrap();
|
||||
let NDI_recv_create_desc = NDIlib_recv_create_v3_t {
|
||||
source_to_connect_to: *p_sources,
|
||||
p_ndi_name: p_ndi_name.as_ptr(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let pNDI_recv = NDIlib_recv_create_v3(&NDI_recv_create_desc);
|
||||
if pNDI_recv.is_null() {
|
||||
println!("Cannot run NDI: NDIlib_recv_create_v3 error.");
|
||||
::std::process::exit(1);
|
||||
}
|
||||
|
||||
// Destroy the NDI finder. We needed to have access to the pointers to p_sources[0]
|
||||
NDIlib_find_destroy(pNDI_find);
|
||||
|
||||
// We are now going to mark this source as being on program output for tally purposes (but not on preview)
|
||||
let tally_state: NDIlib_tally_t = Default::default();
|
||||
NDIlib_recv_set_tally(pNDI_recv, &tally_state);
|
||||
|
||||
// Enable Hardwqre Decompression support if this support has it. Please read the caveats in the documentation
|
||||
// regarding this. There are times in which it might reduce the performance although on small stream numbers
|
||||
// it almost always yields the same or better performance.
|
||||
let data = CString::new("<ndi_hwaccel enabled=\"true\"/>").unwrap();
|
||||
let enable_hw_accel = NDIlib_metadata_frame_t {
|
||||
length: data.to_bytes().len() as i32,
|
||||
timecode: 0,
|
||||
p_data: data.as_ptr(),
|
||||
};
|
||||
|
||||
NDIlib_recv_send_metadata(pNDI_recv, &enable_hw_accel);
|
||||
|
||||
loop {
|
||||
let video_frame: NDIlib_video_frame_v2_t = Default::default();
|
||||
let audio_frame: NDIlib_audio_frame_v2_t = Default::default();
|
||||
let metadata_frame: NDIlib_metadata_frame_t = Default::default();
|
||||
|
||||
let frame_type = NDIlib_recv_capture_v2(
|
||||
pNDI_recv,
|
||||
&video_frame,
|
||||
&audio_frame,
|
||||
&metadata_frame,
|
||||
1000,
|
||||
);
|
||||
|
||||
match frame_type {
|
||||
NDIlib_frame_type_e::NDIlib_frame_type_video => {
|
||||
println!("Tengo video {:?}", video_frame);
|
||||
}
|
||||
NDIlib_frame_type_e::NDIlib_frame_type_audio => {
|
||||
println!("Tengo audio {:?}", audio_frame);
|
||||
}
|
||||
NDIlib_frame_type_e::NDIlib_frame_type_metadata => {
|
||||
println!(
|
||||
"Tengo metadata {} '{}'",
|
||||
metadata_frame.length,
|
||||
CStr::from_ptr(metadata_frame.p_data)
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
);
|
||||
}
|
||||
NDIlib_frame_type_e::NDIlib_frame_type_error => {
|
||||
println!(
|
||||
"Tengo error {} '{}'",
|
||||
metadata_frame.length,
|
||||
CStr::from_ptr(metadata_frame.p_data)
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
);
|
||||
break;
|
||||
}
|
||||
_ => println!("Tengo {:?}", frame_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Exit");
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
#![allow(non_camel_case_types, non_upper_case_globals)]
|
||||
|
||||
use std::ptr;
|
||||
|
||||
#[link(name = "ndi")]
|
||||
extern "C" {
|
||||
pub fn NDIlib_initialize() -> bool;
|
||||
pub fn NDIlib_find_create_v2(
|
||||
p_create_settings: *const NDIlib_find_create_t,
|
||||
) -> NDIlib_find_instance_t;
|
||||
pub fn NDIlib_find_get_current_sources(
|
||||
p_instance: NDIlib_find_instance_t,
|
||||
p_no_sources: *mut u32,
|
||||
) -> *const NDIlib_source_t;
|
||||
pub fn NDIlib_recv_create_v3(
|
||||
p_create_settings: *const NDIlib_recv_create_v3_t,
|
||||
) -> NDIlib_recv_instance_t;
|
||||
pub fn NDIlib_find_destroy(p_instance: NDIlib_find_instance_t);
|
||||
pub fn NDIlib_recv_set_tally(
|
||||
p_instance: NDIlib_recv_instance_t,
|
||||
p_tally: *const NDIlib_tally_t,
|
||||
) -> bool;
|
||||
pub fn NDIlib_recv_send_metadata(
|
||||
p_instance: NDIlib_recv_instance_t,
|
||||
p_metadata: *const NDIlib_metadata_frame_t,
|
||||
) -> bool;
|
||||
pub fn NDIlib_recv_capture_v2(
|
||||
p_instance: NDIlib_recv_instance_t,
|
||||
p_video_data: *const NDIlib_video_frame_v2_t,
|
||||
p_audio_data: *const NDIlib_audio_frame_v2_t,
|
||||
p_metadata: *const NDIlib_metadata_frame_t,
|
||||
timeout_in_ms: u32,
|
||||
) -> NDIlib_frame_type_e;
|
||||
}
|
||||
|
||||
pub type NDIlib_find_instance_t = *mut ::std::os::raw::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NDIlib_find_create_t {
|
||||
pub show_local_sources: bool,
|
||||
pub p_groups: *const ::std::os::raw::c_char,
|
||||
pub p_extra_ips: *const ::std::os::raw::c_char,
|
||||
}
|
||||
|
||||
impl Default for NDIlib_find_create_t {
|
||||
fn default() -> Self {
|
||||
NDIlib_find_create_t {
|
||||
show_local_sources: true,
|
||||
p_groups: ptr::null(),
|
||||
p_extra_ips: ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[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,
|
||||
}
|
||||
|
||||
impl Default for NDIlib_source_t {
|
||||
fn default() -> Self {
|
||||
NDIlib_source_t {
|
||||
p_ndi_name: ptr::null(),
|
||||
p_ip_address: ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NDIlib_frame_type_e {
|
||||
NDIlib_frame_type_none = 0,
|
||||
NDIlib_frame_type_video = 1,
|
||||
NDIlib_frame_type_audio = 2,
|
||||
NDIlib_frame_type_metadata = 3,
|
||||
NDIlib_frame_type_error = 4,
|
||||
NDIlib_frame_type_status_change = 100,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NDIlib_recv_bandwidth_e {
|
||||
NDIlib_recv_bandwidth_metadata_only = -10,
|
||||
NDIlib_recv_bandwidth_audio_only = 10,
|
||||
NDIlib_recv_bandwidth_lowest = 0,
|
||||
NDIlib_recv_bandwidth_highest = 100,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NDIlib_recv_color_format_e {
|
||||
NDIlib_recv_color_format_BGRX_BGRA = 0,
|
||||
NDIlib_recv_color_format_UYVY_BGRA = 1,
|
||||
NDIlib_recv_color_format_RGBX_RGBA = 2,
|
||||
NDIlib_recv_color_format_UYVY_RGBA = 3,
|
||||
NDIlib_recv_color_format_fastest = 100,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NDIlib_FourCC_type_e {
|
||||
NDIlib_FourCC_type_UYVY = 1498831189,
|
||||
NDIlib_FourCC_type_BGRA = 1095911234,
|
||||
NDIlib_FourCC_type_BGRX = 1481787202,
|
||||
NDIlib_FourCC_type_RGBA = 1094862674,
|
||||
NDIlib_FourCC_type_RGBX = 1480738642,
|
||||
NDIlib_FourCC_type_UYVA = 1096178005,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum NDIlib_frame_format_type_e {
|
||||
NDIlib_frame_format_type_progressive = 1,
|
||||
NDIlib_frame_format_type_interleaved = 0,
|
||||
NDIlib_frame_format_type_field_0 = 2,
|
||||
NDIlib_frame_format_type_field_1 = 3,
|
||||
}
|
||||
|
||||
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)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NDIlib_recv_create_v3_t {
|
||||
pub source_to_connect_to: NDIlib_source_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,
|
||||
}
|
||||
|
||||
impl Default for NDIlib_recv_create_v3_t {
|
||||
fn default() -> Self {
|
||||
NDIlib_recv_create_v3_t {
|
||||
source_to_connect_to: Default::default(),
|
||||
allow_video_fields: true,
|
||||
bandwidth: NDIlib_recv_bandwidth_e::NDIlib_recv_bandwidth_highest,
|
||||
color_format: NDIlib_recv_color_format_e::NDIlib_recv_color_format_UYVY_BGRA,
|
||||
p_ndi_name: ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type NDIlib_recv_instance_t = *mut ::std::os::raw::c_void;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NDIlib_tally_t {
|
||||
pub on_program: bool,
|
||||
pub on_preview: bool,
|
||||
}
|
||||
|
||||
impl Default for NDIlib_tally_t {
|
||||
fn default() -> Self {
|
||||
NDIlib_tally_t {
|
||||
on_program: false,
|
||||
on_preview: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NDIlib_metadata_frame_t {
|
||||
pub length: ::std::os::raw::c_int,
|
||||
pub timecode: i64,
|
||||
pub p_data: *const ::std::os::raw::c_char,
|
||||
}
|
||||
|
||||
impl Default for NDIlib_metadata_frame_t {
|
||||
fn default() -> Self {
|
||||
NDIlib_metadata_frame_t {
|
||||
length: 0,
|
||||
timecode: 0, //NDIlib_send_timecode_synthesize,
|
||||
p_data: ptr::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
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 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 p_metadata: *const ::std::os::raw::c_char,
|
||||
pub timestamp: i64,
|
||||
}
|
||||
|
||||
impl Default for NDIlib_video_frame_v2_t {
|
||||
fn default() -> Self {
|
||||
NDIlib_video_frame_v2_t {
|
||||
xres: 0,
|
||||
yres: 0,
|
||||
FourCC: NDIlib_FourCC_type_e::NDIlib_FourCC_type_UYVY,
|
||||
frame_rate_N: 30000,
|
||||
frame_rate_D: 1001,
|
||||
picture_aspect_ratio: 0.0,
|
||||
frame_format_type: NDIlib_frame_format_type_e::NDIlib_frame_format_type_progressive,
|
||||
timecode: NDIlib_send_timecode_synthesize,
|
||||
p_data: ptr::null(),
|
||||
line_stride_in_bytes: 0,
|
||||
p_metadata: ptr::null(),
|
||||
timestamp: NDIlib_send_timecode_empty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct NDIlib_audio_frame_v2_t {
|
||||
pub sample_rate: ::std::os::raw::c_int,
|
||||
pub no_channels: ::std::os::raw::c_int,
|
||||
pub no_samples: ::std::os::raw::c_int,
|
||||
pub timecode: i64,
|
||||
pub p_data: *const ::std::os::raw::c_float,
|
||||
pub channel_stride_in_bytes: ::std::os::raw::c_int,
|
||||
pub p_metadata: *const ::std::os::raw::c_char,
|
||||
pub timestamp: i64,
|
||||
}
|
||||
|
||||
impl Default for NDIlib_audio_frame_v2_t {
|
||||
fn default() -> Self {
|
||||
NDIlib_audio_frame_v2_t {
|
||||
sample_rate: 48000,
|
||||
no_channels: 2,
|
||||
no_samples: 0,
|
||||
timecode: NDIlib_send_timecode_synthesize,
|
||||
p_data: ptr::null(),
|
||||
channel_stride_in_bytes: 0,
|
||||
p_metadata: ptr::null(),
|
||||
timestamp: NDIlib_send_timecode_empty,
|
||||
}
|
||||
}
|
||||
}
|
1
gst-plugin-ndi/.gitignore
vendored
1
gst-plugin-ndi/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
Cargo.lock
|
|
@ -1,63 +0,0 @@
|
|||
GStreamer NDI Plugin for Linux
|
||||
====================
|
||||
|
||||
*Compiled and tested with Ubuntu 16.04.5, GStreamer 1.8.3 and NDI SDK 3.0.9 and 3.5.1*
|
||||
|
||||
This is a plugin for the [GStreamer](https://gstreamer.freedesktop.org/) multimedia framework that allows to receive a stream from a [NDI](https://www.newtek.com/ndi/) source. This plugin is developed by [Teltek](http://teltek.es/) and funded by the [University of the Arts London](https://www.arts.ac.uk/) and [The University of Manchester](https://www.manchester.ac.uk/).
|
||||
|
||||
Currently the plugin only has sources elements, `ndivideosrc` to get video from the stream and `ndiaudiosrc` for audio. Only it's necessary to provide the name or the ip of the stream, and automatically the element get all the information required from the stream, such resolution, framerate, audio channels,...
|
||||
|
||||
Some examples of usage of these elements:
|
||||
```
|
||||
#Information about the elements
|
||||
gst-inspect-1.0 ndi
|
||||
gst-inspect-1.0 ndivideosrc
|
||||
gst-inspect-1.0 ndiaudiosrc
|
||||
|
||||
#Video pipeline
|
||||
gst-launch-1.0 ndivideosrc stream-name="GC-DEV2 (OBS)" ! autovideosink
|
||||
#Audio pipeline
|
||||
gst-launch-1.0 ndiaudiosrc stream-name="GC-DEV2 (OBS)" ! autoaudiosink
|
||||
|
||||
#Video and audio pipeline
|
||||
gst-launch-1.0 ndivideosrc stream-name="GC-DEV2 (OBS)" ! autovideosink ndiaudiosrc stream-name="GC-DEV2 (OBS)" ! autoaudiosink
|
||||
```
|
||||
|
||||
Feel free to contribute to this project testing with more hardware and software, reporting bugs or with pull requests.
|
||||
|
||||
Compile NDI element
|
||||
-------
|
||||
Before compile the element it's necessary install Rust, NDI SDK and the following packages for gstreamer:
|
||||
|
||||
```
|
||||
apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \
|
||||
gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
|
||||
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
|
||||
gstreamer1.0-libav libgstrtspserver-1.0-dev
|
||||
|
||||
```
|
||||
To install the necessary NDI library exists two options:
|
||||
* Download NDI SDK from NDI website and move the library to the correct location.
|
||||
* Use a [deb package](https://github.com/Palakis/obs-ndi/releases/download/4.5.2/libndi3_3.5.1-1_amd64.deb) made by the community. Thanks to [NDI plugin for OBS](https://github.com/Palakis/obs-ndi).
|
||||
|
||||
To build the plugin execute these commands from the root of the repository folder
|
||||
|
||||
```
|
||||
cargo build
|
||||
|
||||
export GST_PLUGIN_PATH=`pwd`/target/debug
|
||||
gst-inspect-1.0 ndi
|
||||
```
|
||||
|
||||
If all went ok, you should see info related to the NDI element. To make the plugin available without using `GST_PLUGIN_PATH` it's necessary copy the plugin to the gstreamer plugins folder.
|
||||
```
|
||||
cp target/debug/libgstndi.so /usr/lib/x86_64-linux-gnu/gstreamer-1.0/
|
||||
```
|
||||
|
||||
More info about GStreamer plugins written in Rust:
|
||||
----------------------------------
|
||||
https://github.com/sdroege/gstreamer-rs
|
||||
https://github.com/sdroege/gst-plugin-rs
|
||||
|
||||
https://coaxion.net/blog/2018/01/how-to-write-gstreamer-elements-in-rust-part-1-a-video-filter-for-converting-rgb-to-grayscale/
|
||||
https://coaxion.net/blog/2018/02/how-to-write-gstreamer-elements-in-rust-part-2-a-raw-audio-sine-wave-source/
|
Loading…
Reference in a new issue