diff --git a/src/rtsp_manager.cpp b/src/rtsp_manager.cpp index 39b5e9e..f61fa44 100644 --- a/src/rtsp_manager.cpp +++ b/src/rtsp_manager.cpp @@ -2,12 +2,17 @@ #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; + void RTSPManager::init() { gst_init(nullptr, nullptr); @@ -57,43 +62,134 @@ void RTSPManager::start(const std::vector &cameras) LOG_INFO("[RTSP] Server stopped."); } -// === 新增方法:挂载摄像头 === -void RTSPManager::mount_camera(const Camera &cam) +// --- 在主线程(main loop)中执行的挂载函数 --- +// data -> pointer to Camera (new'ed when posted). This function will delete it. +static gboolean mount_camera_in_main(gpointer data) { - if (!server) - return; + Camera *cam = static_cast(data); + if (!cam) + { + return G_SOURCE_REMOVE; + } + + 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; + } - GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server); - auto factory = create_media_factory(cam); - std::string mount_point = "/" + cam.name; gst_rtsp_mount_points_add_factory(mounts, mount_point.c_str(), factory); g_object_unref(mounts); - streaming_status[cam.name] = true; // === 更新播放状态 === - LOG_INFO("[RTSP] Camera '" + cam.name + "' mounted at rtsp://localhost:8554" + mount_point); + { + 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; } -// === 新增方法:卸载摄像头 === -void RTSPManager::unmount_camera(const Camera &cam) +// --- 在主线程(main loop)中执行的卸载函数 --- +static gboolean unmount_camera_in_main(gpointer data) { - if (!server) - return; + Camera *cam = static_cast(data); + if (!cam) + { + return G_SOURCE_REMOVE; + } - GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server); - std::string mount_point = "/" + cam.name; + 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); - streaming_status[cam.name] = false; // === 更新播放状态 === - LOG_INFO("[RTSP] Camera '" + cam.name + "' unmounted."); + { + 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; } +// 公共接口:挂载摄像头(可以被任意线程调用,立即返回) +// 将实际挂载工作派发到 main loop 线程执行,避免跨线程直接调用 GStreamer。 +void RTSPManager::mount_camera(const Camera &cam) +{ + // 通过 new 一个临时 Camera 拷贝,主loop callback 会 delete 它 + Camera *camCopy = new Camera(cam); + // 派发到主线程执行 + g_main_context_invoke(nullptr, [](gpointer data) -> gboolean + { return mount_camera_in_main(data); }, camCopy); +} + +// 公共接口:卸载摄像头(可以被任意线程调用,立即返回) +// 将实际卸载工作派发到 main loop 线程执行。 +void RTSPManager::unmount_camera(const Camera &cam) +{ + Camera *camCopy = new Camera(cam); + g_main_context_invoke(nullptr, [](gpointer data) -> gboolean + { return unmount_camera_in_main(data); }, camCopy); +} + +// 查询播放状态(线程安全) bool RTSPManager::is_streaming(const std::string &cam_name) { + std::lock_guard lock(mounted_factories_mutex); auto it = streaming_status.find(cam_name); if (it != streaming_status.end()) return it->second; - return false; // 默认未推流 + return false; } void RTSPManager::stop()