完善契约与客户端、服务端的收发代码

This commit is contained in:
2026-01-03 00:16:28 +08:00
parent d039559402
commit dcf424a86e
30 changed files with 3292 additions and 349 deletions

View File

@@ -1,6 +1,6 @@
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace SHH.Contracts
{
@@ -9,57 +9,90 @@ namespace SHH.Contracts
/// </summary>
public class VideoPayload
{
public List<string> SubscriberIds { get; } = new List<string>(16);
/// <summary>
/// 初始化 <see cref="VideoPayload"/> 类的新实例。
/// </summary>
public VideoPayload()
{
// 预分配一个容量为 16 的列表,以减少内存分配和垃圾回收的压力。
SubscriberIds = new List<string>(16);
}
// ==========================================
// 1. 基础元数据 (将被序列化到 JSON)
// ==========================================
public string CameraId { get; set; } // 摄像头唯一标记
// 时间信息 (建议使用 DateTime调试看日志更直观)
public DateTime CaptureTime { get; set; } // 采集时间 (SDK产生图的时间)
public DateTime DispatchTime { get; set; } // 分发时间 (Server发出图的时间)
// ==========================================
// 2. 图像规格信息
// ==========================================
public int OriginalWidth { get; set; } // 原始宽度
public int OriginalHeight { get; set; } // 原始高度
public int TargetWidth { get; set; } // 目标/处理后宽度
public int TargetHeight { get; set; } // 目标/处理后高度
// ==========================================
// 3. 核心二进制数据 (严禁序列化到 JSON)
// ==========================================
#region --- (Metadata) ---
/// <summary>
/// 原始图像数据 (例如海康SDK出来的原始 JPG)
/// JsonIgnore 防止误操作导致序列化性能崩塌
/// 获取订阅了此帧数据的客户端ID列表。
/// </summary>
public List<string> SubscriberIds { get; }
/// <summary>
/// 获取或设置摄像头的唯一标识符。
/// </summary>
public string CameraId { get; set; }
/// <summary>
/// 获取或设置图像的采集时间即从SDK获取到图像数据的时间。
/// </summary>
public DateTime CaptureTime { get; set; }
/// <summary>
/// 获取或设置图像的分发时间,即服务器准备将此帧数据发送给客户端的时间。
/// </summary>
public DateTime DispatchTime { get; set; }
/// <summary>
/// 获取或设置图像的原始宽度。
/// </summary>
public int OriginalWidth { get; set; }
/// <summary>
/// 获取或设置图像的原始高度。
/// </summary>
public int OriginalHeight { get; set; }
/// <summary>
/// 获取或设置经过处理后的目标图像宽度。
/// </summary>
public int TargetWidth { get; set; }
/// <summary>
/// 获取或设置经过处理后的目标图像高度。
/// </summary>
public int TargetHeight { get; set; }
#endregion
#region --- ---
/// <summary>
/// 获取或设置原始图像的二进制数据例如从SDK直接获取的JPG或YUV数据
/// 此属性被标记为 <see cref="JsonIgnore"/>,以防止在序列化元数据时将其包含在内,从而避免严重的性能问题。
/// </summary>
[JsonIgnore]
public byte[] OriginalImageBytes { get; set; }
/// <summary>
/// 处理后的目标图像 (例如 Yolo 画框后的图,或者缩放后的图)
/// 可为空
/// 获取或设置经过处理后的目标图像的二进制数据例如经过缩放、画框或其他AI处理后的图像
/// 此属性可为空,表示此帧可能只包含原始图像或没有图像数据。
/// 同样,此属性也被标记为 <see cref="JsonIgnore"/>。
/// </summary>
[JsonIgnore]
public byte[] TargetImageBytes { get; set; }
// ==========================================
// 4. 辅助方法
// ==========================================
#endregion
#region --- ---
/// <summary>
/// 仅获取元数据的 JSON 字符串
/// 将当前对象的元数据序列化为一个纯净的 JSON 字符串
/// 此方法会自动忽略所有二进制数据(<see cref="OriginalImageBytes"/> 和 <see cref="TargetImageBytes"/>)。
/// </summary>
/// <returns>包含元数据的 JSON 字符串。</returns>
public string GetMetadataJson()
{
// 创建一个纯净的匿名对象用于序列化
var meta = new
// 创建一个匿名对象,该对象仅包含需要被序列化的元数据字段。
// 这比直接序列化整个对象更安全、更高效。
var metadata = new
{
CameraId,
CaptureTime,
@@ -69,18 +102,24 @@ namespace SHH.Contracts
TargetWidth,
TargetHeight,
SubscriberIds,
// 标记一下是否有目标图方便接收端判断要不要读第3帧
// 附加一个标志,指示此载荷中是否包含目标图像数据,以便接收端进行判断。
HasTargetImage = (TargetImageBytes != null && TargetImageBytes.Length > 0)
};
return JsonConvert.SerializeObject(meta);
return JsonConvert.SerializeObject(metadata);
}
/// <summary>
/// 从 JSON 还原元数据 (还原出来的对象 ImageBytes 默认为空,需后续填充)
/// 从一个 JSON 字符串反序列化,创建一个新的 <see cref="VideoPayload"/> 对象。
/// 注意:反序列化后,对象中的二进制图像数据(<see cref="OriginalImageBytes"/> 和 <see cref="TargetImageBytes"/>)将为 null
/// 需要在后续步骤中手动填充。
/// </summary>
/// <param name="json">包含元数据的 JSON 字符串。</param>
/// <returns>一个新的 <see cref="VideoPayload"/> 对象,其元数据已填充。</returns>
public static VideoPayload FromMetadataJson(string json)
{
return JsonConvert.DeserializeObject<VideoPayload>(json);
}
#endregion
}
}