新增录像功能开关
This commit is contained in:
parent
2cdd2d4f4f
commit
7c90feb3f7
@ -73,6 +73,7 @@ struct MQTTConfig
|
|||||||
// ------------------- 总配置 -------------------
|
// ------------------- 总配置 -------------------
|
||||||
struct AppConfig
|
struct AppConfig
|
||||||
{
|
{
|
||||||
|
bool record_enabled = true;
|
||||||
std::vector<Camera> cameras;
|
std::vector<Camera> cameras;
|
||||||
MQTTConfig mqtt;
|
MQTTConfig mqtt;
|
||||||
|
|
||||||
@ -90,6 +91,9 @@ struct AppConfig
|
|||||||
json j;
|
json j;
|
||||||
ifs >> 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"))
|
if (j.contains("cameras"))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -47,6 +47,8 @@ class RTMPManager
|
|||||||
static void set_live_enabled_all(bool enable);
|
static void set_live_enabled_all(bool enable);
|
||||||
static void set_live_enabled(const std::string& cam_name, bool enable);
|
static void set_live_enabled(const std::string& cam_name, bool enable);
|
||||||
|
|
||||||
|
static bool g_record_enabled;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct StreamContext
|
struct StreamContext
|
||||||
{
|
{
|
||||||
@ -57,6 +59,7 @@ class RTMPManager
|
|||||||
std::mutex status_mutex;
|
std::mutex status_mutex;
|
||||||
|
|
||||||
GstElement* live_valve{nullptr};
|
GstElement* live_valve{nullptr};
|
||||||
|
GstElement* record_valve = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void stream_loop(Camera cam, StreamContext* ctx);
|
static void stream_loop(Camera cam, StreamContext* ctx);
|
||||||
@ -65,6 +68,7 @@ class RTMPManager
|
|||||||
|
|
||||||
static std::unordered_map<std::string, std::unique_ptr<StreamContext>> streams;
|
static std::unordered_map<std::string, std::unique_ptr<StreamContext>> streams;
|
||||||
static std::mutex streams_mutex;
|
static std::mutex streams_mutex;
|
||||||
|
|
||||||
static std::atomic<bool> g_live_enabled;
|
static std::atomic<bool> g_live_enabled;
|
||||||
|
|
||||||
static constexpr int RETRY_BASE_DELAY_MS = 3000;
|
static constexpr int RETRY_BASE_DELAY_MS = 3000;
|
||||||
|
|||||||
@ -61,6 +61,8 @@ int main()
|
|||||||
// ---------- 初始化 GStreamer ----------
|
// ---------- 初始化 GStreamer ----------
|
||||||
RTMPManager::init();
|
RTMPManager::init();
|
||||||
|
|
||||||
|
RTMPManager::g_record_enabled = g_app_config.record_enabled;
|
||||||
|
|
||||||
// ---------- 自动推流(8 路录像守护) ----------
|
// ---------- 自动推流(8 路录像守护) ----------
|
||||||
LOG_INFO("[MAIN] Starting all record streams...");
|
LOG_INFO("[MAIN] Starting all record streams...");
|
||||||
RTMPManager::start_all();
|
RTMPManager::start_all();
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
std::atomic<bool> RTMPManager::g_live_enabled{false};
|
std::atomic<bool> 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 "
|
"! h264parse config-interval=1 "
|
||||||
"! tee name=t "
|
"! tee name=t "
|
||||||
|
|
||||||
// ===== record:永远稳定 =====
|
// ===== record:可开关 =====
|
||||||
"t. ! queue max-size-buffers=8 leaky=downstream "
|
"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 "
|
"! flvmux name=rec_mux streamable=true "
|
||||||
"! rtmpsink name=rec_sink location=\"" +
|
"! rtmpsink name=rec_sink location=\"" +
|
||||||
record_rtmp +
|
record_rtmp +
|
||||||
@ -173,6 +176,30 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx)
|
|||||||
ctx->live_valve = live_valve; // ⚠️ live_valve 引用交给 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<std::mutex> 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<std::mutex> 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);
|
g_object_set(G_OBJECT(ctx->live_valve), "drop", g_live_enabled.load() ? FALSE : TRUE, nullptr);
|
||||||
|
|
||||||
GstBus* bus = gst_element_get_bus(pipeline);
|
GstBus* bus = gst_element_get_bus(pipeline);
|
||||||
@ -248,11 +275,18 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx)
|
|||||||
cleanup:
|
cleanup:
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lk(ctx->status_mutex);
|
std::lock_guard<std::mutex> lk(ctx->status_mutex);
|
||||||
|
|
||||||
if (ctx->live_valve)
|
if (ctx->live_valve)
|
||||||
{
|
{
|
||||||
gst_object_unref(ctx->live_valve);
|
gst_object_unref(ctx->live_valve);
|
||||||
ctx->live_valve = nullptr;
|
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);
|
gst_element_set_state(pipeline, GST_STATE_NULL);
|
||||||
@ -317,11 +351,18 @@ void RTMPManager::stop_all()
|
|||||||
kv.second->thread_running.store(false);
|
kv.second->thread_running.store(false);
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lk(kv.second->status_mutex);
|
std::lock_guard<std::mutex> lk(kv.second->status_mutex);
|
||||||
|
|
||||||
if (kv.second->live_valve)
|
if (kv.second->live_valve)
|
||||||
{
|
{
|
||||||
gst_object_unref(kv.second->live_valve);
|
gst_object_unref(kv.second->live_valve);
|
||||||
kv.second->live_valve = nullptr;
|
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)
|
for (auto& kv : streams)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user