From b125c8db4205ba3c275b8081da62248baf39fe4f Mon Sep 17 00:00:00 2001 From: cxh Date: Wed, 12 Nov 2025 17:57:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BE=AA=E7=8E=AF=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rtmp_manager.cpp | 62 +++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/src/rtmp_manager.cpp b/src/rtmp_manager.cpp index 3348566..07961aa 100644 --- a/src/rtmp_manager.cpp +++ b/src/rtmp_manager.cpp @@ -112,9 +112,10 @@ GstElement* RTMPManager::create_pipeline(const Camera& cam) void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) { const std::string key = make_key(cam.name); + while (ctx->running) { - // 设备是否存在 + // 1. 检查设备节点是否存在 struct stat st{}; if (stat(cam.device.c_str(), &st) != 0) { @@ -125,7 +126,7 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) continue; } - // 创建管线 + // 2. 创建 GStreamer 管线 GstElement* pipeline = create_pipeline(cam); if (!pipeline) { @@ -137,13 +138,13 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) gst_element_set_name(pipeline, key.c_str()); GstBus* bus = gst_element_get_bus(pipeline); - // 在 videoconvert 的 src pad 上挂 probe 判断是否有帧流过 + // 3. 在 v4l2src 的 src pad 上挂探测 probe bool got_frame = false; { - GstElement* vc = gst_bin_get_by_name(GST_BIN(pipeline), "vc"); - if (vc) + GstElement* src = gst_bin_get_by_name(GST_BIN(pipeline), "src"); + if (src) { - GstPad* pad = gst_element_get_static_pad(vc, "src"); + GstPad* pad = gst_element_get_static_pad(src, "src"); if (pad) { gst_pad_add_probe( @@ -158,39 +159,36 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) } else { - LOG_WARN("[RTMP] " + key + " - vc has no src pad?"); + LOG_WARN("[RTMP] " + key + " - src has no 'src' pad?"); } - gst_object_unref(vc); + gst_object_unref(src); } else { - LOG_WARN("[RTMP] " + key + " - cannot find element 'vc' for pad-probe"); + LOG_WARN("[RTMP] " + key + " - cannot find element 'src' for pad-probe"); } } - // 启动 + // 4. 启动播放 LOG_INFO("[RTMP] Starting stream: " + key); gst_element_set_state(pipeline, GST_STATE_PLAYING); - // 等待进入 PLAYING(最长 5s) + // 等待进入 PLAYING 状态(最长 5s) + GstState state = GST_STATE_NULL, pending = GST_STATE_NULL; bool confirmed_running = false; + if (gst_element_get_state(pipeline, &state, &pending, 5 * GST_SECOND) == GST_STATE_CHANGE_SUCCESS && + state == GST_STATE_PLAYING) { - GstState state = GST_STATE_NULL, pending = GST_STATE_NULL; - // 注意:第三个参数单位是纳秒,5s=5*GST_SECOND - if (gst_element_get_state(pipeline, &state, &pending, 5 * GST_SECOND) == GST_STATE_CHANGE_SUCCESS && - state == GST_STATE_PLAYING) - { - confirmed_running = true; - ctx->status.running = true; - ctx->status.last_error.clear(); - LOG_INFO("[RTMP] " + key + " confirmed PLAYING"); - } - else - { - ctx->status.running = false; - ctx->status.last_error = "Pipeline failed to confirm PLAYING"; - LOG_WARN("[RTMP] " + key + " - " + ctx->status.last_error); - } + confirmed_running = true; + ctx->status.running = true; + ctx->status.last_error.clear(); + LOG_INFO("[RTMP] " + key + " confirmed PLAYING"); + } + else + { + ctx->status.running = false; + ctx->status.last_error = "Pipeline failed to confirm PLAYING"; + LOG_WARN("[RTMP] " + key + " - " + ctx->status.last_error); } if (!confirmed_running) @@ -202,13 +200,13 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) continue; } - // 运行中:5s 内必须看到帧,否则认定无信号重启 + // 5. 运行阶段:监测帧和错误 const auto start_t = std::chrono::steady_clock::now(); bool need_restart = false; while (ctx->running) { - // 先检查帧 + // 检查是否收到帧(前 5s 内) if (!got_frame) { auto elapsed = @@ -225,12 +223,11 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) } else { - // 一旦有帧,保持 running=true ctx->status.running = true; ctx->status.last_error.clear(); } - // 监听错误/EOS + // 等待错误或 EOS 消息 GstMessage* msg = gst_bus_timed_pop_filtered(bus, 200 * GST_MSECOND, (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS)); @@ -263,11 +260,12 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) if (need_restart) break; } - // 收尾 + // 6. 收尾清理 gst_element_set_state(pipeline, GST_STATE_NULL); if (bus) gst_object_unref(bus); gst_object_unref(pipeline); + // 7. 若仍在运行状态,准备重启 if (ctx->running) { LOG_WARN("[RTMP] Restarting " + key + " in 3s...");