From 7c90feb3f7fd0b9badefb6dece62a7eca13747f2 Mon Sep 17 00:00:00 2001 From: cxh Date: Thu, 22 Jan 2026 09:29:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BD=95=E5=83=8F=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/app_config.hpp | 4 ++++ include/rtmp_manager.hpp | 4 ++++ src/main.cpp | 2 ++ src/rtmp_manager.cpp | 43 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/app_config.hpp b/include/app_config.hpp index 6ae180b..267d0c5 100644 --- a/include/app_config.hpp +++ b/include/app_config.hpp @@ -73,6 +73,7 @@ struct MQTTConfig // ------------------- 总配置 ------------------- struct AppConfig { + bool record_enabled = true; std::vector cameras; MQTTConfig mqtt; @@ -90,6 +91,9 @@ struct AppConfig json j; ifs >> j; + cfg.record_enabled = j.value("record_enabled", true); + LOG_INFO("[Config] Global record_enabled = " + std::string(cfg.record_enabled ? "true" : "false")); + // 读取摄像头 if (j.contains("cameras")) { diff --git a/include/rtmp_manager.hpp b/include/rtmp_manager.hpp index 01c08c5..6757098 100644 --- a/include/rtmp_manager.hpp +++ b/include/rtmp_manager.hpp @@ -47,6 +47,8 @@ class RTMPManager static void set_live_enabled_all(bool enable); static void set_live_enabled(const std::string& cam_name, bool enable); + static bool g_record_enabled; + private: struct StreamContext { @@ -57,6 +59,7 @@ class RTMPManager std::mutex status_mutex; GstElement* live_valve{nullptr}; + GstElement* record_valve = nullptr; }; static void stream_loop(Camera cam, StreamContext* ctx); @@ -65,6 +68,7 @@ class RTMPManager static std::unordered_map> streams; static std::mutex streams_mutex; + static std::atomic g_live_enabled; static constexpr int RETRY_BASE_DELAY_MS = 3000; diff --git a/src/main.cpp b/src/main.cpp index 54adbb1..bdf03a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,6 +61,8 @@ int main() // ---------- 初始化 GStreamer ---------- RTMPManager::init(); + RTMPManager::g_record_enabled = g_app_config.record_enabled; + // ---------- 自动推流(8 路录像守护) ---------- LOG_INFO("[MAIN] Starting all record streams..."); RTMPManager::start_all(); diff --git a/src/rtmp_manager.cpp b/src/rtmp_manager.cpp index 95e02d1..7acc692 100644 --- a/src/rtmp_manager.cpp +++ b/src/rtmp_manager.cpp @@ -12,6 +12,7 @@ #include std::atomic RTMPManager::g_live_enabled{false}; +bool RTMPManager::g_record_enabled = true; // ======================================================= // 工具函数 @@ -89,8 +90,10 @@ GstElement* RTMPManager::create_pipeline(const Camera& cam) "! h264parse config-interval=1 " "! tee name=t " - // ===== record:永远稳定 ===== + // ===== record:可开关 ===== "t. ! queue max-size-buffers=8 leaky=downstream " + "! valve name=record_valve drop=true " // ★★ 新增 + "! queue max-size-buffers=8 leaky=downstream " "! flvmux name=rec_mux streamable=true " "! rtmpsink name=rec_sink location=\"" + record_rtmp + @@ -173,6 +176,30 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) ctx->live_valve = live_valve; // ⚠️ live_valve 引用交给 ctx 管理 } + // 2.x 获取 record_valve + GstElement* record_valve = gst_bin_get_by_name(GST_BIN(pipeline), "record_valve"); + if (!record_valve) + { + { + std::lock_guard lk(ctx->status_mutex); + ctx->status.running = false; + ctx->status.last_error = "record_valve not found"; + } + LOG_ERROR("[RTMP] " + key + " - record_valve not found"); + gst_object_unref(pipeline); + std::this_thread::sleep_for(std::chrono::seconds(3)); + continue; + } + + // 保存到 ctx + { + std::lock_guard lk(ctx->status_mutex); + if (ctx->record_valve) gst_object_unref(ctx->record_valve); + ctx->record_valve = record_valve; + } + + g_object_set(G_OBJECT(ctx->record_valve), "drop", g_record_enabled.load() ? FALSE : TRUE, nullptr); + g_object_set(G_OBJECT(ctx->live_valve), "drop", g_live_enabled.load() ? FALSE : TRUE, nullptr); GstBus* bus = gst_element_get_bus(pipeline); @@ -248,11 +275,18 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) cleanup: { std::lock_guard lk(ctx->status_mutex); + if (ctx->live_valve) { gst_object_unref(ctx->live_valve); ctx->live_valve = nullptr; } + + if (ctx->record_valve) + { + gst_object_unref(ctx->record_valve); + ctx->record_valve = nullptr; + } } gst_element_set_state(pipeline, GST_STATE_NULL); @@ -317,11 +351,18 @@ void RTMPManager::stop_all() kv.second->thread_running.store(false); std::lock_guard lk(kv.second->status_mutex); + if (kv.second->live_valve) { gst_object_unref(kv.second->live_valve); kv.second->live_valve = nullptr; } + + if (kv.second->record_valve) + { + gst_object_unref(kv.second->record_valve); + kv.second->record_valve = nullptr; + } } for (auto& kv : streams)