diff --git a/include/rtsp_manager.hpp b/include/rtsp_manager.hpp index 2286156..409568c 100644 --- a/include/rtsp_manager.hpp +++ b/include/rtsp_manager.hpp @@ -4,6 +4,7 @@ #include #include #include "app_config.hpp" +#include // RTSP 管理器,负责启动/关闭 RTSP 服务器 class RTSPManager @@ -13,19 +14,28 @@ public: static void start(const std::vector &cameras); static void stop(); - // === 新增方法:按需挂载/卸载摄像头 === + // === 按需挂载/卸载摄像头 === static void mount_camera(const Camera &cam); static void unmount_camera(const Camera &cam); - // === 新增方法:查询播放状态 === + // === 查询播放状态 === static bool is_streaming(const std::string &cam_name); private: static GMainLoop *loop; static GstRTSPServer *server; - // === 新增:维护每个摄像头的播放状态 === + // 播放状态表 static std::unordered_map streaming_status; + // 创建 MediaFactory static GstRTSPMediaFactory *create_media_factory(const Camera &cam); + + // --- 新增:在 main loop 中执行挂载/卸载 --- + static gboolean mount_camera_in_main(gpointer data); + static gboolean unmount_camera_in_main(gpointer data); + + // --- 已挂载的 factory 指针表(用于卸载) --- + static std::unordered_map mounted_factories; + static std::mutex mounted_factories_mutex; }; diff --git a/src/rtsp_manager.cpp b/src/rtsp_manager.cpp index f61fa44..41e6923 100644 --- a/src/rtsp_manager.cpp +++ b/src/rtsp_manager.cpp @@ -2,16 +2,13 @@ #include "rtsp_manager.hpp" #include "logger.hpp" #include -#include // 静态变量定义 GMainLoop *RTSPManager::loop = nullptr; GstRTSPServer *RTSPManager::server = nullptr; -std::unordered_map RTSPManager::streaming_status; // 播放状态表 - -// 新增:保存已挂载的 factory,方便卸载时找到并释放 -static std::unordered_map mounted_factories; -static std::mutex mounted_factories_mutex; +std::unordered_map RTSPManager::streaming_status; +std::unordered_map RTSPManager::mounted_factories; +std::mutex RTSPManager::mounted_factories_mutex; void RTSPManager::init() { @@ -48,7 +45,7 @@ void RTSPManager::start(const std::vector &cameras) LOG_INFO("[RTSP] Server running on rtsp://localhost:8554"); g_main_loop_run(loop); - // loop 退出后再释放资源 + // loop 退出后释放资源 if (server) { g_object_unref(server); @@ -62,104 +59,17 @@ void RTSPManager::start(const std::vector &cameras) LOG_INFO("[RTSP] Server stopped."); } -// --- 在主线程(main loop)中执行的挂载函数 --- -// data -> pointer to Camera (new'ed when posted). This function will delete it. -static gboolean mount_camera_in_main(gpointer data) +void RTSPManager::stop() { - Camera *cam = static_cast(data); - if (!cam) + if (loop) { - return G_SOURCE_REMOVE; + // 仅退出 loop,不 unref server + g_main_context_invoke(nullptr, [](gpointer data) -> gboolean + { + GMainLoop *loop = static_cast(data); + g_main_loop_quit(loop); + return G_SOURCE_REMOVE; }, loop); } - - if (!RTSPManager::server) - { - LOG_ERROR("[RTSP] mount_camera_in_main: server is null"); - delete cam; - return G_SOURCE_REMOVE; - } - - GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(RTSPManager::server); - if (!mounts) - { - LOG_ERROR("[RTSP] mount_camera_in_main: failed to get mounts"); - delete cam; - return G_SOURCE_REMOVE; - } - - std::string mount_point = "/" + cam->name; - GstRTSPMediaFactory *factory = RTSPManager::create_media_factory(*cam); - if (!factory) - { - LOG_ERROR("[RTSP] mount_camera_in_main: failed to create factory for " + cam->name); - g_object_unref(mounts); - delete cam; - return G_SOURCE_REMOVE; - } - - gst_rtsp_mount_points_add_factory(mounts, mount_point.c_str(), factory); - g_object_unref(mounts); - - { - std::lock_guard lock(mounted_factories_mutex); - // 注意:mount_points 接收 factory 的引用,仍然可以保存指针以便后续移除并 unref - mounted_factories[cam->name] = factory; - RTSPManager::streaming_status[cam->name] = true; - } - - LOG_INFO("[RTSP] Camera '" + cam->name + "' mounted at rtsp://localhost:8554" + mount_point); - - delete cam; - return G_SOURCE_REMOVE; -} - -// --- 在主线程(main loop)中执行的卸载函数 --- -static gboolean unmount_camera_in_main(gpointer data) -{ - Camera *cam = static_cast(data); - if (!cam) - { - return G_SOURCE_REMOVE; - } - - if (!RTSPManager::server) - { - LOG_ERROR("[RTSP] unmount_camera_in_main: server is null"); - delete cam; - return G_SOURCE_REMOVE; - } - - GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(RTSPManager::server); - if (!mounts) - { - LOG_ERROR("[RTSP] unmount_camera_in_main: failed to get mounts"); - delete cam; - return G_SOURCE_REMOVE; - } - - std::string mount_point = "/" + cam->name; - gst_rtsp_mount_points_remove_factory(mounts, mount_point.c_str()); - - g_object_unref(mounts); - - { - std::lock_guard lock(mounted_factories_mutex); - auto it = mounted_factories.find(cam->name); - if (it != mounted_factories.end()) - { - // factory 由 mountpoints 拥有引用,移除后我们需要 unref 它 - GstRTSPMediaFactory *factory = it->second; - if (factory) - g_object_unref(factory); - mounted_factories.erase(it); - } - RTSPManager::streaming_status[cam->name] = false; - } - - LOG_INFO("[RTSP] Camera '" + cam->name + "' unmounted."); - - delete cam; - return G_SOURCE_REMOVE; } // 公共接口:挂载摄像头(可以被任意线程调用,立即返回) @@ -192,15 +102,91 @@ bool RTSPManager::is_streaming(const std::string &cam_name) return false; } -void RTSPManager::stop() +// -------------------- private static callbacks -------------------- + +gboolean RTSPManager::mount_camera_in_main(gpointer data) { - if (loop) + Camera *cam = static_cast(data); + if (!cam) + return G_SOURCE_REMOVE; + + if (!server) { - // 仅退出 loop,不 unref server - g_main_context_invoke(nullptr, [](gpointer data) -> gboolean - { - GMainLoop *loop = static_cast(data); - g_main_loop_quit(loop); - return G_SOURCE_REMOVE; }, loop); + LOG_ERROR("[RTSP] mount_camera_in_main: server is null"); + delete cam; + return G_SOURCE_REMOVE; } + + GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server); + if (!mounts) + { + LOG_ERROR("[RTSP] mount_camera_in_main: failed to get mounts"); + delete cam; + return G_SOURCE_REMOVE; + } + + std::string mount_point = "/" + cam->name; + GstRTSPMediaFactory *factory = create_media_factory(*cam); + if (!factory) + { + LOG_ERROR("[RTSP] mount_camera_in_main: failed to create factory for " + cam->name); + g_object_unref(mounts); + delete cam; + return G_SOURCE_REMOVE; + } + + gst_rtsp_mount_points_add_factory(mounts, mount_point.c_str(), factory); + g_object_unref(mounts); + + { + std::lock_guard lock(mounted_factories_mutex); + mounted_factories[cam->name] = factory; + streaming_status[cam->name] = true; + } + + LOG_INFO("[RTSP] Camera '" + cam->name + "' mounted at rtsp://localhost:8554" + mount_point); + delete cam; + return G_SOURCE_REMOVE; +} + +gboolean RTSPManager::unmount_camera_in_main(gpointer data) +{ + Camera *cam = static_cast(data); + if (!cam) + return G_SOURCE_REMOVE; + + if (!server) + { + LOG_ERROR("[RTSP] unmount_camera_in_main: server is null"); + delete cam; + return G_SOURCE_REMOVE; + } + + GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server); + if (!mounts) + { + LOG_ERROR("[RTSP] unmount_camera_in_main: failed to get mounts"); + delete cam; + return G_SOURCE_REMOVE; + } + + std::string mount_point = "/" + cam->name; + gst_rtsp_mount_points_remove_factory(mounts, mount_point.c_str()); + g_object_unref(mounts); + + { + std::lock_guard lock(mounted_factories_mutex); + auto it = mounted_factories.find(cam->name); + if (it != mounted_factories.end()) + { + if (it->second) + g_object_unref(it->second); + mounted_factories.erase(it); + } + streaming_status[cam->name] = false; + } + + LOG_INFO("[RTSP] Camera '" + cam->name + "' unmounted."); + delete cam; + return G_SOURCE_REMOVE; }