2026-01-03 00:16:28 +08:00
|
|
|
|
using System;
|
2025-12-31 20:43:54 +08:00
|
|
|
|
using System.Collections.Generic;
|
2026-01-03 00:16:28 +08:00
|
|
|
|
using Newtonsoft.Json;
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
|
|
|
|
|
namespace SHH.Contracts
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 视频数据传输契约(增强版)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class VideoPayload
|
|
|
|
|
|
{
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化 <see cref="VideoPayload"/> 类的新实例。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public VideoPayload()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 预分配一个容量为 16 的列表,以减少内存分配和垃圾回收的压力。
|
|
|
|
|
|
SubscriberIds = new List<string>(16);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region --- 元数据 (Metadata) ---
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取订阅了此帧数据的客户端ID列表。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<string> SubscriberIds { get; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置摄像头的唯一标识符。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string CameraId { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图像的采集时间,即从SDK获取到图像数据的时间。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public DateTime CaptureTime { get; set; }
|
2025-12-31 20:43:54 +08:00
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图像的分发时间,即服务器准备将此帧数据发送给客户端的时间。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public DateTime DispatchTime { get; set; }
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图像的原始宽度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int OriginalWidth { get; set; }
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置图像的原始高度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int OriginalHeight { get; set; }
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置经过处理后的目标图像宽度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int TargetWidth { get; set; }
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置经过处理后的目标图像高度。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int TargetHeight { get; set; }
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
#endregion
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
#region --- 核心二进制数据 ---
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// 获取或设置原始图像的二进制数据(例如,从SDK直接获取的JPG或YUV数据)。
|
|
|
|
|
|
/// 此属性被标记为 <see cref="JsonIgnore"/>,以防止在序列化元数据时将其包含在内,从而避免严重的性能问题。
|
2025-12-29 08:09:14 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
|
public byte[] OriginalImageBytes { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// 获取或设置经过处理后的目标图像的二进制数据(例如,经过缩放、画框或其他AI处理后的图像)。
|
|
|
|
|
|
/// 此属性可为空,表示此帧可能只包含原始图像或没有图像数据。
|
|
|
|
|
|
/// 同样,此属性也被标记为 <see cref="JsonIgnore"/>。
|
2025-12-29 08:09:14 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
|
public byte[] TargetImageBytes { get; set; }
|
|
|
|
|
|
|
2026-01-03 00:16:28 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region --- 序列化与反序列化辅助方法 ---
|
2025-12-29 08:09:14 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// 将当前对象的元数据序列化为一个纯净的 JSON 字符串。
|
|
|
|
|
|
/// 此方法会自动忽略所有二进制数据(<see cref="OriginalImageBytes"/> 和 <see cref="TargetImageBytes"/>)。
|
2025-12-29 08:09:14 +08:00
|
|
|
|
/// </summary>
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <returns>包含元数据的 JSON 字符串。</returns>
|
2025-12-29 08:09:14 +08:00
|
|
|
|
public string GetMetadataJson()
|
|
|
|
|
|
{
|
2026-01-03 00:16:28 +08:00
|
|
|
|
// 创建一个匿名对象,该对象仅包含需要被序列化的元数据字段。
|
|
|
|
|
|
// 这比直接序列化整个对象更安全、更高效。
|
|
|
|
|
|
var metadata = new
|
2025-12-29 08:09:14 +08:00
|
|
|
|
{
|
|
|
|
|
|
CameraId,
|
|
|
|
|
|
CaptureTime,
|
|
|
|
|
|
DispatchTime,
|
|
|
|
|
|
OriginalWidth,
|
|
|
|
|
|
OriginalHeight,
|
|
|
|
|
|
TargetWidth,
|
|
|
|
|
|
TargetHeight,
|
2025-12-31 20:43:54 +08:00
|
|
|
|
SubscriberIds,
|
2026-01-03 00:16:28 +08:00
|
|
|
|
// 附加一个标志,指示此载荷中是否包含目标图像数据,以便接收端进行判断。
|
2025-12-29 08:09:14 +08:00
|
|
|
|
HasTargetImage = (TargetImageBytes != null && TargetImageBytes.Length > 0)
|
|
|
|
|
|
};
|
2026-01-03 00:16:28 +08:00
|
|
|
|
return JsonConvert.SerializeObject(metadata);
|
2025-12-29 08:09:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// 从一个 JSON 字符串反序列化,创建一个新的 <see cref="VideoPayload"/> 对象。
|
|
|
|
|
|
/// 注意:反序列化后,对象中的二进制图像数据(<see cref="OriginalImageBytes"/> 和 <see cref="TargetImageBytes"/>)将为 null,
|
|
|
|
|
|
/// 需要在后续步骤中手动填充。
|
2025-12-29 08:09:14 +08:00
|
|
|
|
/// </summary>
|
2026-01-03 00:16:28 +08:00
|
|
|
|
/// <param name="json">包含元数据的 JSON 字符串。</param>
|
|
|
|
|
|
/// <returns>一个新的 <see cref="VideoPayload"/> 对象,其元数据已填充。</returns>
|
2025-12-29 08:09:14 +08:00
|
|
|
|
public static VideoPayload FromMetadataJson(string json)
|
|
|
|
|
|
{
|
|
|
|
|
|
return JsonConvert.DeserializeObject<VideoPayload>(json);
|
|
|
|
|
|
}
|
2026-01-03 00:16:28 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-12-29 08:09:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|