新增 Mjpegplayer 用来播放 Web 流
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using SHH.Contracts;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace SHH.MjpegPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// AI 视频流监控控制器
|
||||
/// 职责:接收 gRpc 转换后的 Payload -> 业务转换 -> 分发 UI/AI
|
||||
/// </summary>
|
||||
public class ImageMonitorController
|
||||
{
|
||||
public static ImageMonitorController Instance { get; } = new ImageMonitorController();
|
||||
|
||||
private ImageMonitorController() { }
|
||||
|
||||
/// <summary>
|
||||
/// 统一接收入口:由 GatewayProviderImpl.UploadVideoStream 调用
|
||||
/// </summary>
|
||||
public void ReceivePayload(VideoPayload payload)
|
||||
{
|
||||
if (payload == null) return;
|
||||
|
||||
// 1. 过滤 2 秒外的过期数据
|
||||
if ((DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - payload.CaptureTimestamp) > 2000)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
ImagePayloadConverter.ToXWcfMsg(payload);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[Controller Error] {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using Core.WcfProtocol;
|
||||
using SHH.Contracts;
|
||||
|
||||
namespace SHH.MjpegPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// 图像载荷转换器 (原 PayloadConverter)
|
||||
/// 职责:抹平传输契约与业务契约之间的差异。
|
||||
/// </summary>
|
||||
public static class ImagePayloadConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// 将视频负载转换为 XWcf 协议并分发至会话池
|
||||
/// </summary>
|
||||
/// <param name="payload">VideoPayload 纯净版契约对象</param>
|
||||
public static void ToXWcfMsg(VideoPayload payload)
|
||||
{
|
||||
if (payload == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
// 1. 自动选择图像源逻辑
|
||||
// Optimized: 优先使用 TargetImage,若为空则退而求其次使用 OriginalImage
|
||||
bool isOriginal = false;
|
||||
byte[]? activeBytes;
|
||||
activeBytes = payload.TargetImageBytes;
|
||||
if (payload.TargetImageBytes == null || payload.TargetImageBytes.Length == 0)
|
||||
{
|
||||
isOriginal = true;
|
||||
activeBytes = payload.OriginalImageBytes;
|
||||
}
|
||||
|
||||
// 如果两者都为空,则不进行分发
|
||||
if (activeBytes == null || activeBytes.Length == 0) return;
|
||||
|
||||
// 同理处理宽高:Target 为 0 则使用 Original
|
||||
int activeWidth = !isOriginal ? payload.TargetWidth : payload.OriginalWidth;
|
||||
int activeHeight = !isOriginal ? payload.TargetHeight : payload.OriginalHeight;
|
||||
|
||||
// 2. 构造分发所需的 UploadImageRequest
|
||||
// Modified: [原因] 适配最新的 VideoPayload 契约字段
|
||||
var req = new UploadImageRequest
|
||||
{
|
||||
// 解析 CameraId。由于旧 req 是 Int64 Id,若 CameraId 是数字字符串则解析,否则处理 Hash
|
||||
Id = long.TryParse(payload.CameraId, out long id) ? id : 0,
|
||||
Name = payload.CameraId, // 将原始 CameraId 存入 Name 字段保留引用
|
||||
|
||||
// 默认类型处理 (可根据 Diagnostics 中的信息动态调整)
|
||||
Type = "0",
|
||||
|
||||
Order = (ulong)payload.CaptureTimestamp, // 使用采集时间戳作为序号
|
||||
Time = UnixMillisecondsToDateTime(payload.CaptureTimestamp),
|
||||
|
||||
ImageBytes = activeBytes, // 零拷贝引用
|
||||
ImageWidth = activeWidth,
|
||||
ImageHeight = activeHeight
|
||||
};
|
||||
|
||||
// 3. 执行核心分发逻辑
|
||||
// 此处调用你之前提供的 O(1) 检索分发方法,确保画面最终流向 DoImageProc
|
||||
MjpegStatics.Sessions.ProcUploadImageRequest(req);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 统一使用项目规范的 _sysLog
|
||||
//_sysLog.Error(ex, "VideoPayload 转换分发失败. CameraId: {CameraId}", payload.CameraId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 辅助方法:Unix 毫秒时间戳转 DateTime
|
||||
/// </summary>
|
||||
private static DateTime UnixMillisecondsToDateTime(long timestamp)
|
||||
{
|
||||
return DateTimeOffset.FromUnixTimeMilliseconds(timestamp).LocalDateTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user