增加了通过网络主动上报图像的支持

增加了指令维护通道的支持
This commit is contained in:
2026-01-07 10:59:03 +08:00
parent a697aab3e0
commit 3d47c8f009
47 changed files with 1613 additions and 1734 deletions

View File

@@ -0,0 +1,174 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace SHH.Contracts
{
// ==============================================================================
// 1. 物理与运行配置 DTO (对应 CRUD 操作)
// 用于设备新增/全量配置查询,包含基础身份、连接信息、运行参数等全量字段
// ==============================================================================
public class CameraConfigDto
{
// --- 基础身份 (Identity) ---
/// <summary>
/// 设备唯一标识
/// </summary>
[Required(ErrorMessage = "设备ID不能为空")]
[Range(1, long.MaxValue, ErrorMessage = "设备ID必须为正整数")]
public long Id { get; set; }
/// <summary>
/// 设备友好名称
/// </summary>
[MaxLength(64, ErrorMessage = "设备名称长度不能超过64个字符")]
public string Name { get; set; }
/// <summary>
/// 摄像头品牌类型 (0:HikVision, 1:Dahua, 2:RTSP...)
/// </summary>
[Range(0, 10, ErrorMessage = "品牌类型值必须在0-10范围内")]
public int Brand { get; set; }
/// <summary>
/// 设备安装位置描述
/// </summary>
[MaxLength(128, ErrorMessage = "安装位置长度不能超过128个字符")]
public string Location { get; set; }
// --- 主板关联信息 (Metadata) ---
/// <summary>
/// 关联主板IP地址
/// </summary>
[RegularExpression(@"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)?$",
ErrorMessage = "IPv4地址")]
public string MainboardIp { get; set; } = string.Empty;
/// <summary>
/// 关联主板端口
/// </summary>
[Range(0, 65535, ErrorMessage = "主板端口号必须在1-65535范围内")]
public int MainboardPort { get; set; } = 0;
// --- 核心连接 (Connectivity) - 修改此类参数触发冷重启 ---
/// <summary>
/// 摄像头IP地址
/// </summary>
[Required(ErrorMessage = "IP地址不能为空")]
[RegularExpression(@"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$",
ErrorMessage = "IPv4地址")]
public string IpAddress { get; set; }
/// <summary>
/// 登录用户名
/// </summary>
[MaxLength(32, ErrorMessage = "用户名长度不能超过32个字符")]
public string Username { get; set; }
/// <summary>
/// 登录密码
/// </summary>
[MaxLength(64, ErrorMessage = "密码长度不能超过64个字符")]
public string Password { get; set; }
/// <summary>
/// SDK端口 (如海康默认8000)
/// </summary>
[Range(1, 65535, ErrorMessage = "端口号必须在1-65535范围内")]
public ushort Port { get; set; }
/// <summary>
/// 通道号 (通常为1)
/// </summary>
[Range(0, 256, ErrorMessage = "通道号必须在0-256范围内")]
public int ChannelIndex { get; set; }
/// <summary>
/// 码流类型 (0:主码流, 1:子码流)
/// </summary>
[Range(0, 1, ErrorMessage = "码流类型只能是0(主码流)或1(子码流)")]
public int StreamType { get; set; }
// 渲染句柄 (通常下发时为0由本地窗口绑定时再指定或者此处仅作占位)
public long RenderHandle { get; set; }
/// <summary>
/// RTSP流路径 (备用或非SDK模式使用)
/// </summary>
[MaxLength(256, ErrorMessage = "RTSP地址长度不能超过256个字符")]
public string RtspPath { get; set; }
// --- 运行时参数 (Runtime Options) - 支持热更新 ---
/// <summary>
/// 是否使用灰度图 (用于AI分析场景加速)
/// </summary>
public bool UseGrayscale { get; set; } = false;
/// <summary>
/// 是否启用图像增强 (去噪/锐化等)
/// </summary>
public bool EnhanceImage { get; set; } = true;
// --- 画面变换 (Transform) - 支持热更新 ---
/// <summary>
/// 是否允许图像压缩 (降低带宽占用)
/// </summary>
public bool AllowCompress { get; set; } = true;
/// <summary>
/// 是否允许图像放大 (提升渲染质量)
/// </summary>
public bool AllowExpand { get; set; } = false;
/// <summary>
/// 目标分辨率 (格式如 1920x1080空则保持原图)
/// </summary>
[RegularExpression(@"^\d+x\d+$", ErrorMessage = "分辨率格式必须为 宽度x高度 (如 1920x1080)")]
public string TargetResolution { get; set; } = string.Empty;
/// <summary>
/// 随配置一并下发的自动订阅请求
/// </summary>
public List<CameraConfigSubscribeDto> AutoSubscriptions { get; set; }
= new List<CameraConfigSubscribeDto>();
/// <summary>
/// 是否立即执行
/// </summary>
public bool ImmediateExecution { get; set; }
}
/// <summary>
/// 订阅项
/// </summary>
public class CameraConfigSubscribeDto
{
/// <summary>
/// 订阅标识
/// </summary>
public string AppId { get; set; }
/// <summary>
/// 订阅业务类型 SubscriptionType
/// </summary>
public int Type { get; set; }
/// <summary>
/// 要求的帧率8帧或1帧
/// </summary>
public int TargetFps { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Memo { get; set; }
/// <summary>
/// 是否需要高清晰度
/// </summary>
public bool NeedHighDefinition { get; set; }
= false;
}
}

View File

@@ -6,6 +6,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
</ItemGroup>
</Project>

View File

@@ -1,120 +1,81 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
// 注意:如果不想依赖 Newtonsoft也可以用 System.Text.Json但 Newtonsoft 在 Std 2.0 中兼容性更好
namespace SHH.Contracts
{
/// <summary>
/// 视频数据传输契约(增强版
/// 视频数据传输契约(纯净版 POCO
/// </summary>
public class VideoPayload
{
/// <summary>
/// 初始化 <see cref="VideoPayload"/> 类的新实例。
/// </summary>
public VideoPayload()
{
// 预分配一个容量为 16 的列表,以减少内存分配和垃圾回收的压力。
SubscriberIds = new List<string>(16);
Diagnostics = new Dictionary<string, object>(4);
}
#region --- (Metadata) ---
#region --- 1. (Metadata) ---
/// <summary>
/// 获取订阅了此帧数据的客户端ID列表。
/// </summary>
public List<string> SubscriberIds { get; }
/// <summary>
/// 获取或设置摄像头的唯一标识符。
/// </summary>
public string CameraId { get; set; }
/// <summary>
/// 获取或设置图像的采集时间即从SDK获取到图像数据的时间。
/// 采集时间戳 (Unix 毫秒)
/// </summary>
public DateTime CaptureTime { get; set; }
public long CaptureTimestamp { get; set; }
/// <summary>
/// 获取或设置图像的分发时间,即服务器准备将此帧数据发送给客户端的时间。
/// 分发时间戳 (Unix 毫秒)
/// </summary>
public DateTime DispatchTime { get; set; }
public long DispatchTimestamp { get; set; }
/// <summary>
/// 获取或设置图像的原始宽度。
/// </summary>
public int OriginalWidth { get; set; }
/// <summary>
/// 获取或设置图像的原始高度。
/// </summary>
public int OriginalHeight { get; set; }
/// <summary>
/// 获取或设置经过处理后的目标图像宽度。
/// </summary>
public int TargetWidth { get; set; }
public int TargetHeight { get; set; }
public List<string> SubscriberIds { get; }
public Dictionary<string, object> Diagnostics { get; }
/// <summary>
/// 获取或设置经过处理后的目标图像高度。
/// 指示标志:是否存在原始图
/// </summary>
public int TargetHeight { get; set; }
public bool HasOriginalImage { get; set; }
/// <summary>
/// 指示标志:是否存在处理图
/// </summary>
public bool HasTargetImage { get; set; }
#endregion
#region --- ---
#region --- 2. (Binary) ---
/// <summary>
/// 获取或设置原始图像的二进制数据例如从SDK直接获取的JPG或YUV数据
/// 此属性被标记为 <see cref="JsonIgnore"/>,以防止在序列化元数据时将其包含在内,从而避免严重的性能问题。
/// </summary>
// 标记 JsonIgnore防止被错误序列化
[JsonIgnore]
public byte[] OriginalImageBytes { get; set; }
/// <summary>
/// 获取或设置经过处理后的目标图像的二进制数据例如经过缩放、画框或其他AI处理后的图像
/// 此属性可为空,表示此帧可能只包含原始图像或没有图像数据。
/// 同样,此属性也被标记为 <see cref="JsonIgnore"/>。
/// </summary>
[JsonIgnore]
public byte[] TargetImageBytes { get; set; }
#endregion
#region --- ---
#region --- 3. ( JSON ) ---
/// <summary>
/// 将当前对象的元数据序列化为一个纯净的 JSON 字符串
/// 此方法会自动忽略所有二进制数据(<see cref="OriginalImageBytes"/> 和 <see cref="TargetImageBytes"/>)。
/// 获取纯元数据的 JSON 字符串
/// </summary>
/// <returns>包含元数据的 JSON 字符串。</returns>
public string GetMetadataJson()
{
// 创建一个匿名对象,该对象仅包含需要被序列化的元数据字段。
// 这比直接序列化整个对象更安全、更高效。
var metadata = new
{
CameraId,
CaptureTime,
DispatchTime,
OriginalWidth,
OriginalHeight,
TargetWidth,
TargetHeight,
SubscriberIds,
// 附加一个标志,指示此载荷中是否包含目标图像数据,以便接收端进行判断。
HasTargetImage = (TargetImageBytes != null && TargetImageBytes.Length > 0)
};
return JsonConvert.SerializeObject(metadata);
// 在序列化前自动更新标志位,防止逻辑不同步
this.HasOriginalImage = (OriginalImageBytes != null && OriginalImageBytes.Length > 0);
this.HasTargetImage = (TargetImageBytes != null && TargetImageBytes.Length > 0);
return JsonConvert.SerializeObject(this);
}
/// <summary>
/// 从一个 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);