Skip to content

Commit

Permalink
Merge pull request #20 from AMWA-TV/feature-gstreamer-plugins
Browse files Browse the repository at this point in the history
Feature gstreamer plugins
  • Loading branch information
LufeBisect authored Feb 5, 2025
2 parents 2e7b06e + a386723 commit 0fe2349
Show file tree
Hide file tree
Showing 22 changed files with 2,563 additions and 30 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,9 @@ Open `cpp/demos/ossrf-nmos-api/config/nmos_config.json` and adjust the following
## Build Container and Code simultaneously

./scripts/build-inside-container.sh

## GStreamer Plugins

We have also developed GStreamer plugins (nmossender, nmosvideoreceiver, and nmosaudioreceiver) that integrate NMOS registration and control with the sending and receiving of raw ST2110 audio/video streams.

For detailed instructions on building, installing, and using these plugins (including examples of gst-launch-1.0 pipelines), please see the [Plugins Guide](/cpp/libs/gst_nmos_plugins/).
36 changes: 36 additions & 0 deletions cpp/demos/config/nmos_plugin_node_config_receiver.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"node": {
"id": "8968180c-0418-4422-bea1-f0c642389637",
"configuration": {
"label": "BISECT OSSRF Node Receiver",
"description": "BISECT OSSRF node receiver",
"host_addresses": [
"192.168.1.1"
],
"interfaces": [
{
"chassis_id": "c9-94-02-f7-3e-eb",
"name": "wlp1s0",
"port_id": "00-e0-4c-68-01-8d"
}
],
"clocks": [
{
"name": "clk0",
"ref_type": "ptp",
"traceable": false,
"version": "IEEE1588-2008",
"gmid": "00-20-fc-ff-fe-35-9c-26",
"locked": true
}
],
"registry_address": "192.168.1.1",
"registry_version": "v1.3",
"registration_port": 8010,
"system_address": "192.168.1.1",
"system_version": "v1.0",
"system_port": 8010,
"http_port": 5114
}
}
}
36 changes: 36 additions & 0 deletions cpp/demos/config/nmos_plugin_node_config_sender.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"node": {
"id": "d5504cd1-fe68-489d-99d4-20d3f075f062",
"configuration": {
"label": "BISECT OSSRF Node Sender",
"description": "BISECT OSSRF node sender",
"host_addresses": [
"192.168.1.1"
],
"interfaces": [
{
"chassis_id": "c8-94-02-f7-3e-eb",
"name": "wlp1s0",
"port_id": "01-e0-4c-68-01-8d"
}
],
"clocks": [
{
"name": "clk0",
"ref_type": "ptp",
"traceable": false,
"version": "IEEE1588-2008",
"gmid": "00-20-fc-ff-fe-35-9c-25",
"locked": true
}
],
"registry_address": "192.168.1.1",
"registry_version": "v1.3",
"registration_port": 8010,
"system_address": "192.168.1.1",
"system_version": "v1.0",
"system_port": 8010,
"http_port": 6114
}
}
}
54 changes: 28 additions & 26 deletions cpp/demos/ossrf-nmos-api/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,43 +61,45 @@ namespace
{
if(i == 1)
{
auto receiver_activation_callback = [r = (*it).dump(), &gst_receiver_uptr](
const std::optional<std::string>& sdp, bool master_enable) {
if(sdp.has_value())
{
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
if(plugin.has_value())
auto receiver_activation_callback =
[r = (*it).dump(), &gst_receiver_uptr](const std::optional<std::string>& sdp,
bool master_enable, const nlohmann::json&) {
if(sdp.has_value())
{
gst_receiver_uptr.reset(plugin.value().release());
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
if(plugin.has_value())
{
gst_receiver_uptr.reset(plugin.value().release());
return;
}
fmt::print("failed creating receiver\n");
return;
}
fmt::print("failed creating receiver\n");
return;
}
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
};
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
};
BST_CHECK(nmos_client->add_receiver(device_id, (*it).dump(), receiver_activation_callback));
receiver_info_config = (*it).dump();
}
else if(i == 2)
{
auto receiver_activation_callback = [r = (*it).dump(), &gst_receiver_uptr_2](
const std::optional<std::string>& sdp, bool master_enable) {
if(sdp.has_value())
{
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
if(plugin.has_value())
auto receiver_activation_callback =
[r = (*it).dump(), &gst_receiver_uptr_2](const std::optional<std::string>& sdp,
bool master_enable, const nlohmann::json&) {
if(sdp.has_value())
{
gst_receiver_uptr_2.reset(plugin.value().release());
fmt::print("nmos_receiver_callback: {} {}\n", master_enable, sdp.value());
auto plugin = ossrf::gst::plugins::create_gst_receiver_plugin(r, sdp.value());
if(plugin.has_value())
{
gst_receiver_uptr_2.reset(plugin.value().release());
return;
}
fmt::print("failed creating receiver\n");
return;
}
fmt::print("failed creating receiver\n");
return;
}
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
};
fmt::print("nmos_receiver_callback: {} no sdp\n", master_enable);
};
BST_CHECK(nmos_client->add_receiver(device_id, (*it).dump(), receiver_activation_callback));
}
i++;
Expand Down
1 change: 1 addition & 0 deletions cpp/libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_subdirectory(bisect_expected)
add_subdirectory(bisect_nmoscpp)
add_subdirectory(bisect_sdp)
add_subdirectory(bisect_gst)
add_subdirectory(gst_nmos_plugins)
add_subdirectory(ossrf_nmos_api)
add_subdirectory(ossrf_gstreamer_api)
add_subdirectory(bisect_json)
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ namespace bisect::nmoscpp
nmos::rational exact_framerate;
std::string chroma_sub_sampling;
nmos::interlace_mode structure;
int depth = 0;
};

