using Microsoft.Extensions.Hosting; using OpenCvSharp; using SHH.Contracts; using SHH.NetMQ; namespace SHH.CameraSdk { public class ZeroMqBridgeService : BackgroundService { private readonly DistributorServer _distributor; private readonly ForwarderClient _forwarder; public ZeroMqBridgeService(DistributorServer distributor, ForwarderClient forwarder) { _distributor = distributor; _forwarder = forwarder; } protected override Task ExecuteAsync(CancellationToken stoppingToken) { Console.WriteLine("[Bridge] 正在连接全局广播总线..."); // 【关键修改】直接订阅静态的全局事件 // 不需要传入 APP_ID,因为这是 C# 原生事件,不是字典查找 GlobalStreamDispatcher.OnGlobalFrame += BridgeHandler; Console.WriteLine("[Bridge] 全局总线连接成功!任何动态增删的设备都会自动转发。"); return Task.CompletedTask; } // 真正的事件处理函数 private void BridgeHandler(long deviceId, SmartFrame frame) { try { // 1. 安全检查 var sourceMat = frame.TargetMat ?? frame.InternalMat; if (sourceMat == null || sourceMat.Empty()) return; // 2. 内存克隆 (Deep Copy) - 这一步不能省 using var safeMat = sourceMat.Clone(); // 3. 编码 & 封装 // 建议:可以在这里判断一下 deviceId,如果某些设备不想发,可以在这里 return var jpgParams = new int[] { (int)ImwriteFlags.JpegQuality, 70 }; byte[] jpgBytes = safeMat.ImEncode(".jpg", jpgParams); var payload = new VideoPayload { CameraId = deviceId.ToString(), CaptureTime = DateTime.Now, DispatchTime = DateTime.Now, OriginalWidth = safeMat.Width, OriginalHeight = safeMat.Height, OriginalImageBytes = jpgBytes }; // 4. 发射 _distributor.Broadcast(payload); _forwarder.Push(payload); } catch (Exception ex) { // Console.WriteLine(ex.Message); // 生产环境建议注释掉,防止日志刷屏 } } public override Task StopAsync(CancellationToken cancellationToken) { // 优雅退订,防止内存泄漏 GlobalStreamDispatcher.OnGlobalFrame -= BridgeHandler; return base.StopAsync(cancellationToken); } } }