Files

176 lines
6.9 KiB
C#
Raw Permalink Normal View History

namespace SHH.CameraSdk;
/// <summary>
/// 增强型设备元数据中心 (V3.3.1 修复版)
/// 核心职责:
/// <para>1. 封装设备的硬件参数、通道能力、功能集,提供能力自发现</para>
/// <para>2. 支持元数据同步与差异对比,指导上层模块执行差异化处理</para>
/// <para>3. 存储运维指标与 SDK 原生句柄,支撑故障诊断与性能调优</para>
/// 设计特性:只读优先,通过版本号标记同步状态,避免并发修改冲突
/// </summary>
public class DeviceMetadata
{
#region --- 1. (Identity) ---
/// <summary> 设备型号名称(如 DS-2CD3T47G2-LIU </summary>
public string ModelName { get; init; } = "Unknown";
/// <summary> 设备唯一序列号(全局唯一,用于设备溯源) </summary>
public string SerialNumber { get; init; } = string.Empty;
/// <summary> 固件/系统版本号(用于判断 SDK 兼容性) </summary>
public string FirmwareVersion { get; init; } = string.Empty;
/// <summary> 所属厂商/品牌(决定驱动适配逻辑) </summary>
public DeviceBrand Brand { get; init; } = DeviceBrand.Unknown;
/// <summary> 元数据版本号(本地刷新计数,每次同步自增) </summary>
public long Version { get; private set; }
/// <summary> 最后同步时间(标记元数据的最新有效时刻) </summary>
public DateTime LastSyncedAt { get; private set; }
#endregion
#region --- 2. (Cascaded Capabilities) ---
private readonly ReadOnlyCollection<ChannelMetadata> _channels;
/// <summary> 通道元数据集合(只读,防止外部篡改) </summary>
public ReadOnlyCollection<ChannelMetadata> Channels
{
get => _channels;
init => _channels = value ?? new ReadOnlyCollection<ChannelMetadata>(new List<ChannelMetadata>());
}
/// <summary> 设备总通道数量IPC 通常为 1NVR 为接入路数) </summary>
public int ChannelCount => Channels.Count;
/// <summary> 索引器:通过通道号快速获取对应通道的能力描述 </summary>
/// <param name="channelIndex">物理通道号</param>
/// <returns>通道元数据 / 不存在则返回 null</returns>
public ChannelMetadata? this[int channelIndex] =>
Channels.FirstOrDefault(c => c.ChannelIndex == channelIndex);
#endregion
#region --- 3. ---
/// <summary> 设备实时健康度字典(如 CPU 使用率、温度、内存占用等) </summary>
public Dictionary<string, object> HealthMetrics { get; init; } = new();
/// <summary>
/// 厂商 SDK 原始句柄/结构体快照
/// <para>注意事项:</para>
/// <para>1. 标记 [JsonIgnore] 防止序列化非托管指针导致程序崩溃</para>
/// <para>2. 仅用于驱动层与 SDK 交互,上层业务禁止直接操作</para>
/// </summary>
[JsonIgnore]
public object? NativeHandle { get; init; }
/// <summary> 厂商扩展标签(如设备位置、安装时间、责任人等自定义信息) </summary>
public Dictionary<string, string> Tags { get; init; } = new();
#endregion
#region --- 4. (Constructor & Sync) ---
/// <summary>
/// 默认构造函数(用于 BaseVideoSource 初始状态,无通道数据)
/// </summary>
public DeviceMetadata() : this(Enumerable.Empty<ChannelMetadata>()) { }
/// <summary>
/// 完整构造函数(初始化通道元数据集合)
/// </summary>
/// <param name="channels">通道元数据列表</param>
public DeviceMetadata(IEnumerable<ChannelMetadata> channels)
{
// 转换为只读集合,确保通道数据不可变
_channels = new ReadOnlyCollection<ChannelMetadata>(channels?.ToList() ?? new List<ChannelMetadata>());
// 标记初始同步状态
MarkSynced();
}
/// <summary>
/// 标记元数据同步完成
/// <para>作用:更新版本号与同步时间,用于差异对比的基准判断</para>
/// </summary>
public void MarkSynced()
{
Version++;
LastSyncedAt = DateTime.Now;
}
#endregion
#region --- 5. (Business Helpers) ---
/// <summary>
/// 校验动态流配置的合法性(基于设备能力)
/// </summary>
/// <param name="options">待校验的动态配置项</param>
/// <param name="errorMessage">校验失败时的详细原因</param>
/// <returns>合法返回 true非法返回 false</returns>
public bool ValidateOptions(DynamicStreamOptions options, out string errorMessage)
{
errorMessage = string.Empty;
if (options == null) return true;
// 示例校验规则:云台控制权限校验
if (options.VendorExtensions?.ContainsKey("PtzAction") == true
&& !Channels.Any(c => c.SupportPtz))
{
errorMessage = "该设备物理硬件不支持云台控制功能";
return false;
}
// 可扩展其他校验规则:如分辨率合法性、码流类型支持性等
return true;
}
/// <summary>
/// 元数据差异比对逻辑(用于 BaseVideoSource.RefreshMetadataAsync 方法)
/// </summary>
/// <param name="other">最新拉取的设备元数据</param>
/// <returns>元数据差异描述符</returns>
public MetadataDiff CompareWith(DeviceMetadata other)
{
// 入参防护:对比对象为空则返回无差异
if (other == null) return MetadataDiff.None;
return new MetadataDiff
{
// 1. 基础信息变更:任意通道名称变化则标记
NameChanged = this.Channels.Any(c =>
{
var targetChannel = other[c.ChannelIndex];
return targetChannel != null && targetChannel.Name != c.Name;
}),
// 2. 能力集变更PTZ/音频/AI 功能支持状态变化则标记
CapabilityChanged = this.Channels.Any(c =>
{
var targetChannel = other[c.ChannelIndex];
if (targetChannel == null) return false;
return targetChannel.SupportPtz != c.SupportPtz
|| targetChannel.SupportAudioIn != c.SupportAudioIn
|| targetChannel.SupportAiAnalysis != c.SupportAiAnalysis;
}),
// 3. 致命变更:品牌不一致或通道数量变化(设备更换/替换场景)
IsMajorChange = this.Brand != other.Brand || this.ChannelCount != other.ChannelCount,
// 4. 分辨率配置变更:任意通道的分辨率档位数量变化则标记
ResolutionProfilesChanged = this.Channels.Any(c =>
{
var targetChannel = other[c.ChannelIndex];
return targetChannel != null
&& targetChannel.SupportedResolutions.Count != c.SupportedResolutions.Count;
})
};
}
#endregion
}