增加本地Cv2.ImShow播放的动态增加、移除的支持

This commit is contained in:
2025-12-26 17:28:07 +08:00
parent 83ad6221a4
commit e98059fd30
5 changed files with 305 additions and 185 deletions

View File

@@ -177,4 +177,25 @@ public static class GlobalStreamDispatcher
}
#endregion
#region Unsubscribe
/// <summary>
/// [新增重载] 强制取消订阅:直接移除指定 AppId 的整个路由项
/// 用途:当业务模块(如播放窗口)销毁时,彻底切断该 AppId 的数据流
/// </summary>
/// <param name="appId">业务唯一标识</param>
public static void Unsubscribe(string appId)
{
if (string.IsNullOrWhiteSpace(appId)) return;
// 直接从字典中移除 Key这将丢弃该 Key 下挂载的所有委托链
// TryRemove 是原子的、线程安全的
if (_routingTable.TryRemove(appId, out _))
{
Console.WriteLine($"[Dispatcher] 已强制移除 AppId [{appId}] 的所有订阅路由");
}
}
#endregion
}

View File

@@ -36,8 +36,15 @@ public class FrameController
public void Unregister(string appId)
{
if (string.IsNullOrWhiteSpace(appId)) return;
// 1. 从需求配置中移除
_requirements.TryRemove(appId, out _);
_accumulators.TryRemove(appId, out _); // 同步清理,防止内存泄漏
// 2. 从积分累加器中移除(防止内存泄漏)
_accumulators.TryRemove(appId, out _);
Console.WriteLine($"[Scheduler] 已从调度中心彻底移除 AppId: {appId}");
}
// ---------------------------------------------------------

View File

@@ -0,0 +1,63 @@
namespace SHH.CameraSdk;
/// <summary>
/// 动态窗口管理器
/// 职责:根据业务指令动态创建/销毁 OpenCV 播放窗口,并管理流订阅
/// </summary>
public class DisplayWindowManager
{
// 存储活跃的渲染器实例Key = AppId (如 "UI_Preview_Main")
private readonly ConcurrentDictionary<string, FrameConsumer> _activeWindows = new();
/// <summary>
/// 开启一个本地播放窗口
/// </summary>
/// <param name="appId">业务标识 (将作为窗口标题)</param>
/// <param name="deviceId">要观看的设备ID</param>
public void StartDisplay(string appId, int deviceId)
{
// 如果窗口已存在,直接返回(防止重复创建)
if (_activeWindows.ContainsKey(appId)) return;
Console.WriteLine($"[DisplayManager] 正在创建窗口: {appId} -> Device {deviceId}...");
// 1. 动态创建渲染器
var renderer = new FrameConsumer(appId);
// 2. 启动渲染循环 (由于我们之前加了懒加载逻辑,此时不会立即弹窗,直到有帧数据过来)
renderer.Start();
// 3. 存入字典管理
if (_activeWindows.TryAdd(appId, renderer))
{
// 4. 【关键】建立数据订阅:将设备流导向这个渲染器
GlobalStreamDispatcher.Subscribe(appId, deviceId, frame =>
{
// 引用计数 +1防止在渲染前被回收
frame.AddRef();
renderer.Enqueue(frame);
});
}
else
{
renderer.Dispose(); // 并发冲突处理
}
}
/// <summary>
/// 关闭并销毁窗口
/// </summary>
public void StopDisplay(string appId)
{
if (_activeWindows.TryRemove(appId, out var renderer))
{
Console.WriteLine($"[DisplayManager] 正在关闭窗口: {appId}");
// 1. 取消订阅 (停止接收数据)
GlobalStreamDispatcher.Unsubscribe(appId);
// 2. 销毁渲染器 (OpenCV DestroyWindow 会在 FrameConsumer 内部触发)
renderer.Dispose();
}
}
}