mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-17 05:09:58 +01:00
Added Output support for default Gstreamer shared memory
With option to select and configure socket path
This commit is contained in:
@@ -277,6 +277,7 @@ struct Application
|
|||||||
int broadcast_port;
|
int broadcast_port;
|
||||||
KnownHosts recentSRT;
|
KnownHosts recentSRT;
|
||||||
int loopback_camera;
|
int loopback_camera;
|
||||||
|
int shm_method;
|
||||||
std::string shm_socket_path;
|
std::string shm_socket_path;
|
||||||
|
|
||||||
// Settings of widgets
|
// Settings of widgets
|
||||||
@@ -337,6 +338,7 @@ struct Application
|
|||||||
recentSRT.protocol = "srt://";
|
recentSRT.protocol = "srt://";
|
||||||
recentSRT.default_host = { "127.0.0.1", "7070"};
|
recentSRT.default_host = { "127.0.0.1", "7070"};
|
||||||
loopback_camera = 0;
|
loopback_camera = 0;
|
||||||
|
shm_method = 0;
|
||||||
shm_socket_path = "";
|
shm_socket_path = "";
|
||||||
pannel_current_session_mode = 0;
|
pannel_current_session_mode = 0;
|
||||||
current_view = 1;
|
current_view = 1;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of vimix - video live mixer
|
* This file is part of vimix - video live mixer
|
||||||
*
|
*
|
||||||
* **Copyright** (C) 2019-2023 Bruno Herbelin <bruno.herbelin@gmail.com>
|
* **Copyright** (C) 2019-2023 Bruno Herbelin <bruno.herbelin@gmail.com>
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
|
||||||
// gstreamer
|
// gstreamer
|
||||||
#include <gst/gstformat.h>
|
#include <gst/gstformat.h>
|
||||||
@@ -28,54 +31,78 @@
|
|||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "GstToolkit.h"
|
#include "GstToolkit.h"
|
||||||
|
#include "SystemToolkit.h"
|
||||||
|
|
||||||
#include "ShmdataBroadcast.h"
|
#include "ShmdataBroadcast.h"
|
||||||
|
|
||||||
// Test command
|
// Test command shmdata
|
||||||
// gst-launch-1.0 --gst-plugin-path=/usr/local/lib/gstreamer-1.0/ shmdatasrc socket-path=/tmp/shmdata_vimix0 ! videoconvert ! autovideosink
|
// gst-launch-1.0 --gst-plugin-path=/usr/local/lib/gstreamer-1.0/ shmdatasrc socket-path=/tmp/shmdata_vimix0 ! videoconvert ! autovideosink
|
||||||
|
|
||||||
std::string ShmdataBroadcast::shmdata_sink_ = "shmdatasink";
|
// Test command shmsrc
|
||||||
|
// gst-launch-1.0 shmsrc socket-path=/tmp/shmdata_vimix0 is-live=true ! video/x-raw, format=RGB, framerate=30/1, width=1152, height=720 ! videoconvert ! autovideosink
|
||||||
|
|
||||||
bool ShmdataBroadcast::available()
|
// OBS receiver
|
||||||
|
// shmsrc socket-path=/tmp/shmdata_vimix0 is-live=true ! video/x-raw, format=RGB, framerate=30/1, width=1152, height=720 ! videoconvert ! video.
|
||||||
|
// !!! OBS needs access to shm & filesystem
|
||||||
|
// sudo flatpak override --device=shm com.obsproject.Studio
|
||||||
|
// sudo flatpak override --filesystem=/tmp com.obsproject.Studio
|
||||||
|
|
||||||
|
std::vector<std::string> shm_sink_ = {
|
||||||
|
"shmsink",
|
||||||
|
"shmdatasink"
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ShmdataBroadcast::available(Method m)
|
||||||
{
|
{
|
||||||
// test for availability once on first run
|
// test for availability once on first run
|
||||||
static bool _available = false, _tested = false;
|
static bool _shm_available = false, _shmdata_available = false, _tested = false;
|
||||||
if (!_tested) {
|
if (!_tested) {
|
||||||
_available = GstToolkit::has_feature(ShmdataBroadcast::shmdata_sink_);
|
_shm_available = GstToolkit::has_feature(shm_sink_[SHM_SHMSINK]);
|
||||||
|
_shmdata_available = GstToolkit::has_feature(shm_sink_[SHM_SHMDATASINK]);
|
||||||
_tested = true;
|
_tested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _available;
|
if (m == SHM_SHMSINK)
|
||||||
|
return _shm_available;
|
||||||
|
else if (m == SHM_SHMDATASINK)
|
||||||
|
return _shmdata_available;
|
||||||
|
else
|
||||||
|
return _shm_available | _shmdata_available;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShmdataBroadcast::ShmdataBroadcast(const std::string &socketpath): FrameGrabber(), socket_path_(socketpath)
|
ShmdataBroadcast::ShmdataBroadcast(Method m, const std::string &socketpath): FrameGrabber(), method_(m), socket_path_(socketpath)
|
||||||
{
|
{
|
||||||
frame_duration_ = gst_util_uint64_scale_int (1, GST_SECOND, SHMDATA_FPS); // fixed 30 FPS
|
frame_duration_ = gst_util_uint64_scale_int (1, GST_SECOND, SHMDATA_FPS); // fixed 30 FPS
|
||||||
|
|
||||||
|
// default socket path
|
||||||
if (socket_path_.empty())
|
if (socket_path_.empty())
|
||||||
socket_path_ = SHMDATA_DEFAULT_PATH;
|
socket_path_ = SHMDATA_DEFAULT_PATH;
|
||||||
|
|
||||||
|
// default to SHMSINK / ignore SHM_SHMDATASINK if not available
|
||||||
|
if (!GstToolkit::has_feature(shm_sink_[SHM_SHMDATASINK]) || m == SHM_SHMDATAANY)
|
||||||
|
method_ = SHM_SHMSINK;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ShmdataBroadcast::init(GstCaps *caps)
|
std::string ShmdataBroadcast::init(GstCaps *caps)
|
||||||
{
|
{
|
||||||
if (!ShmdataBroadcast::available())
|
if (!ShmdataBroadcast::available())
|
||||||
return std::string("Shmdata Broadcast : Not available (missing shmdatasink plugin)");
|
return std::string("Shared Memory Broadcast : Not available (missing shmsink or shmdatasink plugin)");
|
||||||
|
|
||||||
// ignore
|
// ignore
|
||||||
if (caps == nullptr)
|
if (caps == nullptr)
|
||||||
return std::string("Shmdata Broadcast : Invalid caps");
|
return std::string("Shared Memory Broadcast : Invalid caps");
|
||||||
|
|
||||||
// create a gstreamer pipeline
|
// create a gstreamer pipeline
|
||||||
std::string description = "appsrc name=src ! queue ! ";
|
std::string description = "appsrc name=src ! queue ! ";
|
||||||
|
|
||||||
// complement pipeline with sink
|
// complement pipeline with sink
|
||||||
description += ShmdataBroadcast::shmdata_sink_ + " name=sink";
|
description += shm_sink_[method_] + " name=sink";
|
||||||
|
|
||||||
// parse pipeline descriptor
|
// parse pipeline descriptor
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
pipeline_ = gst_parse_launch (description.c_str(), &error);
|
pipeline_ = gst_parse_launch (description.c_str(), &error);
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
std::string msg = std::string("Shmdata Broadcast : Could not construct pipeline ") + description + "\n" + std::string(error->message);
|
std::string msg = std::string("Shared Memory Broadcast : Could not construct pipeline ") + description + "\n" + std::string(error->message);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
@@ -83,6 +110,7 @@ std::string ShmdataBroadcast::init(GstCaps *caps)
|
|||||||
// setup shm sink
|
// setup shm sink
|
||||||
g_object_set (G_OBJECT (gst_bin_get_by_name (GST_BIN (pipeline_), "sink")),
|
g_object_set (G_OBJECT (gst_bin_get_by_name (GST_BIN (pipeline_), "sink")),
|
||||||
"socket-path", socket_path_.c_str(),
|
"socket-path", socket_path_.c_str(),
|
||||||
|
"wait-for-connection", FALSE,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
// setup custom app source
|
// setup custom app source
|
||||||
@@ -123,19 +151,19 @@ std::string ShmdataBroadcast::init(GstCaps *caps)
|
|||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return std::string("Shmdata Broadcast : Failed to configure frame grabber.");
|
return std::string("Shared Memory Broadcast : Failed to configure frame grabber ") + shm_sink_[method_];
|
||||||
}
|
}
|
||||||
|
|
||||||
// start
|
// start
|
||||||
GstStateChangeReturn ret = gst_element_set_state (pipeline_, GST_STATE_PLAYING);
|
GstStateChangeReturn ret = gst_element_set_state (pipeline_, GST_STATE_PLAYING);
|
||||||
if (ret == GST_STATE_CHANGE_FAILURE) {
|
if (ret == GST_STATE_CHANGE_FAILURE) {
|
||||||
return std::string("Shmdata Broadcast : Failed to start frame grabber.");
|
return std::string("Shared Memory Broadcast : Failed to start frame grabber.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// all good
|
// all good
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
|
|
||||||
return std::string("Shared Memory with Shmdata started on ") + socket_path_;
|
return std::string("Shared Memory Broadcast with '") + shm_sink_[method_] + "' started on " + socket_path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -145,21 +173,44 @@ void ShmdataBroadcast::terminate()
|
|||||||
endofstream_ = true;
|
endofstream_ = true;
|
||||||
active_ = false;
|
active_ = false;
|
||||||
|
|
||||||
|
// delete socket
|
||||||
|
SystemToolkit::remove_file(socket_path_);
|
||||||
|
|
||||||
Log::Notify("Shared Memory terminated after %s s.",
|
Log::Notify("Shared Memory terminated after %s s.",
|
||||||
GstToolkit::time_to_string(duration_).c_str());
|
GstToolkit::time_to_string(duration_).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string ShmdataBroadcast::gst_pipeline() const
|
||||||
|
{
|
||||||
|
std::string pipeline;
|
||||||
|
|
||||||
|
pipeline += (method_ == SHM_SHMDATASINK) ? "shmdatasrc" : "shmsrc";
|
||||||
|
pipeline += " socket-path=";
|
||||||
|
pipeline += socket_path_;
|
||||||
|
pipeline += " is-live=true";
|
||||||
|
|
||||||
|
if (method_ == SHM_SHMSINK){
|
||||||
|
pipeline += " ! ";
|
||||||
|
pipeline += std::string( gst_caps_to_string(caps_) );
|
||||||
|
pipeline = std::regex_replace(pipeline, std::regex("\\(int\\)"), "");
|
||||||
|
pipeline = std::regex_replace(pipeline, std::regex("\\(fraction\\)"), "");
|
||||||
|
pipeline = std::regex_replace(pipeline, std::regex("\\(string\\)"), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
std::string ShmdataBroadcast::info() const
|
std::string ShmdataBroadcast::info() const
|
||||||
{
|
{
|
||||||
std::ostringstream ret;
|
std::ostringstream ret;
|
||||||
|
|
||||||
if (!initialized_)
|
if (!initialized_)
|
||||||
ret << "Shmdata starting..";
|
ret << "Shared Memory starting..";
|
||||||
else if (active_)
|
else if (active_)
|
||||||
ret << "Shmdata " << socket_path_;
|
ret << "Shared Memory " << socket_path_;
|
||||||
else
|
else
|
||||||
ret << "Shmdata terminated";
|
ret << "Shared Memory terminated";
|
||||||
|
|
||||||
return ret.str();
|
return ret.str();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,27 @@
|
|||||||
|
|
||||||
#include "FrameGrabber.h"
|
#include "FrameGrabber.h"
|
||||||
|
|
||||||
#define SHMDATA_DEFAULT_PATH "/tmp/shmdata_vimix"
|
#define SHMDATA_DEFAULT_PATH "/tmp/shm_vimix"
|
||||||
#define SHMDATA_FPS 30
|
#define SHMDATA_FPS 30
|
||||||
|
|
||||||
class ShmdataBroadcast : public FrameGrabber
|
class ShmdataBroadcast : public FrameGrabber
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ShmdataBroadcast(const std::string &socketpath = SHMDATA_DEFAULT_PATH);
|
|
||||||
|
enum Method {
|
||||||
|
SHM_SHMSINK,
|
||||||
|
SHM_SHMDATASINK,
|
||||||
|
SHM_SHMDATAANY
|
||||||
|
};
|
||||||
|
|
||||||
|
ShmdataBroadcast(Method m = SHM_SHMSINK, const std::string &socketpath = "");
|
||||||
virtual ~ShmdataBroadcast() {}
|
virtual ~ShmdataBroadcast() {}
|
||||||
|
|
||||||
static bool available();
|
static bool available(Method m = SHM_SHMDATAANY);
|
||||||
|
|
||||||
|
inline Method method() const { return method_; }
|
||||||
inline std::string socket_path() const { return socket_path_; }
|
inline std::string socket_path() const { return socket_path_; }
|
||||||
|
std::string gst_pipeline() const;
|
||||||
|
|
||||||
std::string info() const override;
|
std::string info() const override;
|
||||||
|
|
||||||
@@ -23,9 +32,8 @@ private:
|
|||||||
void terminate() override;
|
void terminate() override;
|
||||||
|
|
||||||
// connection information
|
// connection information
|
||||||
|
Method method_;
|
||||||
std::string socket_path_;
|
std::string socket_path_;
|
||||||
|
|
||||||
static std::string shmdata_sink_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHMDATABROADCAST_H
|
#endif // SHMDATABROADCAST_H
|
||||||
|
|||||||
@@ -4113,9 +4113,14 @@ void OutputPreview::ToggleSharedMemory()
|
|||||||
shm_broadcaster_->stop();
|
shm_broadcaster_->stop();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (Settings::application.shm_socket_path.empty())
|
// find a folder to put the socket for shm
|
||||||
Settings::application.shm_socket_path = SHMDATA_DEFAULT_PATH + std::to_string(Settings::application.instance_id);
|
std::string _shm_socket_file = Settings::application.shm_socket_path;
|
||||||
shm_broadcaster_ = new ShmdataBroadcast(Settings::application.shm_socket_path);
|
if (_shm_socket_file.empty() || !SystemToolkit::file_exists(_shm_socket_file))
|
||||||
|
_shm_socket_file = SystemToolkit::home_path();
|
||||||
|
_shm_socket_file = SystemToolkit::full_filename(_shm_socket_file, ".shm_vimix" + std::to_string(Settings::application.instance_id));
|
||||||
|
|
||||||
|
// create shhmdata broadcaster with method
|
||||||
|
shm_broadcaster_ = new ShmdataBroadcast( (ShmdataBroadcast::Method) Settings::application.shm_method, _shm_socket_file);
|
||||||
FrameGrabbing::manager().add(shm_broadcaster_);
|
FrameGrabbing::manager().add(shm_broadcaster_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4306,7 +4311,7 @@ void OutputPreview::Render()
|
|||||||
{
|
{
|
||||||
// Stream sharing menu
|
// Stream sharing menu
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_STREAM, 0.9f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_STREAM, 0.9f));
|
||||||
if ( ImGui::MenuItem( ICON_FA_SHARE_ALT_SQUARE " Peer-to-peer sharing", NULL, &Settings::application.accept_connections) ) {
|
if ( ImGui::MenuItem( ICON_FA_SHARE_ALT_SQUARE " P2P Peer-to-peer sharing", NULL, &Settings::application.accept_connections) ) {
|
||||||
Streaming::manager().enable(Settings::application.accept_connections);
|
Streaming::manager().enable(Settings::application.accept_connections);
|
||||||
}
|
}
|
||||||
ImGui::PopStyleColor(1);
|
ImGui::PopStyleColor(1);
|
||||||
@@ -4323,7 +4328,7 @@ void OutputPreview::Render()
|
|||||||
|
|
||||||
// Shared Memory menu
|
// Shared Memory menu
|
||||||
if (ShmdataBroadcast::available()) {
|
if (ShmdataBroadcast::available()) {
|
||||||
if ( ImGui::MenuItem( ICON_FA_SHARE_ALT " Shared Memory", NULL, sharedMemoryEnabled()) )
|
if ( ImGui::MenuItem( ICON_FA_MEMORY " SHM Shared Memory", NULL, sharedMemoryEnabled()) )
|
||||||
ToggleSharedMemory();
|
ToggleSharedMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4363,8 +4368,8 @@ void OutputPreview::Render()
|
|||||||
// copy text icon to give user the socket path to connect to
|
// copy text icon to give user the socket path to connect to
|
||||||
ImVec2 draw_pos = ImGui::GetCursorPos();
|
ImVec2 draw_pos = ImGui::GetCursorPos();
|
||||||
ImGui::SetCursorPos(draw_pos + ImVec2(ImGui::GetContentRegionAvailWidth() - 1.2 * ImGui::GetTextLineHeightWithSpacing(), -0.8 * ImGui::GetFrameHeight()) );
|
ImGui::SetCursorPos(draw_pos + ImVec2(ImGui::GetContentRegionAvailWidth() - 1.2 * ImGui::GetTextLineHeightWithSpacing(), -0.8 * ImGui::GetFrameHeight()) );
|
||||||
if (ImGuiToolkit::IconButton( ICON_FA_COPY, shm_broadcaster_->socket_path().c_str()))
|
if (ImGuiToolkit::IconButton( ICON_FA_COPY, shm_broadcaster_->gst_pipeline().c_str()))
|
||||||
ImGui::SetClipboardText(shm_broadcaster_->socket_path().c_str());
|
ImGui::SetClipboardText(shm_broadcaster_->gst_pipeline().c_str());
|
||||||
ImGui::SetCursorPos(draw_pos);
|
ImGui::SetCursorPos(draw_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4482,7 +4487,7 @@ void OutputPreview::Render()
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.8f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.8f));
|
||||||
else
|
else
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.4f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.4f));
|
||||||
ImGui::Text(ICON_FA_SHARE_ALT);
|
ImGui::Text(ICON_FA_MEMORY);
|
||||||
ImGui::PopStyleColor(1);
|
ImGui::PopStyleColor(1);
|
||||||
vertical += 2.f * r;
|
vertical += 2.f * r;
|
||||||
}
|
}
|
||||||
@@ -8373,7 +8378,7 @@ void Navigator::RenderMainPannelSettings()
|
|||||||
char buf[512]; sprintf(buf, "Buffer at %s can contain %ld frames (%dx%d), i.e. %.1f sec", VideoRecorder::buffering_preset_name[Settings::application.record.buffering_mode],
|
char buf[512]; sprintf(buf, "Buffer at %s can contain %ld frames (%dx%d), i.e. %.1f sec", VideoRecorder::buffering_preset_name[Settings::application.record.buffering_mode],
|
||||||
(unsigned long)nb, output->width(), output->height(),
|
(unsigned long)nb, output->width(), output->height(),
|
||||||
(float)nb / (float) VideoRecorder::framerate_preset_value[Settings::application.record.framerate_mode] );
|
(float)nb / (float) VideoRecorder::framerate_preset_value[Settings::application.record.framerate_mode] );
|
||||||
ImGuiToolkit::Indication(buf, ICON_FA_MEMORY);
|
ImGuiToolkit::Indication(buf, ICON_FA_ELLIPSIS_H);
|
||||||
ImGui::SameLine(0);
|
ImGui::SameLine(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8391,22 +8396,22 @@ void Navigator::RenderMainPannelSettings()
|
|||||||
ImGui::Combo("Priority", &Settings::application.record.priority_mode, "Duration\0Framerate\0");
|
ImGui::Combo("Priority", &Settings::application.record.priority_mode, "Duration\0Framerate\0");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Networking preferences
|
// Steaming preferences
|
||||||
//
|
//
|
||||||
ImGuiToolkit::Spacing();
|
ImGuiToolkit::Spacing();
|
||||||
ImGui::Text("Stream");
|
ImGui::Text("Stream");
|
||||||
|
|
||||||
ImGuiToolkit::Indication("Peer-to-peer sharing on local network\n\n"
|
ImGuiToolkit::Indication("Peer-to-peer sharing local network\n\n"
|
||||||
"vimix can stream JPEG (default) or H264 (requires less bandwidth but more resources for encoding)", ICON_FA_SHARE_ALT_SQUARE);
|
"vimix can stream JPEG (default) or H264 (less bandwidth, higher encoding cost)", ICON_FA_SHARE_ALT_SQUARE);
|
||||||
ImGui::SameLine(0);
|
ImGui::SameLine(0);
|
||||||
ImGui::SetCursorPosX(width_);
|
ImGui::SetCursorPosX(width_);
|
||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
ImGui::Combo("Share P2P", &Settings::application.stream_protocol, "JPEG\0H264\0");
|
ImGui::Combo("P2P codec", &Settings::application.stream_protocol, "JPEG\0H264\0");
|
||||||
|
|
||||||
if (VideoBroadcast::available()) {
|
if (VideoBroadcast::available()) {
|
||||||
char msg[256];
|
char msg[256];
|
||||||
ImFormatString(msg, IM_ARRAYSIZE(msg), "Broadcast SRT\n\n"
|
ImFormatString(msg, IM_ARRAYSIZE(msg), "SRT Broadcast\n\n"
|
||||||
"vimix is listening to SRT requests on Port %d. "
|
"vimix listens to SRT requests on Port %d. "
|
||||||
"Example network addresses to call:\n"
|
"Example network addresses to call:\n"
|
||||||
" srt//%s:%d (localhost)\n"
|
" srt//%s:%d (localhost)\n"
|
||||||
" srt//%s:%d (local IP)",
|
" srt//%s:%d (local IP)",
|
||||||
@@ -8420,13 +8425,52 @@ void Navigator::RenderMainPannelSettings()
|
|||||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
char bufport[7] = "";
|
char bufport[7] = "";
|
||||||
sprintf(bufport, "%d", Settings::application.broadcast_port);
|
sprintf(bufport, "%d", Settings::application.broadcast_port);
|
||||||
ImGui::InputTextWithHint("Port SRT", "7070", bufport, 6, ImGuiInputTextFlags_CharsDecimal);
|
ImGui::InputTextWithHint("SRT Port", "7070", bufport, 6, ImGuiInputTextFlags_CharsDecimal);
|
||||||
if (ImGui::IsItemDeactivatedAfterEdit()){
|
if (ImGui::IsItemDeactivatedAfterEdit()){
|
||||||
if ( BaseToolkit::is_a_number(bufport, &Settings::application.broadcast_port))
|
if ( BaseToolkit::is_a_number(bufport, &Settings::application.broadcast_port))
|
||||||
Settings::application.broadcast_port = CLAMP(Settings::application.broadcast_port, 1029, 49150);
|
Settings::application.broadcast_port = CLAMP(Settings::application.broadcast_port, 1029, 49150);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShmdataBroadcast::available()) {
|
||||||
|
std::string _shm_socket_file = Settings::application.shm_socket_path;
|
||||||
|
if (_shm_socket_file.empty() || !SystemToolkit::file_exists(_shm_socket_file))
|
||||||
|
_shm_socket_file = SystemToolkit::home_path();
|
||||||
|
_shm_socket_file = SystemToolkit::full_filename(_shm_socket_file, ".shm_vimix" + std::to_string(Settings::application.instance_id));
|
||||||
|
|
||||||
|
char msg[256];
|
||||||
|
if (ShmdataBroadcast::available(ShmdataBroadcast::SHM_SHMDATASINK)) {
|
||||||
|
ImFormatString(msg, IM_ARRAYSIZE(msg), "Shared Memory\n\n"
|
||||||
|
"vimix can share to RAM with "
|
||||||
|
"gstreamer default 'shmsink' "
|
||||||
|
"and with 'shmdatasink'.\n"
|
||||||
|
"Socket file to connect to:\n%s\n",
|
||||||
|
_shm_socket_file.c_str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImFormatString(msg, IM_ARRAYSIZE(msg), "Shared Memory\n\n"
|
||||||
|
"vimix can share to RAM with "
|
||||||
|
"gstreamer 'shmsink'.\n"
|
||||||
|
"Socket file to connect to:\n%s\n",
|
||||||
|
_shm_socket_file.c_str());
|
||||||
|
}
|
||||||
|
ImGuiToolkit::Indication(msg, ICON_FA_MEMORY);
|
||||||
|
ImGui::SameLine(0);
|
||||||
|
ImGui::SetCursorPosX(width_);
|
||||||
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
|
char bufsocket[64] = "";
|
||||||
|
sprintf(bufsocket, "%s", Settings::application.shm_socket_path.c_str());
|
||||||
|
ImGui::InputTextWithHint("SHM path", SystemToolkit::home_path().c_str(), bufsocket, 64);
|
||||||
|
if (ImGui::IsItemDeactivatedAfterEdit()) {
|
||||||
|
Settings::application.shm_socket_path = bufsocket;
|
||||||
|
}
|
||||||
|
if (ShmdataBroadcast::available(ShmdataBroadcast::SHM_SHMDATASINK)) {
|
||||||
|
ImGui::SetCursorPosX(width_);
|
||||||
|
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||||
|
ImGui::Combo("SHM plugin", &Settings::application.shm_method, "shmsink\0shmdatasink\0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// OSC preferences
|
// OSC preferences
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user