diff --git a/src/rtmp_manager.cpp b/src/rtmp_manager.cpp index 60f2126..f337e02 100644 --- a/src/rtmp_manager.cpp +++ b/src/rtmp_manager.cpp @@ -14,6 +14,12 @@ #include "logger.hpp" +static bool device_exists(const std::string &path) +{ + struct stat st; + return (stat(path.c_str(), &st) == 0); +} + static std::string get_ip_address(const std::string &ifname) { struct ifaddrs *ifaddr, *ifa; @@ -129,6 +135,14 @@ RTMPManager::StreamResultInfo RTMPManager::start_camera(const Camera &cam, Strea return res; } + // 新增:设备节点存在性检查 + if (!device_exists(cam.device)) + { + res.result = 1; + res.reason = "Device not found: " + cam.device; + return res; + } + const std::string key = make_stream_key(cam.name, type); std::unique_ptr ctx; @@ -139,15 +153,13 @@ RTMPManager::StreamResultInfo RTMPManager::start_camera(const Camera &cam, Strea auto it = streams.find(key); if (it != streams.end() && it->second->running.load()) { - res.result = 0; + res.result = 1; // 修改为 1:表示重复启动,不是真成功 res.reason = "Already streaming"; return res; } ctx = std::make_unique(); ctx->running.store(true); - - // 重要:在把 ctx 放入 map 之前,先从 ctx->start_promise 拿到 future status_future = ctx->start_promise.get_future(); StreamContext *ctx_ptr = ctx.get(); @@ -202,7 +214,7 @@ RTMPManager::StreamResultInfo RTMPManager::stop_camera(const std::string &cam_na streams.erase(it); } - bool was_running = ctx->status.running; // ✅ 新增:判断是否真的在推流 + bool was_running = ctx->running.load(); // ✅ 改为使用 running ctx->running.store(false); if (ctx->thread.joinable()) ctx->thread.join(); @@ -262,17 +274,15 @@ void RTMPManager::stream_loop(Camera cam, StreamType type, StreamContext *ctx) while (true) { - // 手动停止 if (!ctx->running.load()) { status.running = false; status.last_result = StreamResult::UNKNOWN; status.last_error = "Stream stopped manually"; - try_set_start(status); // 若启动阶段还没返回,这里补一次 + try_set_start(status); break; } - // 首帧超时(5s) if (!first_frame && std::chrono::duration_cast(std::chrono::steady_clock::now() - t0).count() > 5) { @@ -301,8 +311,7 @@ void RTMPManager::stream_loop(Camera cam, StreamType type, StreamContext *ctx) status.running = true; ctx->status.running = true; status.last_result = StreamResult::OK; - status.last_error.clear(); - try_set_start(status); // 首帧成功:通知 start_camera + try_set_start(status); } break; } @@ -331,19 +340,21 @@ void RTMPManager::stream_loop(Camera cam, StreamType type, StreamContext *ctx) gst_message_unref(msg); - // 错误/EOS 后退出循环 if (status.last_result == StreamResult::CONNECTION_FAIL || status.last_result == StreamResult::EOS_RECEIVED) - { break; - } } - gst_element_set_state(pipeline, GST_STATE_NULL); - if (bus) gst_object_unref(bus); - gst_object_unref(pipeline); + if (pipeline) + { + gst_element_set_state(pipeline, GST_STATE_NULL); + gst_object_unref(pipeline); + } + if (bus) + { + gst_object_unref(bus); + } ctx->status.running = false; - // 线程收尾:这里不要删 map 里的 ctx,stop_camera 已经负责转移并 join } void RTMPManager::stop_all() @@ -400,21 +411,24 @@ std::vector RTMPManager::process_push_request(con for (int ch : item.channels) { - if (ch < 0 || ch >= static_cast(g_app_config.cameras.size())) continue; + if (ch < 0 || ch >= static_cast(g_app_config.cameras.size())) + { + StreamResultInfo info; + info.loc = ch; + info.result = 1; + info.reason = "Invalid channel index"; + info.url = ""; + results.push_back(info); + continue; + } const auto &cam = g_app_config.cameras[ch]; StreamResultInfo info; if (item.switchVal == 0) - { - // 开启推流 info = start_camera(cam, type); - } else - { - // 停止推流 info = stop_camera(cam.name, type); - } results.push_back(info); }