Integration of Shmdata in vimix

Unified menu in output window for streaming (for SRT, Shmdata and peer to peer). Cleanup SRT broadcaster and bugfix on FrameGrabber default frame timing.
This commit is contained in:
Bruno Herbelin
2022-12-06 23:21:17 +01:00
parent 07e8f489c1
commit da06cf52ec
6 changed files with 124 additions and 52 deletions

View File

@@ -270,7 +270,7 @@ void FrameGrabbing::grabFrame(FrameBuffer *frame_buffer)
FrameGrabber::FrameGrabber(): finished_(false), initialized_(false), active_(false), endofstream_(false), accept_buffer_(false), buffering_full_(false),
pipeline_(nullptr), src_(nullptr), caps_(nullptr), timer_(nullptr), timer_firstframe_(0),
timestamp_(0), duration_(0), frame_count_(0), buffering_size_(MIN_BUFFER_SIZE), timestamp_on_clock_(false)
timestamp_(0), duration_(0), frame_count_(0), buffering_size_(MIN_BUFFER_SIZE), timestamp_on_clock_(true)
{
// unique id
id_ = BaseToolkit::uniqueId();

View File

@@ -231,10 +231,15 @@ bool Rendering::init()
g_setenv ("GST_PLUGIN_SCANNER", plugins_scanner.c_str(), TRUE);
}
std::string plugins_path;
const gchar *c = g_getenv("GST_PLUGIN_PATH");
std::string plugins_path = c != NULL ? std::string(c) : "";
std::string local_plugin_path = SystemToolkit::cwd_path() + "gstreamer-1.0";
if ( SystemToolkit::file_exists(local_plugin_path))
plugins_path = local_plugin_path;
if ( SystemToolkit::file_exists(local_plugin_path)){
if (!plugins_path.empty())
plugins_path += ":";
plugins_path += local_plugin_path;
}
#ifdef GSTREAMER_SHMDATA_PLUGIN
std::string shmdata_plugin_path = GSTREAMER_SHMDATA_PLUGIN;

View File

