Files
Ayay/SHH.CameraDashboard/Services/VideoPushServer.cs

110 lines
3.8 KiB
C#
Raw Permalink 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 NetMQ;
using NetMQ.Sockets;
using SHH.Contracts; // 引用你 ExportCode_Dump2.txt 里的契约
namespace SHH.CameraDashboard
{
/// <summary>
/// 视频推流接收服务 (服务端模式)
/// 职责:监听本地端口,被动接收来自采集端的 Push 数据流
/// </summary>
public class VideoPushServer : IDisposable
{
private PullSocket? _pullSocket;
private bool _isRunning;
private Task? _listenTask;
// 当收到完整视频帧时触发UI 层订阅此事件来更新画面
// VideoPayload 定义在 ExportCode_Dump2.txt 中
public event Action<VideoPayload>? OnFrameReceived;
/// <summary>
/// 启动监听
/// </summary>
/// <param name="port">本机开放的监听端口 (例如 6000)</param>
public void Start(int port)
{
if (_isRunning) return;
try
{
_pullSocket = new PullSocket();
// 1. 设置高水位 (HWM),防止渲染不及导致内存溢出
// 与发送端 ForwarderClient 的 HWM_LIMIT = 50 保持策略一致
_pullSocket.Options.ReceiveHighWatermark = 50;
// 2. 【核心】绑定本地端口 (Bind),等待别人连我
// 允许局域网内任何 IP 推送数据过来
_pullSocket.Bind($"tcp://*:{port}");
_isRunning = true;
// 3. 开启后台接收线程
_listenTask = Task.Run(ReceiveLoop);
System.Diagnostics.Debug.WriteLine($"[PushServer] 服务已启动,正在监听端口: {port}...");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[PushServer] 启动失败: {ex.Message}");
}
}
private void ReceiveLoop()
{
while (_isRunning && _pullSocket != null)
{
try
{
// 1. 接收多帧消息 (超时控制以便能优雅退出)
NetMQMessage? msg = null;
if (!_pullSocket.TryReceiveMultipartMessage(TimeSpan.FromMilliseconds(500), ref msg))
{
continue;
}
// 2. 协议校验:必须包含 3 帧 (JSON + Raw + Target)
// 对应 ExportCode_Dump1.txt 中 ForwarderClient.Push 的 msg.Append 顺序
if (msg == null || msg.FrameCount < 3) continue;
// 3. 解析数据帧
string jsonMeta = msg[0].ConvertToString();
byte[] originalBytes = msg[1].Buffer;
byte[] targetBytes = msg[2].Buffer;
// 4. 反序列化元数据
// 使用你 Core/JsonHelper.cs 里的稳健反序列化
var payload = JsonHelper.Deserialize<VideoPayload>(jsonMeta);
if (payload != null)
{
// 5. 组装二进制数据 (因为传输时是分离的)
payload.OriginalImageBytes = originalBytes;
payload.TargetImageBytes = targetBytes;
// 6. 触发事件 (抛出给 ViewModel)
OnFrameReceived?.Invoke(payload);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[PushServer] 接收异常: {ex.Message}");
}
}
}
public void Stop()
{
_isRunning = false;
_pullSocket?.Close();
_pullSocket?.Dispose();
_pullSocket = null;
}
public void Dispose()
{
Stop();
}
}
}