using System.Windows; using System.Windows.Media.Imaging; using SHH.Contracts; // ★★★ 引用契约库 (VideoPayload) ★★★ namespace SHH.CameraDashboard; public class VideoTileViewModel : ViewModelBase { private readonly string _boundCameraId; // --- 属性定义 (保持不变) --- private string _cameraName; public string CameraName { get => _cameraName; set { _cameraName = value; OnPropertyChanged(); } } private string _statusInfo; public string StatusInfo { get => _statusInfo; set { _statusInfo = value; OnPropertyChanged(); } } private BitmapImage _videoSource; public BitmapImage VideoSource { get => _videoSource; set { _videoSource = value; OnPropertyChanged(); } } // --- 构造函数 --- public VideoTileViewModel(string cameraId, string name) { _boundCameraId = cameraId; CameraName = name; StatusInfo = "等待信号..."; // ★★★ 变更 1: 订阅新的 OnPayloadReceived 事件 ★★★ // 旧的 OnFrameReceived(string, byte[]) 已经无法满足需求 StreamReceiverService.Instance.OnPayloadReceived += OnPayloadReceived; } // --- 事件回调 (后台线程) --- // ★★★ 变更 2: 参数变为 VideoPayload 实体对象 ★★★ private void OnPayloadReceived(VideoPayload payload) { // 1. 过滤:校验 Payload 中的 CameraId if (payload.CameraId != _boundCameraId) return; // 2. ★★★ 智能选图策略 ★★★ // 优先显示 AI 处理后的图 (TargetImageBytes) // 如果没有处理图,则降级显示原始图 (OriginalImageBytes) byte[] dataToShow = null; if (payload.HasTargetImage && payload.TargetImageBytes != null) { dataToShow = payload.TargetImageBytes; } else if (payload.HasOriginalImage && payload.OriginalImageBytes != null) { dataToShow = payload.OriginalImageBytes; } // 如果两张图都没有,直接返回 if (dataToShow == null || dataToShow.Length == 0) return; // 3. 解码图片 (耗时操作在后台完成) var bitmap = BitmapHelper.ToBitmapImage(dataToShow); if (bitmap == null) return; // 4. ★★★ 计算端到端延迟 ★★★ // 当前时间(接收端) - 采集时间(发送端) = 真实的网络+处理延迟 long latency = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - payload.CaptureTimestamp; // 5. UI 更新 Application.Current.Dispatcher.InvokeAsync(() => { VideoSource = bitmap; // 显示更丰富的信息:延迟毫秒数、数据量、当前时间 // 工业监控中,"延迟(ms)" 是比 "当前时间" 更重要的指标 StatusInfo = $"延迟: {latency}ms | {dataToShow.Length / 1024} KB | {DateTime.Now:HH:mm:ss}"; }); } // --- 资源清理 --- public void Unload() { // ★★★ 变更 3: 取消订阅新的事件 ★★★ StreamReceiverService.Instance.OnPayloadReceived -= OnPayloadReceived; // 清空图片引用,帮助 GC 回收内存 VideoSource = null; } }