@@ -95,6 +95,7 @@ using namespace std;
#include "ImageProcessingShader.h"
#include "Metronome.h"
#include "VideoBroadcast.h"
#include "ShmdataBroadcast.h"
#include "MultiFileRecorder.h"
#include "TextEditor.h"
@@ -3863,12 +3864,13 @@ void OutputPreview::Update()
video_recorder_->stop();
}
// verify the video broadcaster is valid (change to nullptr if invalid)
// verify the broadcasters are valid (change to nullptr if invalid)
FrameGrabbing::manager().verify( (FrameGrabber**) &video_broadcaster_);
FrameGrabbing::manager().verify( (FrameGrabber**) &shm_broadcaster_);
#if defined(LINUX)
// verify the frame grabber for webcam emulator is valid
FrameGrabbing::manager().verify(&webcam_emulator_);
FrameGrabbing::manager().verify( (FrameGrabber**) &webcam_emulator_);
#endif
}
@@ -3911,6 +3913,17 @@ void OutputPreview::ToggleBroadcast()
}
}
void OutputPreview::ToggleSharedMemory()
{
if (shm_broadcaster_) {
shm_broadcaster_->stop();
}
else {
shm_broadcaster_ = new ShmdataBroadcast;
FrameGrabbing::manager().add(shm_broadcaster_);
}
}
void OutputPreview::Render()
{
@@ -4096,41 +4109,69 @@ void OutputPreview::Render()
}
#endif
if (VideoBroadcast::available()) {
// Broadcasting menu
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.8f));
// Stop broadcast menu (broadcaster already exists)
if (video_broadcaster_) {
if ( ImGui::MenuItem( ICON_FA_SQUARE " Stop Broadcast SRT") )
video_broadcaster_->stop();
}
// start broadcast (broadcaster does not exists)
else {
if ( ImGui::MenuItem( ICON_FA_PODCAST " Broadcast SRT") ) {
video_broadcaster_ = new VideoBroadcast(Settings::application.broadcast_port);
FrameGrabbing::manager().add(video_broadcaster_);
}
}
ImGui::PopStyleColor(1);
}
// Stream sharing menu
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 " Peer-to-peer sharing", NULL, &Settings::application.accept_connections) ) {
Streaming::manager().enable(Settings::application.accept_connections);
}
ImGui::PopStyleColor(1);
if (Settings::application.accept_connections)
{
std::vector<std::string> ls = Streaming::manager().listStreams();
if (ls.size()>0) {
ImGui::Separator();
ImGui::MenuItem("Connected peers", nullptr, false, false);
for (auto it = ls.begin(); it != ls.end(); ++it)
ImGui::Text(" %s", (*it).c_str() );
// list active streams:
std::vector<std::string> ls = Streaming::manager().listStreams();
// Broadcasting menu
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.9f));
if (VideoBroadcast::available()) {
bool enabled = (video_broadcaster_!=nullptr);
if ( ImGui::MenuItem( ICON_FA_PODCAST " SRT Broadcast", NULL, &enabled) )
ToggleBroadcast();
}
// Shared Memory menu
if (ShmdataBroadcast::available()) {
bool enabled = (shm_broadcaster_!=nullptr);
if ( ImGui::MenuItem( ICON_FA_PROJECT_DIAGRAM " Shared Memory", NULL, &enabled) )
ToggleSharedMemory();
}
ImGui::PopStyleColor(1);
// Display list of active stream
if (ls.size()>0 || video_broadcaster_ || shm_broadcaster_) {
ImGui::Separator();
ImGui::MenuItem("Active streaming", nullptr, false, false);
// First the list of peer 2 peer
for (auto it = ls.begin(); it != ls.end(); ++it)
ImGui::Text(" %s ", (*it).c_str() );
// Second the SRT
if (video_broadcaster_) {
ImGui::Text(" %s ", video_broadcaster_->info().c_str());
// copy text icon to give user the srt link to connect to
ImVec2 draw_pos = ImGui::GetCursorPos();
ImGui::SetCursorPos(draw_pos + ImVec2(ImGui::GetContentRegionAvailWidth() - 1.2 * ImGui::GetTextLineHeightWithSpacing(), -0.8 * ImGui::GetFrameHeight()) );
char msg[256];
ImFormatString(msg, IM_ARRAYSIZE(msg), "srt//%s:%d", NetworkToolkit::host_ips()[1].c_str(), Settings::application.broadcast_port );
if (ImGuiToolkit::IconButton( ICON_FA_COPY, msg))
ImGui::SetClipboardText(msg);
ImGui::SetCursorPos(draw_pos);
}
// Third the SHMdata
if (shm_broadcaster_) {
ImGui::Text(" %s ", shm_broadcaster_->info().c_str());
// copy text icon to give user the socket path to connec to
ImVec2 draw_pos = ImGui::GetCursorPos();
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()))
ImGui::SetClipboardText(shm_broadcaster_->socket_path().c_str());
ImGui::SetCursorPos(draw_pos);
}
}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
@@ -4194,6 +4235,19 @@ void OutputPreview::Render()
ImGui::PopStyleColor(1);
ImGui::PopFont();
}
// shmdata indicator
if (shm_broadcaster_)
{
ImGui::SetCursorScreenPos(ImVec2(draw_pos.x + imagesize.x - 4.5f * r, draw_pos.y + r));
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE);
if (shm_broadcaster_->busy())
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.8f));
else
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.4f));
ImGui::Text(ICON_FA_PROJECT_DIAGRAM);
ImGui::PopStyleColor(1);
ImGui::PopFont();
}
// streaming indicator
if (Settings::application.accept_connections)
{
@@ -4239,6 +4293,7 @@ void OutputPreview::Render()
float h = 1.f;
h += (Settings::application.accept_connections ? 1.f : 0.f);
h += (video_broadcaster_ ? 1.f : 0.f);
h += (shm_broadcaster_ ? 1.f : 0.f);
draw_list->AddRectFilled(draw_pos, ImVec2(draw_pos.x + imagesize.x, draw_pos.y + h * r), IMGUI_COLOR_OVERLAY);
ImGui::SetCursorScreenPos(draw_pos);
ImGui::Text(" " ICON_FA_TV " %d x %d px, %.d fps", output->width(), output->height(), int(Mixer::manager().fps()) );
@@ -4248,6 +4303,8 @@ void OutputPreview::Render()
Streaming::manager().listStreams().size() );
if (video_broadcaster_)
ImGui::Text( " " ICON_FA_PODCAST " %s", video_broadcaster_->info().c_str() );
if (shm_broadcaster_)
ImGui::Text( " " ICON_FA_PROJECT_DIAGRAM " %s", shm_broadcaster_->info().c_str() );
}
ImGui::End();
@@ -5872,6 +5929,7 @@ void ShaderEditor::Render()
{
filters_.clear();
current_ = nullptr;
_editor.SetText("");
}
// if compiling, cannot change source nor do anything else
@@ -7800,8 +7858,16 @@ void Navigator::RenderMainPannelSettings()
//
// Networking preferences
//
ImGuiToolkit::Spacing();
ImGui::Text("Stream");
ImGuiToolkit::Indication("Peer-to-peer sharing on local network\n\n"
"vimix can stream JPEG (default) or H264 (requires less bandwidth but more resources for encoding)", ICON_FA_SHARE_ALT_SQUARE);
ImGui::SameLine(0);
ImGui::SetCursorPosX(-1.f * IMGUI_RIGHT_ALIGN);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::Combo("Share P2P", &Settings::application.stream_protocol, "JPEG\0H264\0");
if (VideoBroadcast::available()) {
char msg[256];
ImFormatString(msg, IM_ARRAYSIZE(msg), "Broadcast SRT\n\n"
@@ -7819,20 +7885,13 @@ void Navigator::RenderMainPannelSettings()
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
char bufport[7] = "";
sprintf(bufport, "%d", Settings::application.broadcast_port);
ImGui::InputTextWithHint("Broadcast", "7070", bufport, 6, ImGuiInputTextFlags_CharsDecimal);
ImGui::InputTextWithHint("Port SRT", "7070", bufport, 6, ImGuiInputTextFlags_CharsDecimal);
if (ImGui::IsItemDeactivatedAfterEdit()){
if ( BaseToolkit::is_a_number(bufport, &Settings::application.broadcast_port))
Settings::application.broadcast_port = CLAMP(Settings::application.broadcast_port, 1029, 49150);
}
}
ImGuiToolkit::Indication("Peer-to-peer sharing on local network\n\n"
"vimix can stream JPEG (default) or H264 (requires less bandwidth but more resources for encoding)", ICON_FA_SHARE_ALT_SQUARE);
ImGui::SameLine(0);
ImGui::SetCursorPosX(-1.f * IMGUI_RIGHT_ALIGN);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::Combo("P2P Share", &Settings::application.stream_protocol, "JPEG\0H264\0");
//
// OSC preferences
//

View File

@@ -110,6 +110,7 @@ class FrameBufferImage;
class FrameGrabber;
class VideoRecorder;
class VideoBroadcast;
class ShmdataBroadcast;
class SourcePreview {
@@ -330,6 +331,7 @@ class OutputPreview : public WorkspaceWindow
// frame grabbers
VideoRecorder *video_recorder_;
VideoBroadcast *video_broadcaster_;
ShmdataBroadcast *shm_broadcaster_;
// delayed trigger for recording
std::vector< std::future<VideoRecorder *> > _video_recorders;
@@ -350,6 +352,9 @@ public:
void ToggleBroadcast();
inline bool isBroadcasting() const { return video_broadcaster_ != nullptr; }
void ToggleSharedMemory();
inline bool isSharingMemory() const { return shm_broadcaster_ != nullptr; }
void Render();
void setVisible(bool on);

View File

@@ -27,9 +27,9 @@ std::vector< std::pair<std::string, std::string> > pipeline_sink_ {
};
std::vector< std::pair<std::string, std::string> > pipeline_encoder_ {
{"nvh264enc", "nvh264enc zerolatency=true rc-mode=cbr-ld-hq bitrate=4000 ! video/x-h264, profile=(string)high ! h264parse config-interval=1 ! mpegtsmux ! queue ! "},
{"vaapih264enc", "vaapih264enc rate-control=cqp init-qp=26 ! video/x-h264, profile=high ! h264parse config-interval=1 ! mpegtsmux ! queue ! "},
{"x264enc", "x264enc tune=zerolatency ! video/x-h264, profile=high ! mpegtsmux ! "}
{"nvh264enc", "nvh264enc zerolatency=true rc-mode=cbr-ld-hq bitrate=4000 ! "},
{"vaapih264enc", "vaapih264enc rate-control=cqp init-qp=26 ! "},
{"x264enc", "x264enc tune=zerolatency ! "}
};
bool VideoBroadcast::available()
@@ -76,18 +76,21 @@ VideoBroadcast::VideoBroadcast(int port): FrameGrabber(), port_(port), stopped_(
std::string VideoBroadcast::init(GstCaps *caps)
{
if (!VideoBroadcast::available())
return std::string("Video Broadcast : Not available (missing SRT or H264)");
// ignore
if (caps == nullptr)
return std::string("Video Broadcast : Invalid caps");
if (!VideoBroadcast::available())
return std::string("Video Broadcast : Not available (missing SRT or H264)");
// create a gstreamer pipeline
std::string description = "appsrc name=src ! videoconvert ! ";
// complement pipeline with encoder and sink
// complement pipeline with encoder
description += VideoBroadcast::h264_encoder_;
description += "video/x-h264, profile=high ! queue ! h264parse config-interval=-1 ! mpegtsmux ! ";
// complement pipeline with sink
description += VideoBroadcast::srt_sink_;
// change the placeholder to include the broadcast port
@@ -192,11 +195,11 @@ std::string VideoBroadcast::info() const
std::ostringstream ret;
if (!initialized_)
ret << "Starting SRT";
ret << "SRT starting..";
else if (active_)
ret << "Broadcasting on SRT (listener mode)";
ret << "SRT Broadcast on port " << port_;
else
ret << "SRT Terminated";
ret << "SRT terminated";
return ret.str();
}

View File

@@ -82,7 +82,7 @@
#define IMGUI_COLOR_CAPTURE 1.0, 0.55, 0.05
#define IMGUI_COLOR_RECORD 1.0, 0.05, 0.05
#define IMGUI_COLOR_STREAM 0.05, 0.8, 1.0
#define IMGUI_COLOR_BROADCAST 0.1, 0.9, 0.1
#define IMGUI_COLOR_BROADCAST 0.1, 0.5, 1.0
#define IMGUI_NOTIFICATION_DURATION 2.5f
#define IMGUI_TOOLTIP_TIMEOUT 80