Files
Ayay/SHH.CameraService/ZeroMQBridgeWorker.cs
2026-01-05 14:54:06 +08:00

87 lines
3.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Hosting;
using NetMQ;
using NetMQ.Sockets;
using SHH.CameraSdk;
namespace SHH.CameraService;
public class ZeroMQBridgeWorker : BackgroundService
{
private readonly ServiceConfig _config;
private readonly VideoDataChannel _channel; // 数据源
public ZeroMQBridgeWorker(ServiceConfig config, VideoDataChannel channel)
{
_config = config;
_channel = channel;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// 1. 如果不是主动/混合模式,不需要连接
if (!_config.ShouldConnect) return;
// ★★★ 核心修正:直接读取解析好的视频地址列表 ★★★
// 这些地址来自参数 --uris "IP,VideoPort&CommandPort" 中的 VideoPort 部分 (符号左边)
var streamUris = _config.VideoEndpoints;
if (streamUris.Count == 0)
{
Console.WriteLine("[推流] 未在参数中找到视频通道地址(位于&符号左侧),跳过连接。");
return;
}
// 2. 初始化 Publisher Socket
// 特点:只需 Send 一次,底层会自动分发给所有 Connect 的 Dashboard
using var pubSocket = new PublisherSocket();
// 设置发送高水位 (HWM)
// 防止网络拥塞或接收端处理慢时内存无限增长。超过50帧积压就开始丢弃旧帧。
pubSocket.Options.SendHighWatermark = 50;
// 3. 连接所有视频目标
foreach (var uri in streamUris)
{
Console.WriteLine($"[推流] 连接视频接收端: {uri}");
pubSocket.Connect(uri);
}
Console.WriteLine($"[推流] 服务就绪 (AppId: {_config.AppId}),等待视频帧...");
// 4. 推流循环
while (!stoppingToken.IsCancellationRequested)
{
try
{
// 从通道读取最新帧 (支持异步等待)
// 注意:这里使用了之前 VideoDataChannel 暴露出来的 Reader 属性
var payload = await _channel.Reader.ReadAsync(stoppingToken);
// 简单校验
if (payload == null || payload.OriginalImageBytes == null || payload.OriginalImageBytes.Length == 0)
continue;
// 构造 Topic (通常用 AppId 作为 Topic这样 Dashboard 可以按需订阅)
string topic = _config.AppId;
// 发送两帧:[Topic] [ImageBytes]
// 这样 Dashboard 的 Subscriber 可以通过 Subscribe(topic) 来过滤
pubSocket.SendMoreFrame(topic)
.SendFrame(payload.OriginalImageBytes);
// 调试日志 (生产环境建议注释掉,否则刷屏)
// Console.WriteLine($"[推流] Sent {payload.OriginalImageBytes.Length} bytes");
}
catch (OperationCanceledException)
{
break; // 正常退出
}
catch (Exception ex)
{
Console.WriteLine($"[推流] 发送异常: {ex.Message}");
// 发生错误稍微停顿,防止死循环占用 CPU
await Task.Delay(1000, stoppingToken);
}
}
}
}