Commit d503fc6b authored by Nicolas Bouillot's avatar Nicolas Bouillot

Merge branch 'develop'

parents ec999e3a 0508ea03
build/
\ No newline at end of file
Nicolas Bouillot
\ No newline at end of file
# CMake Config
cmake_minimum_required(VERSION 3.5.1)
#
# CONFIGURATION
#
# Project Variables
set(NDI2SHMDATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NDI2SHMDATA_VERSION_MAJOR 0)
set(NDI2SHMDATA_VERSION_MINOR 1)
set(NDI2SHMDATA_VERSION_PATCH 0)
set(NDI2SHMDATA_VERSION_STRING ${NDI2SHMDATA_VERSION_MAJOR}.${NDI2SHMDATA_VERSION_MINOR}.${NDI2SHMDATA_VERSION_PATCH})
set(SHMDATA_REQUIRED_VERSION 1.3)
# Package (pkg-config) Information
set(PACKAGE_NAME ndi2shmdata)
set(PACKAGE_DESCRIPTION "Ndi2shmdata provides tools for sharing video between shmdata and NewTek's NDI")
set(PACKAGE_URL "https://gitlab.com/sat-metalab/ndi2shmdata")
set(PACKAGE_VERSION ${NDI2SHMDATA_VERSION_STRING})
# Compilation
set(CMAKE_CXX_STANDARD 17)
set(DATADIR ${CMAKE_INSTALL_PREFIX}/share/ndi2shmdata/)
# CPack - General
set(CPACK_PACKAGE_NAME ${PACKAGE_NAME})
set(CPACK_PACKAGE_VENDOR "Metalab - Société des arts technologiques")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PACKAGE_DESCRIPTION}")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION_MAJOR "${NDI2SHMDATA_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${NDI2SHMDATA_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${NDI2SHMDATA_VERSION_PATCH}")
set(CPACK_GENERATOR TGZ)
set(CPACK_SOURCE_GENERATOR TGZ)
set(CPACK_COMPONENTS_ALL applications)
# CPack - Applications
set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "ndi2shmdata & shmdata2ndi")
set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION "Application for converting ndi to shmdata")
set(CPACK_COMPONENT_APPLICATIONS_DEPENDS libraries)
# CPack - Source
set(CPACK_SOURCE_IGNORE_FILES "/\.hooks/;/\.idea/;/build/;/html/;/scripts/;${CPACK_SOURCE_IGNORE_FILES}")
# Add local cmake directory to ckame module path in case we need it
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
#
# INCLUDES
#
include(FeatureSummary)
include(CPack)
include(PackageSourceTest)
include(CMakeDependentOption)
#
# PROJECT
#
project(Ndi2shmdata)
enable_testing()
option(ACCEPT_NDI_LICENSE "Accept NDI License Agreement" OFF)
if (NOT ACCEPT_NDI_LICENSE)
message(FATAL_ERROR "ndi2shmdata compilation requires acceptation of the NDI License. The license is available in the ndi-sdk folder. License can be accepted using the following cmake option: -DACCEPT_NDI_LICENSE=ON\nExample 'cmake -DACCEPT_NDI_LICENSE=ON ..' ")
endif()
# Prerequisites
find_package(PkgConfig REQUIRED)
# This is required in the case where macport screwed with the paths on mac os x
set(ENV{PKG_CONFIG_PATH} "/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH")
pkg_check_modules(SHMDATA REQUIRED shmdata-${SHMDATA_REQUIRED_VERSION})
# Global stuff
link_directories(
${SHMDATA_LIBRARY_DIRS}
${NDI2SHMDATA_DIR}/ndi-sdk/lib/x86_64-linux-gnu
)
link_libraries(
${SHMDATA_LIBRARIES}
dl
ndi
pthread
)
include_directories(
${SHMDATA_INCLUDE_DIRS}
${NDI2SHMDATA_DIR}/ndi-sdk/include
)
add_compile_options(${SHMDATA_CFLAGS})
# BUILD TYPE
if(CMAKE_BUILD_TYPE EQUAL "Debug")
add_definitions(-DDEBUG)
endif()
# WARNINGS
add_definitions(-Wall)
add_definitions(-Wextra)
add_definitions(-Werror)
add_definitions(-Wno-error=unused-parameter)
# OSX (not tested !)
if(APPLE AND ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(OSX TRUE)
add_definitions(-DOSX)
add_compile_options(-ObjC++) # Allows objective-c building
endif ()
#
# MODULES
#
add_subdirectory(src)
#
# OTHER TARGETS
#
# Uninstall
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/CMakeUninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/CMakeUninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/CMakeUninstall.cmake)
#
# POST
#
# Report
feature_summary(WHAT ALL)
if (NOT EXISTS "@[email protected]/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @[email protected]/install_manifest.txt")
endif (NOT EXISTS "@[email protected]/install_manifest.txt")
file(READ "@[email protected]/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach (file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@[email protected]" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if (NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif (NOT "${rm_retval}" STREQUAL 0)
else (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach (file)
\ No newline at end of file
CONTRIBUTING
======
Coding style
------------
We use Google C++ Style Guide, as decribed [here](https://google.github.io/styleguide/cppguide.html), with two excpetions:
* a function call’s arguments will either be all on the same line or will have one line each.
* a function declaration’s or function definition’s parameters will either all be on the same line or will have one line each.
Note that you may find configuration file for your editor [here](https://github.com/google/styleguide).
Contributing
------------
Please send your merge request at the [sat-metalab' gitlab account](https://gitlab.com/sat-metalab/ndi2shmdata). If you do not know how to make a merge request, gitlab provides some [help about creating a merge request](https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.html).
Branching strategy with git
---------------------------
The [master](https://gitlab.com/sat-metalab/ndi2shmdata/tree/master) branch contains releases. Validated new developments are into the [develop](https://gitlab.com/sat-metalab/ndi2shmdata/tree/develop) branch.
Modifications are made into a dedicated branch that need to be merged into the develop branch through a gitlab merge request. When you modification is ready, you need to prepare your merge request as follow:
* Update your develop branch.
```
git fetch
git checkout develop
git pull origin develop
```
* Go back to your branch and rebase onto develop. Note that it would be appreciated that you only merge request from a single commit (i.e interactive rebase with squash and/or fixup before pushing).
```
git rebase -i develop
```
# How to make new releases
First make sure `develop` branch reflects the desired `master`:
* Increase the version (major, minor or patch) or in the CMakeLists.txt file located at the root of the project
* Create a new entry in the NEWS.md file (top of the file) with version number, date and description of changes
* Commit and push, open a code review
Release into the master branch:
* merge into master: `git checkout master && git pull origin master && git merge --no-ff develop`
* tag the version `git tag -a vX.X.X -m"Short message that explains the new version"`
* push to master: `git push origin master --tags`
You're done.
# NDI2shmdata Changelog
ndi2shmdata [0.1.0] - 2019-02-11
--------------------------------
New features:
* command line listing of available NDI streams
* ndi2shmdata subscribes to a NDI stream using its name, and write video frames to a shmdata
* shmdata2ndi subscribes to a shmdata and publishes it as a NDI stream
# NDI2shmdata
Tool that convert shmdata to NewTek's NDI. This allows for shmdata enabled software to enter the NDI world.
\ No newline at end of file
Tool that convert [shmdata](https://gitlab.com/sat-metalab/shmdata) to [NewTek's NDI](http://ndi.newtek.com), and _vice versa_.
Example
=======
List visible NDI streams:
```
ndi2shmdata -l
```
Get a stream and make it a shmdata located at `/tmp/shmomg`:
```
ndi2shmdata -d -o /tmp/shmomg -n "ndi-stream-name"
```
View the stream with gst-launch:
```
gst-launch -v shmdatasrc socket-path=/tmp/shmomg ! videoconvert ! xvimagesink sync=false
```
For more detailled information, get help from the commands using the `-h` flag:
```
ndi2shmdata -h
shmdata2ndi -h
```
Build from sources
==================
This has been tested with Ubuntu 18.04. git and shmdata must be installed on your system.
You need to accept NDI license for the code to compile. The License Agreement text is available [here](ndi-sdk/NDI\ License\ Agreement.pdf) and can be accepted with the cmake variable "ACCEPT_NDI_LICENSE" set to "ON".
```
git clone http://gitlab.com:sat-metalab/ndi2shmdata.git
cd ndi2shmdata && mkdir build && cd build
cmake -DACCEPT_NDI_LICENSE=ON ..
make
sudo make install
```
TODO
====
* audio support in ndi2shmdata and shmdata2ndi
* (maybe) support NDI timecode
configure_file("cmake/PackageSourceTest.sh.in" "PackageSourceTest.sh" @ONLY)
add_custom_target(package_source_test COMMAND ${CMAKE_CURRENT_BINARY_DIR}/PackageSourceTest.sh)
\ No newline at end of file
#!/usr/bin/env bash
set -e
# Clean before, in case of a previous failed test
rm -f @[email protected]@[email protected]
rm -rf @[email protected]@[email protected]
# Create the source package
make package_source
# Extract and rebuild + test
tar -zxvf @[email protected]@[email protected]
cd @[email protected]@[email protected]
mkdir build
cd build
cmake ..
make
make test
# Cleanup after
cd ../..
rm -f @[email protected]@[email protected]
rm -rf @[email protected]@[email protected]
\ No newline at end of file
#pragma once
// NOTE : The following MIT license applies to this file ONLY and not to the SDK as a whole. Please review the SDK documentation
// for the description of the full license terms, which are also provided in the file "NDI License Agreement.pdf" within the SDK or
// online at http://new.tk/ndisdk_license/. Your use of any part of this SDK is acknowledgment that you agree to the SDK license
// terms. The full NDI SDK may be downloaded at https://www.newtek.com/ndi/sdk/
//
//***********************************************************************************************************************************************
//
// Copyright(c) 2014-2018 NewTek, inc
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
// merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//***********************************************************************************************************************************************
//****************************************************************************************************************
typedef struct NDIlib_v3
{ // V1.5
bool(*NDIlib_initialize)(void);
void(*NDIlib_destroy)(void);
const char* (*NDIlib_version)(void);
bool(*NDIlib_is_supported_CPU)(void);
PROCESSINGNDILIB_DEPRECATED NDIlib_find_instance_t(*NDIlib_find_create)(const NDIlib_find_create_t* p_create_settings);
NDIlib_find_instance_t(*NDIlib_find_create_v2)(const NDIlib_find_create_t* p_create_settings);
void(*NDIlib_find_destroy)(NDIlib_find_instance_t p_instance);
const NDIlib_source_t* (*NDIlib_find_get_sources)(NDIlib_find_instance_t p_instance, uint32_t* p_no_sources, uint32_t timeout_in_ms);
NDIlib_send_instance_t(*NDIlib_send_create)(const NDIlib_send_create_t* p_create_settings);
void(*NDIlib_send_destroy)(NDIlib_send_instance_t p_instance);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_send_send_video)(NDIlib_send_instance_t p_instance, const NDIlib_video_frame_t* p_video_data);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_send_send_video_async)(NDIlib_send_instance_t p_instance, const NDIlib_video_frame_t* p_video_data);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_send_send_audio)(NDIlib_send_instance_t p_instance, const NDIlib_audio_frame_t* p_audio_data);
void(*NDIlib_send_send_metadata)(NDIlib_send_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);
NDIlib_frame_type_e(*NDIlib_send_capture)(NDIlib_send_instance_t p_instance, NDIlib_metadata_frame_t* p_metadata, uint32_t timeout_in_ms);
void(*NDIlib_send_free_metadata)(NDIlib_send_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);
bool(*NDIlib_send_get_tally)(NDIlib_send_instance_t p_instance, NDIlib_tally_t* p_tally, uint32_t timeout_in_ms);
int(*NDIlib_send_get_no_connections)(NDIlib_send_instance_t p_instance, uint32_t timeout_in_ms);
void(*NDIlib_send_clear_connection_metadata)(NDIlib_send_instance_t p_instance);
void(*NDIlib_send_add_connection_metadata)(NDIlib_send_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);
void(*NDIlib_send_set_failover)(NDIlib_send_instance_t p_instance, const NDIlib_source_t* p_failover_source);
PROCESSINGNDILIB_DEPRECATED NDIlib_recv_instance_t(*NDIlib_recv_create_v2)(const NDIlib_recv_create_t* p_create_settings);
PROCESSINGNDILIB_DEPRECATED NDIlib_recv_instance_t(*NDIlib_recv_create)(const NDIlib_recv_create_t* p_create_settings);
void(*NDIlib_recv_destroy)(NDIlib_recv_instance_t p_instance);
PROCESSINGNDILIB_DEPRECATED NDIlib_frame_type_e(*NDIlib_recv_capture)(NDIlib_recv_instance_t p_instance, NDIlib_video_frame_t* p_video_data, NDIlib_audio_frame_t* p_audio_data, NDIlib_metadata_frame_t* p_metadata, uint32_t timeout_in_ms);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_recv_free_video)(NDIlib_recv_instance_t p_instance, const NDIlib_video_frame_t* p_video_data);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_recv_free_audio)(NDIlib_recv_instance_t p_instance, const NDIlib_audio_frame_t* p_audio_data);
void(*NDIlib_recv_free_metadata)(NDIlib_recv_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);
bool(*NDIlib_recv_send_metadata)(NDIlib_recv_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);
bool(*NDIlib_recv_set_tally)(NDIlib_recv_instance_t p_instance, const NDIlib_tally_t* p_tally);
void(*NDIlib_recv_get_performance)(NDIlib_recv_instance_t p_instance, NDIlib_recv_performance_t* p_total, NDIlib_recv_performance_t* p_dropped);
void(*NDIlib_recv_get_queue)(NDIlib_recv_instance_t p_instance, NDIlib_recv_queue_t* p_total);
void(*NDIlib_recv_clear_connection_metadata)(NDIlib_recv_instance_t p_instance);
void(*NDIlib_recv_add_connection_metadata)(NDIlib_recv_instance_t p_instance, const NDIlib_metadata_frame_t* p_metadata);
int(*NDIlib_recv_get_no_connections)(NDIlib_recv_instance_t p_instance);
NDIlib_routing_instance_t(*NDIlib_routing_create)(const NDIlib_routing_create_t* p_create_settings);
void(*NDIlib_routing_destroy)(NDIlib_routing_instance_t p_instance);
bool(*NDIlib_routing_change)(NDIlib_routing_instance_t p_instance, const NDIlib_source_t* p_source);
bool(*NDIlib_routing_clear)(NDIlib_routing_instance_t p_instance);
void(*NDIlib_util_send_send_audio_interleaved_16s)(NDIlib_send_instance_t p_instance, const NDIlib_audio_frame_interleaved_16s_t* p_audio_data);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_util_audio_to_interleaved_16s)(const NDIlib_audio_frame_t* p_src, NDIlib_audio_frame_interleaved_16s_t* p_dst);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_util_audio_from_interleaved_16s)(const NDIlib_audio_frame_interleaved_16s_t* p_src, NDIlib_audio_frame_t* p_dst);
// V2
bool(*NDIlib_find_wait_for_sources)(NDIlib_find_instance_t p_instance, uint32_t timeout_in_ms);
const NDIlib_source_t* (*NDIlib_find_get_current_sources)(NDIlib_find_instance_t p_instance, uint32_t* p_no_sources);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_util_audio_to_interleaved_32f)(const NDIlib_audio_frame_t* p_src, NDIlib_audio_frame_interleaved_32f_t* p_dst);
PROCESSINGNDILIB_DEPRECATED void(*NDIlib_util_audio_from_interleaved_32f)(const NDIlib_audio_frame_interleaved_32f_t* p_src, NDIlib_audio_frame_t* p_dst);
void(*NDIlib_util_send_send_audio_interleaved_32f)(NDIlib_send_instance_t p_instance, const NDIlib_audio_frame_interleaved_32f_t* p_audio_data);
// V3
void(*NDIlib_recv_free_video_v2)(NDIlib_recv_instance_t p_instance, const NDIlib_video_frame_v2_t* p_video_data);
void(*NDIlib_recv_free_audio_v2)(NDIlib_recv_instance_t p_instance, const NDIlib_audio_frame_v2_t* p_audio_data);
NDIlib_frame_type_e(*NDIlib_recv_capture_v2)(NDIlib_recv_instance_t p_instance, NDIlib_video_frame_v2_t* p_video_data, NDIlib_audio_frame_v2_t* p_audio_data, NDIlib_metadata_frame_t* p_metadata, uint32_t timeout_in_ms); // The amount of time in milliseconds to wait for data.
void(*NDIlib_send_send_video_v2)(NDIlib_send_instance_t p_instance, const NDIlib_video_frame_v2_t* p_video_data);
void(*NDIlib_send_send_video_async_v2)(NDIlib_send_instance_t p_instance, const NDIlib_video_frame_v2_t* p_video_data);
void(*NDIlib_send_send_audio_v2)(NDIlib_send_instance_t p_instance, const NDIlib_audio_frame_v2_t* p_audio_data);
void(*NDIlib_util_audio_to_interleaved_16s_v2)(const NDIlib_audio_frame_v2_t* p_src, NDIlib_audio_frame_interleaved_16s_t* p_dst);
void(*NDIlib_util_audio_from_interleaved_16s_v2)(const NDIlib_audio_frame_interleaved_16s_t* p_src, NDIlib_audio_frame_v2_t* p_dst);
void(*NDIlib_util_audio_to_interleaved_32f_v2)(const NDIlib_audio_frame_v2_t* p_src, NDIlib_audio_frame_interleaved_32f_t* p_dst);
void(*NDIlib_util_audio_from_interleaved_32f_v2)(const NDIlib_audio_frame_interleaved_32f_t* p_src, NDIlib_audio_frame_v2_t* p_dst);
// V3.01
void(*NDIlib_recv_free_string)(NDIlib_recv_instance_t p_instance, const char* p_string);
bool(*NDIlib_recv_ptz_is_supported)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_recording_is_supported)(NDIlib_recv_instance_t p_instance);
const char*(*NDIlib_recv_get_web_control)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_ptz_zoom)(NDIlib_recv_instance_t p_instance, const float zoom_value);
bool(*NDIlib_recv_ptz_zoom_speed)(NDIlib_recv_instance_t p_instance, const float zoom_speed);
bool(*NDIlib_recv_ptz_pan_tilt)(NDIlib_recv_instance_t p_instance, const float pan_value, const float tilt_value);
bool(*NDIlib_recv_ptz_pan_tilt_speed)(NDIlib_recv_instance_t p_instance, const float pan_speed, const float tilt_speed);
bool(*NDIlib_recv_ptz_store_preset)(NDIlib_recv_instance_t p_instance, const int preset_no);
bool(*NDIlib_recv_ptz_recall_preset)(NDIlib_recv_instance_t p_instance, const int preset_no, const float speed);
bool(*NDIlib_recv_ptz_auto_focus)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_ptz_focus)(NDIlib_recv_instance_t p_instance, const float focus_value);
bool(*NDIlib_recv_ptz_focus_speed)(NDIlib_recv_instance_t p_instance, const float focus_speed);
bool(*NDIlib_recv_ptz_white_balance_auto)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_ptz_white_balance_indoor)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_ptz_white_balance_outdoor)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_ptz_white_balance_oneshot)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_ptz_white_balance_manual)(NDIlib_recv_instance_t p_instance, const float red, const float blue);
bool(*NDIlib_recv_ptz_exposure_auto)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_ptz_exposure_manual)(NDIlib_recv_instance_t p_instance, const float exposure_level);
bool(*NDIlib_recv_recording_start)(NDIlib_recv_instance_t p_instance, const char* p_filename_hint);
bool(*NDIlib_recv_recording_stop)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_recording_set_audio_level)(NDIlib_recv_instance_t p_instance, const float level_dB);
bool(*NDIlib_recv_recording_is_recording)(NDIlib_recv_instance_t p_instance);
const char*(*NDIlib_recv_recording_get_filename)(NDIlib_recv_instance_t p_instance);
const char*(*NDIlib_recv_recording_get_error)(NDIlib_recv_instance_t p_instance);
bool(*NDIlib_recv_recording_get_times)(NDIlib_recv_instance_t p_instance, NDIlib_recv_recording_time_t* p_times);
// V3.10
NDIlib_recv_instance_t(*NDIlib_recv_create_v3)(const NDIlib_recv_create_v3_t* p_create_settings);
// V3.5
void(*NDIlib_recv_connect)(NDIlib_recv_instance_t p_instance, const NDIlib_source_t* p_src);
// V3.6
NDIlib_send_instance_t(*NDIlib_send_create_v2)(const NDIlib_send_create_t* p_create_settings, const char* p_config_data);
NDIlib_recv_instance_t(*NDIlib_recv_create_v4)(const NDIlib_recv_create_v3_t* p_create_settings, const char* p_config_data);
NDIlib_find_instance_t(*NDIlib_find_create_v3)(const NDIlib_find_create_t* p_create_settings, const char* p_config_data);
void(*NDIlib_util_send_send_audio_interleaved_32s)(NDIlib_send_instance_t p_instance, const NDIlib_audio_frame_interleaved_32s_t* p_audio_data);
void(*NDIlib_util_audio_to_interleaved_32s_v2)(const NDIlib_audio_frame_v2_t* p_src, NDIlib_audio_frame_interleaved_32s_t* p_dst);
void(*NDIlib_util_audio_from_interleaved_32s_v2)(const NDIlib_audio_frame_interleaved_32s_t* p_src, NDIlib_audio_frame_v2_t* p_dst);
NDIlib_framesync_instance_t(*NDIlib_framesync_create)(NDIlib_recv_instance_t p_receiver);
void(*NDIlib_framesync_destroy)(NDIlib_framesync_instance_t p_instance);
void(*NDIlib_framesync_capture_audio)(NDIlib_framesync_instance_t p_instance, NDIlib_audio_frame_v2_t* p_audio_data, int sample_rate, int no_channels, int no_samples);
void(*NDIlib_framesync_free_audio)(NDIlib_framesync_instance_t p_instance, NDIlib_audio_frame_v2_t* p_audio_data);
void(*NDIlib_framesync_capture_video)(NDIlib_framesync_instance_t p_instance, NDIlib_video_frame_v2_t* p_video_data, NDIlib_frame_format_type_e field_type);
void(*NDIlib_framesync_free_video)(NDIlib_framesync_instance_t p_instance, NDIlib_video_frame_v2_t* p_video_data);
} NDIlib_v3;
typedef struct NDIlib_v3 NDIlib_v2;
// Load the library
PROCESSINGNDILIB_API
const NDIlib_v3* NDIlib_v3_load(void);
PROCESSINGNDILIB_API PROCESSINGNDILIB_DEPRECATED
const NDIlib_v2* NDIlib_v2_load(void);
#pragma once
// NOTE : The following MIT license applies to this file ONLY and not to the SDK as a whole. Please review the SDK documentation
// for the description of the full license terms, which are also provided in the file "NDI License Agreement.pdf" within the SDK or
// online at http://new.tk/ndisdk_license/. Your use of any part of this SDK is acknowledgment that you agree to the SDK license
// terms. The full NDI SDK may be downloaded at https://www.newtek.com/ndi/sdk/
//
//***********************************************************************************************************************************************
//
// Copyright(c) 2014-2018 NewTek, inc
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
// files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
// merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//***********************************************************************************************************************************************
//**************************************************************************************************************************
// Structures and type definitions required by NDI finding
// The reference to an instance of the finder
typedef void* NDIlib_find_instance_t;
// The creation structure that is used when you are creating a finder
typedef struct NDIlib_find_create_t
{ // Do we want to incluide the list of NDI sources that are running
// on the local machine ?
// If TRUE then local sources will be visible, if FALSE then they
// will not.
bool show_local_sources;
// Which groups do you want to search in for sources
const char* p_groups;
// The list of additional IP addresses that exist that we should query for
// sources on. For instance, if you want to find the sources on a remote machine
// that is not on your local sub-net then you can put a comma seperated list of
// those IP addresses here and those sources will be available locally even though
// they are not mDNS discoverable. An example might be "12.0.0.8,13.0.12.8".
// When none is specified the registry is used.
// Default = nullptr;
const char* p_extra_ips;
#if NDILIB_CPP_DEFAULT_CONSTRUCTORS
NDIlib_find_create_t(bool show_local_sources_ = true, const char* p_groups_ = nullptr, const char* p_extra_ips_ = nullptr);
#endif // NDILIB_CPP_DEFAULT_CONSTRUCTORS
} NDIlib_find_create_t;
//**************************************************************************************************************************
// Create a new finder instance. This will return nullptr if it fails.
// This function is deprecated, please use NDIlib_find_create_v2 if you can. This function
// ignores the p_extra_ips member and sets it to the default.
PROCESSINGNDILIB_API
NDIlib_find_instance_t NDIlib_find_create_v2(const NDIlib_find_create_t* p_create_settings NDILIB_CPP_DEFAULT_VALUE(nullptr));
// Create a new finder instance. This will return nullptr if it fails.
// This function is deprecated, please use NDIlib_find_create_v2 if you can. This function
// ignores the p_extra_ips member and sets it to the default.
PROCESSINGNDILIB_API
NDIlib_find_instance_t NDIlib_find_create_v3(const NDIlib_find_create_t* p_create_settings NDILIB_CPP_DEFAULT_VALUE(nullptr), const char* p_config_data NDILIB_CPP_DEFAULT_VALUE(nullptr));
// This will destroy an existing finder instance.
PROCESSINGNDILIB_API
void NDIlib_find_destroy(NDIlib_find_instance_t p_instance);
// This function will recover the current set of sources (i.e. the ones that exist right this second).
// The char* memory buffers returned in NDIlib_source_t are valid until the next call to NDIlib_find_get_current_sources or a call to NDIlib_find_destroy.
// For a given NDIlib_find_instance_t, do not call NDIlib_find_get_current_sources asynchronously.
PROCESSINGNDILIB_API
const NDIlib_source_t* NDIlib_find_get_current_sources(NDIlib_find_instance_t p_instance, uint32_t* p_no_sources);
// This will allow you to wait until the number of online sources have changed.
PROCESSINGNDILIB_API
bool NDIlib_find_wait_for_sources(NDIlib_find_instance_t p_instance, uint32_t timeout_in_ms);
#pragma once
//***********************************************************************************************************************************************
//
// Copyright(c) 2014-2018 NewTek, inc
//
//***********************************************************************************************************************************************
// It is important when using video to realize that often you are using differenc clocks
// for different parts of the signal chain. Within NDI, the sender can send at the clock rate
// that it wants and the receiver will receive it at that rate. The receiver however is very
// unlikely to share the exact same clock rate in many cases. For instance, bear in mind that
// computer clocks rely on crystals which while all rated for the same frequency are still not
// exact. If you sending computer has an audio clock that it "thinks" is 48000Hz, to the receiver
// computer that has a different audio clock this might be 48001Hz or 47998Hz. While these
// differences might appear small they accumulate over time and can cause audio to either
// slightly drift out of sync (it is receiving more audio sample sthan it needs to play back)
// or might cause audio glitches because it is not receiving enough audio samples. While we
// have described the situation for audio, the same exact problem occurs for video sources;
// it is commonly thought that this can be solved by simply having a "frame buffer" and that
// displaying the "most recently received video frame" will solve these timing discrepencies.
// Unfortunately this is not the case and when it is done because of the variance in clock
// timings, it is veyr common the the video will appear the "jitter" when the sending and
// receiving closks are almost in alignment. The solution to these problems is to implement
// a "time base corrector" for the video clock which is a device that uses hysterisis to know
// when the best time is to either drop or insert a video frame such that the video is most
// likely to play back smoothly, and audio should be dynamically audio sampled (with a high
// order resampling filter) to adaptively track any clocking differences. Implementing these
// components is very difficult to get entirely correct under all scenarios and this
// implementation is provided to facilitate this and help people who are building real time
// video applications to receive audio and video without needing to undertake the full
// complexity of implementing such clock devices.
//
// Another way to look at what this class does is that it transforms "push" sources (i.e.
// NDI sources in which the data is pushed from the sender to the receiver) into "pull"
// sources in which a host application is pulling the data down-stream. The frame-sync
// automatically tracks all clocks to acheive the best video performance doing this
// operation.
//
// In addition to time-base correction operations, these implementations also will automatically
// detect and correct timing jitter that might occur. This will internally correct for timing
// anomolies that might be caused by network, sender or receiver side timing errors caused
// by CPU limitatoins, network bandwidth fluctuations, etc...
//
// A very common use of a frame-synchronizer might be if you are displaying video on screen
// timed to the GPU v-sync, you should use sych a device to convert from the incoming time-base
// into the time-base of the GPU.
//
// The following are common times that you want to use a frame-synchronizer
// Video playback on screen : Yes, you want the clock to be synced with vertical refresh.