struct audio_sender_info_t
Expand Down Expand Up @@ -156,5 +157,5 @@ namespace bisect::nmoscpp
std::function<void(bool master_enable, const nlohmann::json& transport_params)>;

using receiver_activation_callback_t =
std::function<void(const std::optional<std::string>& sdp, const bool master_enable)>;
std::function<void(const std::optional<std::string>& sdp, const bool master_enable, const nlohmann::json& transport_params)>;
} // namespace bisect::nmoscpp
3 changes: 2 additions & 1 deletion cpp/libs/bisect_sdp/lib/src/reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ namespace
.exact_framerate = nmos::rational(params.exactframerate.numerator(), params.exactframerate.denominator()),
.chroma_sub_sampling = "YCbCr-4:2:2",
.structure = params.interlace ? nmos::interlace_modes::interlaced_tff : nmos::interlace_modes::progressive,
.depth = static_cast<int>(params.depth),
};
}
} // namespace
Expand Down Expand Up @@ -196,4 +197,4 @@ expected<sdp_settings_t> bisect::sdp::parse_sdp(const std::string& sdp)
{
BST_FAIL("error parsing SDP: {}", ex.what());
}
}
}
99 changes: 99 additions & 0 deletions cpp/libs/gst_nmos_plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
cmake_minimum_required(VERSION 3.16)
project(gst_nmos_plugins LANGUAGES CXX)

find_package(nlohmann_json REQUIRED)
find_package(PkgConfig REQUIRED)

# Locate GLib package
pkg_check_modules(GLIB REQUIRED glib-2.0)

# Locate GStreamer packages
pkg_search_module(GSTREAMER REQUIRED gstreamer-1.0>=1.4)
pkg_search_module(GSTREAMER_APP REQUIRED gstreamer-app-1.0>=1.4)
pkg_search_module(GSTREAMER_AUDIO REQUIRED gstreamer-audio-1.0>=1.4)
pkg_search_module(GSTREAMER_VIDEO REQUIRED gstreamer-video-1.0>=1.4)

# Include the parent directory of gst_nmos_plugins
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)

# Utils library (shared across plugins)
add_library(utils STATIC src/utils.cpp)

# Enable -fPIC for utils
set_target_properties(utils PROPERTIES POSITION_INDEPENDENT_CODE ON)

target_include_directories(utils
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..
PRIVATE ${GLIB_INCLUDE_DIRS}
PRIVATE ${GSTREAMER_INCLUDE_DIRS}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../bisect
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ossrf
)
target_link_libraries(utils
PUBLIC nlohmann_json::nlohmann_json
PRIVATE ${GLIB_LIBRARIES}
PRIVATE ${GSTREAMER_LIBRARIES}
PRIVATE ${GSTREAMER_APP_LIBRARIES}
PRIVATE ${GSTREAMER_AUDIO_LIBRARIES}
PRIVATE ${GSTREAMER_VIDEO_LIBRARIES}
PRIVATE bisect::project_warnings
PRIVATE bisect::expected
PRIVATE bisect::bisect_nmoscpp
PRIVATE bisect::bisect_json
PRIVATE ossrf::ossrf_nmos_api
)

# Function to create a plugin target
function(create_plugin plugin_name plugin_sources output_name)
add_library(${plugin_name} MODULE ${plugin_sources})
target_include_directories(${plugin_name}
PRIVATE ${GSTREAMER_INCLUDE_DIRS}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
target_link_libraries(${plugin_name}
PRIVATE
${GSTREAMER_LIBRARIES}
${GSTREAMER_APP_LIBRARIES}
${GSTREAMER_AUDIO_LIBRARIES}
${GSTREAMER_VIDEO_LIBRARIES}
utils
PUBLIC
bisect::project_warnings
bisect::expected
bisect::bisect_nmoscpp
bisect::bisect_json
nlohmann_json::nlohmann_json
ossrf::ossrf_nmos_api
${GLIB_LIBRARIES}
)
set_target_properties(${plugin_name} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
OUTPUT_NAME ${output_name}
)
add_library(ossrf::${plugin_name} ALIAS ${plugin_name})
install(TARGETS ${plugin_name}
LIBRARY DESTINATION ~/.local/lib/gstreamer-1.0
)
endfunction()

# Plugin: Video Receiver
create_plugin(
gst_nmos_video_receiver_plugin
src/gst_nmos_video_receiver_plugin.cpp
"gstnmosvideoreceiver"
)

# Plugin: Audio Receiver
create_plugin(
gst_nmos_audio_receiver_plugin
src/gst_nmos_audio_receiver_plugin.cpp
"gstnmosaudioreceiver"
)

# Plugin: Sender
create_plugin(
gst_nmos_sender_plugin
src/gst_nmos_sender_plugin.cpp
"gstnmossender"
)
Loading

0 comments on commit 0fe2349

Please sign in to comment.