63 lines
2.1 KiB
C#
63 lines
2.1 KiB
C#
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();
|
||
}
|
||
}
|
||
} |