diff --git a/include/rtsp_manager.hpp b/include/rtsp_manager.hpp index 83d9a26..0010fe0 100644 --- a/include/rtsp_manager.hpp +++ b/include/rtsp_manager.hpp @@ -1,3 +1,4 @@ +// rtsp_manager.hpp #pragma once #include @@ -6,6 +7,7 @@ #include #include #include +#include class RTSPManager { @@ -34,4 +36,12 @@ private: // 静态 mutex 和工厂表 static std::unordered_map mounted_factories; static std::mutex mounted_factories_mutex; -}; + + // 媒体对象跟踪 + static std::unordered_map> media_map; + static std::mutex media_map_mutex; + + // 信号处理函数 + static void on_media_created(GstRTSPMediaFactory *factory, GstRTSPMedia *media, gpointer user_data); + static void on_media_unprepared(GstRTSPMedia *media, gpointer user_data); +}; \ No newline at end of file diff --git a/src/rtsp_manager.cpp b/src/rtsp_manager.cpp index a749f74..ef1ed80 100644 --- a/src/rtsp_manager.cpp +++ b/src/rtsp_manager.cpp @@ -1,3 +1,4 @@ +// rtsp_manager.cpp #include "rtsp_manager.hpp" #include "logger.hpp" #include @@ -9,6 +10,8 @@ GstRTSPServer *RTSPManager::server = nullptr; std::unordered_map RTSPManager::streaming_status; std::unordered_map RTSPManager::mounted_factories; std::mutex RTSPManager::mounted_factories_mutex; +std::unordered_map> RTSPManager::media_map; +std::mutex RTSPManager::media_map_mutex; void RTSPManager::init() { @@ -28,6 +31,11 @@ GstRTSPMediaFactory *RTSPManager::create_media_factory(const Camera &cam) GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new(); gst_rtsp_media_factory_set_launch(factory, launch_str.c_str()); gst_rtsp_media_factory_set_shared(factory, TRUE); + + // 连接 media-created 信号,跟踪媒体对象 + g_signal_connect_data(factory, "media-created", G_CALLBACK(on_media_created), g_strdup(cam.name.c_str()), + (GClosureNotify)g_free, 0); + return factory; } @@ -57,6 +65,36 @@ void RTSPManager::start(const std::vector &cameras) LOG_INFO("[RTSP] Server stopped."); } +// 媒体创建信号处理函数 +void RTSPManager::on_media_created(GstRTSPMediaFactory *factory, GstRTSPMedia *media, gpointer user_data) +{ + const char *cam_name = static_cast(user_data); + std::lock_guard lock(media_map_mutex); + media_map[cam_name].push_back(media); + g_object_ref(media); // 增加引用计数,防止意外销毁 + + // 连接 unprepared 信号,以便在媒体销毁时从列表中移除 + g_signal_connect_data(media, "unprepared", G_CALLBACK(on_media_unprepared), g_strdup(cam_name), (GClosureNotify)g_free, 0); +} + +// 媒体 unprepared 信号处理函数 +void RTSPManager::on_media_unprepared(GstRTSPMedia *media, gpointer user_data) +{ + const char *cam_name = static_cast(user_data); + std::lock_guard lock(media_map_mutex); + auto it = media_map.find(cam_name); + if (it != media_map.end()) + { + auto &media_list = it->second; + media_list.erase(std::remove(media_list.begin(), media_list.end(), media), media_list.end()); + if (media_list.empty()) + { + media_map.erase(it); + } + } + g_object_unref(media); // 释放我们在 on_media_created 中增加的引用 +} + // 挂载摄像头 gboolean RTSPManager::mount_camera_in_main(gpointer data) { @@ -97,7 +135,7 @@ gboolean RTSPManager::mount_camera_in_main(gpointer data) return G_SOURCE_REMOVE; } -// 卸载摄像头(发送 EOS 停止 pipeline) +// 卸载摄像头(停止所有媒体会话) gboolean RTSPManager::unmount_camera_in_main(gpointer data) { Camera *cam = static_cast(data); @@ -107,27 +145,44 @@ gboolean RTSPManager::unmount_camera_in_main(gpointer data) return G_SOURCE_REMOVE; } + std::string cam_name = cam->name; + std::string mount_point = "/" + cam_name; + + // 停止所有相关的媒体会话 + { + std::lock_guard lock(media_map_mutex); + auto it = media_map.find(cam_name); + if (it != media_map.end()) + { + for (GstRTSPMedia *media : it->second) + { + gst_rtsp_media_stop(media); + } + it->second.clear(); + media_map.erase(it); + } + } + GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server); if (mounts) { - 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); + auto it = mounted_factories.find(cam_name); if (it != mounted_factories.end()) { if (it->second && G_IS_OBJECT(it->second)) g_object_unref(it->second); // 安全 unref mounted_factories.erase(it); } - streaming_status[cam->name] = false; + streaming_status[cam_name] = false; } - LOG_INFO("[RTSP] Camera '" + cam->name + "' unmounted."); + LOG_INFO("[RTSP] Camera '" + cam_name + "' unmounted."); delete cam; return G_SOURCE_REMOVE; }