From 08114e2cbe324d965fe6c6cd3820c42a70823419 Mon Sep 17 00:00:00 2001 From: brunoherbelin Date: Sun, 9 Nov 2025 11:38:01 +0100 Subject: [PATCH] Implement broadcast manager functionality and enhance FrameGrabber info and type methods --- src/ControlManager.cpp | 11 ++++ src/ControlManager.h | 2 + src/FrameGrabber.cpp | 106 +++++++++++++++++++++++++++++++++++- src/FrameGrabber.h | 48 +++++++++++++++- src/Loopback.cpp | 19 ++++--- src/Loopback.h | 4 +- src/OutputPreviewWindow.cpp | 81 ++++++++++++--------------- src/OutputPreviewWindow.h | 12 +--- src/Recorder.cpp | 5 +- src/Recorder.h | 6 +- src/ShmdataBroadcast.cpp | 19 ++++--- src/ShmdataBroadcast.h | 4 +- src/Streamer.cpp | 25 ++++++--- src/Streamer.h | 4 +- src/VideoBroadcast.cpp | 23 +++++--- src/VideoBroadcast.h | 4 +- 16 files changed, 281 insertions(+), 92 deletions(-) diff --git a/src/ControlManager.cpp b/src/ControlManager.cpp index 226f319..506032c 100644 --- a/src/ControlManager.cpp +++ b/src/ControlManager.cpp @@ -42,6 +42,7 @@ #include "NetworkToolkit.h" #include "UserInterfaceManager.h" #include "Streamer.h" +#include "VideoBroadcast.h" #include "ControlManager.h" @@ -605,6 +606,16 @@ bool Control::receiveOutputAttribute(const std::string &attribute, Mixer::manager().session()->setFadingTarget( Mixer::manager().session()->fading() + f * 0.01); need_feedback = true; } + else if ( attribute.compare(OSC_OUTPUT_SRT_START) == 0) { + float f = (float) Settings::application.broadcast_port; + // if argument is given, it is the connection port + if (!arguments.Eos()) + arguments >> f >> osc::EndMessage; + Broadcast::manager().start( new VideoBroadcast((int) f), true); + } + else if ( attribute.compare(OSC_OUTPUT_SRT_STOP) == 0) { + Broadcast::manager().stop(FrameGrabber::GRABBER_BROADCAST); + } // inform of invalid attribute name else { Log::Info(CONTROL_OSC_MSG "Unknown attribute '%s' for target 'output'", attribute.c_str()); diff --git a/src/ControlManager.h b/src/ControlManager.h index 02effe3..2ba62f5 100644 --- a/src/ControlManager.h +++ b/src/ControlManager.h @@ -24,6 +24,8 @@ #define OSC_OUTPUT_FADING "/fading" #define OSC_OUTPUT_FADE_IN "/fade-in" #define OSC_OUTPUT_FADE_OUT "/fade-out" +#define OSC_OUTPUT_SRT_START "/srt-start" +#define OSC_OUTPUT_SRT_STOP "/srt-stop" #define OSC_ALL "/all" #define OSC_SELECTION "/selection" diff --git a/src/FrameGrabber.cpp b/src/FrameGrabber.cpp index 5d85c89..6499451 100644 --- a/src/FrameGrabber.cpp +++ b/src/FrameGrabber.cpp @@ -106,6 +106,28 @@ FrameGrabber *FrameGrabbing::get(uint64_t id) return nullptr; } +struct fgType +{ + inline bool operator()(const FrameGrabber* elem) const { + return (elem && elem->type() == _t); + } + explicit fgType(FrameGrabber::Type t) : _t(t) { } +private: + FrameGrabber::Type _t; +}; + +FrameGrabber *FrameGrabbing::get(FrameGrabber::Type t) +{ + if (grabbers_.size() > 0 ) + { + std::list::iterator iter = std::find_if(grabbers_.begin(), grabbers_.end(), fgType(t)); + if (iter != grabbers_.end()) + return (*iter); + } + + return nullptr; +} + void FrameGrabbing::stopAll() { std::list::iterator iter; @@ -349,8 +371,37 @@ void FrameGrabber::stop () } -std::string FrameGrabber::info() const +std::string FrameGrabber::info(bool extended) const { + if (extended) { + std::string typestring; + switch ( type() ) + { + case GRABBER_PNG : + typestring = "Portable Network Graphics frame grabber"; + break; + case GRABBER_VIDEO : + typestring = "Video file frame grabber"; + break; + case GRABBER_P2P : + typestring = "Peer-to-Peer stream frame grabber"; + break; + case GRABBER_BROADCAST : + typestring = "SRT Broarcast frame grabber"; + break; + case GRABBER_SHM : + typestring = "Shared Memory frame grabber"; + break; + case GRABBER_LOOPBACK : + typestring = "Loopback frame grabber"; + break; + default: + typestring = "Generic frame grabber"; + break; + } + return typestring; + } + if (!initialized_) return "Initializing"; if (active_) @@ -603,3 +654,56 @@ guint64 FrameGrabber::frames() const { return frame_count_; } + + +uint64_t Broadcast::start(FrameGrabber *ptr, bool singleton) +{ + if (singleton) + stop( ptr->type() ); + + uint64_t b = ptr->id(); + FrameGrabbing::manager().add(ptr); + return b; +} + +bool Broadcast::enabled(uint64_t b) +{ + return ( FrameGrabbing::manager().get(b) != nullptr); +} + +bool Broadcast::busy(uint64_t b) +{ + FrameGrabber *ptr = FrameGrabbing::manager().get(b); + if (ptr != nullptr) + return ptr->busy(); + + return false; +} + +std::string Broadcast::info(uint64_t b, bool extended) +{ + FrameGrabber *ptr = FrameGrabbing::manager().get(b); + if (ptr != nullptr) + return ptr->info(extended); + + return "Disabled"; +} + +void Broadcast::stop(uint64_t b) +{ + FrameGrabber *ptr = FrameGrabbing::manager().get(b); + if (ptr != nullptr) + ptr->stop(); + +} + +void Broadcast::stop(FrameGrabber::Type T) +{ + FrameGrabber *prev = nullptr; + do { + prev = FrameGrabbing::manager().get( T ); + if (prev != nullptr) + prev->stop(); + } + while (prev != nullptr); +} diff --git a/src/FrameGrabber.h b/src/FrameGrabber.h index 3853436..ec2a2fa 100644 --- a/src/FrameGrabber.h +++ b/src/FrameGrabber.h @@ -40,9 +40,22 @@ public: virtual ~FrameGrabber(); inline uint64_t id() const { return id_; } + + // types of sub-classes of FrameGrabber + typedef enum { + GRABBER_GENERIC = 0, + GRABBER_PNG = 1, + GRABBER_VIDEO = 2, + GRABBER_P2P, + GRABBER_BROADCAST, + GRABBER_SHM, + GRABBER_LOOPBACK, + GRABBER_INVALID + } Type; + virtual Type type () const { return GRABBER_GENERIC; } virtual void stop(); - virtual std::string info() const; + virtual std::string info(bool extended = false) const; virtual uint64_t duration() const; virtual bool finished() const; virtual bool busy() const; @@ -133,6 +146,7 @@ public: void verify(FrameGrabber **rec); bool busy() const; FrameGrabber *get(uint64_t id); + FrameGrabber *get(FrameGrabber::Type t); void stopAll(); void clearAll(); @@ -154,6 +168,38 @@ private: GstCaps *caps_; }; +/** + * @brief The Broadcast class gives a global access to launch and stop FrameGrabbers + * + * FrameGrabbers can terminate (normal behavior or failure) and the FrameGrabber + * is deleted automatically; pointer is then invalid and cannot be accessed. To avoid this, + * the Broadcast::manager() gives access to FrameGrabbers by id. + * + * Singleton mechanism also allows starting a unique instance of each FrameGrabber::Type + */ +class Broadcast +{ + // Private Constructor + Broadcast() {}; + Broadcast(Broadcast const& copy) = delete; + Broadcast& operator=(Broadcast const& copy) = delete; + +public: + + static Broadcast& manager () + { + // The only instance + static Broadcast _instance; + return _instance; + } + + uint64_t start(FrameGrabber *ptr, bool singleton = false); + bool enabled(uint64_t); + bool busy(uint64_t); + std::string info(uint64_t, bool extended = false); + void stop(uint64_t); + void stop(FrameGrabber::Type); +}; #endif // FRAMEGRABBER_H diff --git a/src/Loopback.cpp b/src/Loopback.cpp index bdd1b4c..9fef0af 100644 --- a/src/Loopback.cpp +++ b/src/Loopback.cpp @@ -175,16 +175,21 @@ void Loopback::stop () active_ = false; } -std::string Loopback::info() const +std::string Loopback::info(bool extended) const { std::ostringstream ret; - if (!initialized_) - ret << "Loopback starting.."; - else if (active_) - ret << "V4L2 Loopback on " << device_name(); - else - ret << "Loopback terminated"; + if (extended) { + ret << device_name(); + } + else { + if (!initialized_) + ret << "Loopback starting.."; + else if (active_) + ret << "V4L2 Loopback on " << device_name(); + else + ret << "Loopback terminated"; + } return ret.str(); } diff --git a/src/Loopback.h b/src/Loopback.h index e92f784..80364db 100644 --- a/src/Loopback.h +++ b/src/Loopback.h @@ -12,13 +12,15 @@ public: Loopback(int deviceid = LOOPBACK_DEFAULT_DEVICE); virtual ~Loopback() {} + FrameGrabber::Type type () const override { return FrameGrabber::GRABBER_LOOPBACK; } + static bool available(); inline int device_id() const { return loopback_device_; } std::string device_name() const; void stop() override; - std::string info() const override; + std::string info(bool extended = false) const override; private: std::string init(GstCaps *caps) override; diff --git a/src/OutputPreviewWindow.cpp b/src/OutputPreviewWindow.cpp index c9f9ea3..7c662b0 100644 --- a/src/OutputPreviewWindow.cpp +++ b/src/OutputPreviewWindow.cpp @@ -41,7 +41,7 @@ OutputPreviewWindow::OutputPreviewWindow() : WorkspaceWindow("OutputPreview"), - video_recorder_(nullptr), video_broadcaster_(nullptr), loopback_broadcaster_(nullptr), + video_recorder_(nullptr), srt_(0), shm_(0), loopback_(0), magnifying_glass(false) { @@ -96,11 +96,6 @@ void OutputPreviewWindow::Update() video_recorder_->stop(); } - // verify the frame grabbers are valid (change to nullptr if invalid) - FrameGrabbing::manager().verify( (FrameGrabber**) &video_broadcaster_); - FrameGrabbing::manager().verify( (FrameGrabber**) &shm_broadcaster_); - FrameGrabbing::manager().verify( (FrameGrabber**) &loopback_broadcaster_); - } VideoRecorder *delayTrigger(VideoRecorder *g, std::chrono::milliseconds delay) { @@ -140,22 +135,19 @@ void OutputPreviewWindow::ToggleRecordPause() void OutputPreviewWindow::ToggleVideoBroadcast() { - if (video_broadcaster_) { - video_broadcaster_->stop(); - } + if (Broadcast::manager().enabled(srt_) ) + Broadcast::manager().stop(srt_); else { if (Settings::application.broadcast_port<1000) Settings::application.broadcast_port = BROADCAST_DEFAULT_PORT; - video_broadcaster_ = new VideoBroadcast(Settings::application.broadcast_port); - FrameGrabbing::manager().add(video_broadcaster_); + srt_ = Broadcast::manager().start( new VideoBroadcast(Settings::application.broadcast_port), true); } } void OutputPreviewWindow::ToggleSharedMemory() { - if (shm_broadcaster_) { - shm_broadcaster_->stop(); - } + if (Broadcast::manager().enabled(shm_) ) + Broadcast::manager().stop(shm_); else { // find a folder to put the socket for shm std::string _shm_socket_file = Settings::application.shm_socket_path; @@ -164,25 +156,22 @@ void OutputPreviewWindow::ToggleSharedMemory() _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_); + shm_ = Broadcast::manager().start( new ShmdataBroadcast( (ShmdataBroadcast::Method) Settings::application.shm_method, _shm_socket_file), true); } } bool OutputPreviewWindow::ToggleLoopbackCamera() { bool need_initialization = false; - if (loopback_broadcaster_) { - loopback_broadcaster_->stop(); - } + if (Broadcast::manager().enabled(loopback_)) + Broadcast::manager().stop(loopback_); else { if (Settings::application.loopback_camera < 1) Settings::application.loopback_camera = LOOPBACK_DEFAULT_DEVICE; Settings::application.loopback_camera += Settings::application.instance_id; try { - loopback_broadcaster_ = new Loopback(Settings::application.loopback_camera); - FrameGrabbing::manager().add(loopback_broadcaster_); + loopback_ = Broadcast::manager().start( new Loopback(Settings::application.loopback_camera), true ); } catch (const std::runtime_error &e) { need_initialization = true; @@ -400,26 +389,27 @@ void OutputPreviewWindow::Render() // Broadcasting menu ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.9f)); if (VideoBroadcast::available()) { - if ( ImGui::MenuItem( ICON_FA_GLOBE " SRT Broadcast", NULL, videoBroadcastEnabled()) ) + if ( ImGui::MenuItem( ICON_FA_GLOBE " SRT Broadcast", NULL, Broadcast::manager().enabled(srt_) ) ) ToggleVideoBroadcast(); } // Shared Memory menu if (ShmdataBroadcast::available()) { - if ( ImGui::MenuItem( ICON_FA_MEMORY " SHM Shared Memory", NULL, sharedMemoryEnabled()) ) + if ( ImGui::MenuItem( ICON_FA_MEMORY " SHM Shared Memory", NULL, Broadcast::manager().enabled(shm_) ) ) ToggleSharedMemory(); } // Loopback camera menu if (Loopback::available()) { - if ( ImGui::MenuItem( ICON_FA_VIDEO " Loopback Camera", NULL, loopbackCameraEnabled()) ) + if ( ImGui::MenuItem( ICON_FA_VIDEO " Loopback Camera", NULL, Broadcast::manager().enabled(loopback_)) ) openInitializeSystemLoopback = ToggleLoopbackCamera(); } ImGui::PopStyleColor(1); // Display list of active stream - if (ls.size()>0 || videoBroadcastEnabled() || sharedMemoryEnabled() || loopbackCameraEnabled()) { + if (ls.size()>0 || Broadcast::manager().enabled(srt_) || + Broadcast::manager().enabled(shm_) || Broadcast::manager().enabled(loopback_)) { ImGui::Separator(); ImGui::MenuItem("Active streams:", nullptr, false, false); @@ -428,37 +418,38 @@ void OutputPreviewWindow::Render() ImGui::Text(" %s ", (*it).c_str() ); // SRT broadcast description - if (videoBroadcastEnabled()) { - ImGui::Text(" %s ", video_broadcaster_->info().c_str()); + if (Broadcast::manager().enabled(srt_)) { + ImGui::Text(" %s ", Broadcast::manager().info(srt_).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); + std::string moreinfo = Broadcast::manager().info(srt_, true); + if (ImGuiToolkit::IconButton( ICON_FA_COPY, moreinfo.c_str())) + ImGui::SetClipboardText(moreinfo.c_str()); ImGui::SetCursorPos(draw_pos); } // Shared memory broadcast description - if (sharedMemoryEnabled()) { - ImGui::Text(" %s ", shm_broadcaster_->info().c_str()); + if (Broadcast::manager().enabled(shm_)) { + ImGui::Text(" %s ", Broadcast::manager().info(shm_).c_str()); // copy text icon to give user the socket path to connect 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_->gst_pipeline().c_str())) - ImGui::SetClipboardText(shm_broadcaster_->gst_pipeline().c_str()); + std::string moreinfo = Broadcast::manager().info(shm_, true); + if (ImGuiToolkit::IconButton( ICON_FA_COPY, moreinfo.c_str())) + ImGui::SetClipboardText(moreinfo.c_str()); ImGui::SetCursorPos(draw_pos); } // Loopback camera description - if (loopbackCameraEnabled()) { - ImGui::Text(" %s ", loopback_broadcaster_->info().c_str()); + if (Broadcast::manager().enabled(loopback_)) { + ImGui::Text(" %s ", Broadcast::manager().info(loopback_).c_str()); // copy text icon to give user the device path to connect 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, loopback_broadcaster_->device_name().c_str())) - ImGui::SetClipboardText(loopback_broadcaster_->device_name().c_str()); + std::string moreinfo = Broadcast::manager().info(loopback_, true); + if (ImGuiToolkit::IconButton( ICON_FA_COPY, moreinfo.c_str())) + ImGui::SetClipboardText(moreinfo.c_str()); ImGui::SetCursorPos(draw_pos); } } @@ -558,10 +549,10 @@ void OutputPreviewWindow::Render() } // broadcast indicator float vertical = r; - if (video_broadcaster_) + if (Broadcast::manager().enabled(srt_)) { ImGui::SetCursorScreenPos(ImVec2(draw_pos.x + imagesize.x - 2.5f * r, draw_pos.y + vertical)); - if (video_broadcaster_->busy()) + if (Broadcast::manager().busy(srt_)) ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.8f)); else ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.4f)); @@ -570,10 +561,10 @@ void OutputPreviewWindow::Render() vertical += 2.f * r; } // shmdata indicator - if (shm_broadcaster_) + if (Broadcast::manager().enabled(shm_)) { ImGui::SetCursorScreenPos(ImVec2(draw_pos.x + imagesize.x - 2.5f * r, draw_pos.y + vertical)); - if (shm_broadcaster_->busy()) + if (Broadcast::manager().busy(shm_)) ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.8f)); else ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.4f)); @@ -582,10 +573,10 @@ void OutputPreviewWindow::Render() vertical += 2.f * r; } // loopback camera indicator - if (loopback_broadcaster_) + if (Broadcast::manager().enabled(loopback_)) { ImGui::SetCursorScreenPos(ImVec2(draw_pos.x + imagesize.x - 2.5f * r, draw_pos.y + vertical)); - if (loopback_broadcaster_->busy()) + if (Broadcast::manager().busy(loopback_)) ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.8f)); else ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_BROADCAST, 0.4f)); diff --git a/src/OutputPreviewWindow.h b/src/OutputPreviewWindow.h index 3b5e26c..75b15bb 100644 --- a/src/OutputPreviewWindow.h +++ b/src/OutputPreviewWindow.h @@ -5,7 +5,6 @@ #include "WorkspaceWindow.h" class VideoRecorder; -class VideoBroadcast; class ShmdataBroadcast; class Loopback; @@ -13,9 +12,9 @@ class OutputPreviewWindow : public WorkspaceWindow { // frame grabbers VideoRecorder *video_recorder_; - VideoBroadcast *video_broadcaster_; - ShmdataBroadcast *shm_broadcaster_; - Loopback *loopback_broadcaster_; + uint64_t srt_; + uint64_t shm_; + uint64_t loopback_; // delayed trigger for recording std::vector< std::future > _video_recorders; @@ -34,13 +33,8 @@ public: inline bool isRecording() const { return video_recorder_ != nullptr; } void ToggleVideoBroadcast(); - inline bool videoBroadcastEnabled() const { return video_broadcaster_ != nullptr; } - void ToggleSharedMemory(); - inline bool sharedMemoryEnabled() const { return shm_broadcaster_ != nullptr; } - bool ToggleLoopbackCamera(); - inline bool loopbackCameraEnabled() const { return loopback_broadcaster_!= nullptr; } void Render(); void setVisible(bool on); diff --git a/src/Recorder.cpp b/src/Recorder.cpp index edb70b9..f0aa4cb 100644 --- a/src/Recorder.cpp +++ b/src/Recorder.cpp @@ -516,8 +516,11 @@ void VideoRecorder::terminate() Settings::application.recentRecordings.remove(filename_); } -std::string VideoRecorder::info() const +std::string VideoRecorder::info(bool extended) const { + if (extended) + return filename(); + if (initialized_ && !active_ && !endofstream_) return "Saving file..."; diff --git a/src/Recorder.h b/src/Recorder.h index c4e138a..ab8a13c 100644 --- a/src/Recorder.h +++ b/src/Recorder.h @@ -20,6 +20,8 @@ public: PNGRecorder(const std::string &basename = std::string()); std::string filename() const { return filename_; } + FrameGrabber::Type type () const override { return FrameGrabber::GRABBER_PNG; } + protected: std::string init(GstCaps *caps) override; @@ -60,7 +62,9 @@ public: static const int framerate_preset_value[3]; VideoRecorder(const std::string &basename = std::string()); - std::string info() const override; + FrameGrabber::Type type () const override { return FrameGrabber::GRABBER_VIDEO; } + + std::string info(bool extended = false) const override; std::string filename() const { return filename_; } }; diff --git a/src/ShmdataBroadcast.cpp b/src/ShmdataBroadcast.cpp index 6ba73bd..8a706a4 100644 --- a/src/ShmdataBroadcast.cpp +++ b/src/ShmdataBroadcast.cpp @@ -203,16 +203,21 @@ std::string ShmdataBroadcast::gst_pipeline() const return pipeline; } -std::string ShmdataBroadcast::info() const +std::string ShmdataBroadcast::info(bool extended) const { std::ostringstream ret; - if (!initialized_) - ret << "Shared Memory starting.."; - else if (active_) - ret << "Shared Memory " << socket_path_; - else - ret << "Shared Memory terminated"; + if (extended) { + ret << gst_pipeline(); + } + else { + if (!initialized_) + ret << "Shared Memory starting.."; + else if (active_) + ret << "Shared Memory " << socket_path_; + else + ret << "Shared Memory terminated"; + } return ret.str(); } diff --git a/src/ShmdataBroadcast.h b/src/ShmdataBroadcast.h index cf4fec0..0ffb4ba 100644 --- a/src/ShmdataBroadcast.h +++ b/src/ShmdataBroadcast.h @@ -19,13 +19,15 @@ public: ShmdataBroadcast(Method m = SHM_SHMSINK, const std::string &socketpath = ""); virtual ~ShmdataBroadcast() {} + FrameGrabber::Type type () const override { return FrameGrabber::GRABBER_SHM; } + static bool available(Method m = SHM_SHMDATAANY); inline Method method() const { return method_; } inline std::string socket_path() const { return socket_path_; } std::string gst_pipeline() const; - std::string info() const override; + std::string info(bool extended = false) const override; private: std::string init(GstCaps *caps) override; diff --git a/src/Streamer.cpp b/src/Streamer.cpp index 17973cc..3fc4ccb 100644 --- a/src/Streamer.cpp +++ b/src/Streamer.cpp @@ -516,17 +516,24 @@ void VideoStreamer::stop () active_ = false; } -std::string VideoStreamer::info() const +std::string VideoStreamer::info(bool extended) const { std::ostringstream ret; - if (!initialized_) - ret << "Connecting"; - else if (active_) { - ret << NetworkToolkit::stream_protocol_label[config_.protocol]; - ret << " to "; - ret << config_.client_name; + + if (extended) { + ret << NetworkToolkit::stream_send_pipeline[config_.protocol]; } - else - ret << "Streaming terminated."; + else { + if (!initialized_) + ret << "Connecting"; + else if (active_) { + ret << NetworkToolkit::stream_protocol_label[config_.protocol]; + ret << " to "; + ret << config_.client_name; + } + else + ret << "Streaming terminated."; + } + return ret.str(); } diff --git a/src/Streamer.h b/src/Streamer.h index 3e09914..0aae4f0 100644 --- a/src/Streamer.h +++ b/src/Streamer.h @@ -81,7 +81,9 @@ public: VideoStreamer(const NetworkToolkit::StreamConfig &conf); virtual ~VideoStreamer() {} - std::string info() const override; + + FrameGrabber::Type type () const override { return FrameGrabber::GRABBER_P2P; } + std::string info(bool extended = false) const override; }; diff --git a/src/VideoBroadcast.cpp b/src/VideoBroadcast.cpp index 6180069..e662629 100644 --- a/src/VideoBroadcast.cpp +++ b/src/VideoBroadcast.cpp @@ -29,6 +29,7 @@ #include "Log.h" #include "GstToolkit.h" +#include "NetworkToolkit.h" #include "Settings.h" #include "VideoBroadcast.h" @@ -210,16 +211,24 @@ void VideoBroadcast::stop () active_ = false; } -std::string VideoBroadcast::info() const +std::string VideoBroadcast::info(bool extended) const { std::ostringstream ret; - if (!initialized_) - ret << "SRT starting.."; - else if (active_) - ret << "SRT Broadcast on port " << port_; - else - ret << "SRT terminated"; + if (extended) { + ret << "srt://"; + ret << NetworkToolkit::host_ips()[1]; + ret << ":"; + ret << port_; + } + else { + if (!initialized_) + ret << "SRT starting.."; + else if (active_) + ret << "SRT Broadcast on port " << port_; + else + ret << "SRT terminated"; + } return ret.str(); } diff --git a/src/VideoBroadcast.h b/src/VideoBroadcast.h index 91f9558..b208c3d 100644 --- a/src/VideoBroadcast.h +++ b/src/VideoBroadcast.h @@ -14,11 +14,13 @@ public: VideoBroadcast(int port = BROADCAST_DEFAULT_PORT); virtual ~VideoBroadcast() {} + FrameGrabber::Type type () const override { return FrameGrabber::GRABBER_BROADCAST; } + static bool available(); inline int port() const { return port_; } void stop() override; - std::string info() const override; + std::string info(bool extended = false) const override; private: std::string init(GstCaps *caps) override;