核心代码格式化
This commit is contained in:
@@ -8,85 +8,69 @@ using System.Security;
|
||||
namespace SHH.CameraSdk;
|
||||
|
||||
/// <summary>
|
||||
/// [海康驱动] 工业级视频源实现 V3.4.0 (运维增强版)
|
||||
/// 修复记录:
|
||||
/// 1. [Fix Bug Z] 控制器遮蔽:移除子类 Controller 定义,复用基类实例,修复 FPS 控制失效问题。
|
||||
/// 2. [Feat A] 热更新支持:实现 OnApplyOptions,支持码流/句柄不亦断线热切换。
|
||||
/// 3. [Feat B] 审计集成:全面接入 AddAuditLog,对接 Web 运维仪表盘。
|
||||
/// [海康驱动] 工业级视频源实现 V3.5.0 (运维增强版)
|
||||
/// <para>技术支撑:基于 Hikvision CH-NetSDK V6.1.x 开发</para>
|
||||
/// <para>核心职责:深度封装海康私有协议,实现从原始私有码流到 BGR 零拷贝帧池的高性能转换与分发</para>
|
||||
/// 关键修复与增强记录:
|
||||
/// <para>✅ 1. [Fix Bug Z] 架构修正:移除子类冗余的 Controller 定义,强制复用基类 <see cref="BaseVideoSource.Controller"/>,彻底修复多路并发下的 FPS 流控失效问题</para>
|
||||
/// <para>✅ 2. [Feat A] 热更新支持:重写 <see cref="OnApplyOptions"/>,实现码流类型(Main/Sub)与渲染句柄的动态热切换,无需重启设备链路即可生效</para>
|
||||
/// <para>✅ 3. [Feat B] 运维集成:全链路接入 <see cref="BaseVideoSource.AddAuditLog"/>,将登录、取流、重连及 SDK 报警实时推送至 Web 运维仪表盘</para>
|
||||
/// <para>✅ 4. [Feat C] 性能优化:在解码回调中使用 <see cref="Monitor.TryEnter"/> 竞争锁,有效规避在设备断开瞬间可能产生的驱动层死锁</para>
|
||||
/// </summary>
|
||||
public class HikVideoSource : BaseVideoSource,
|
||||
IHikContext, ITimeSyncFeature, IRebootFeature, IPtzFeature
|
||||
{
|
||||
#region --- 静态资源 (Global Resources) ---
|
||||
#region --- 1. 静态资源与全局路由 (Static Resources) ---
|
||||
|
||||
// 日志实例
|
||||
/// <summary> 海康 SDK 专用日志实例 </summary>
|
||||
protected override ILogger _sdkLog => Log.ForContext("SourceContext", LogModules.HikVisionSdk);
|
||||
|
||||
// 静态路由表
|
||||
/// <summary> 全局句柄映射表:用于静态异常回调分发至具体实例 </summary>
|
||||
private static readonly ConcurrentDictionary<int, HikVideoSource> _instances = new();
|
||||
// 全局异常回调
|
||||
|
||||
/// <summary> 静态异常回调委托引用 </summary>
|
||||
private static readonly HikNativeMethods.EXCEPTION_CALLBACK _globalExceptionCallback = StaticOnSdkException;
|
||||
// 端口抢占锁
|
||||
|
||||
/// <summary> 全局播放端口抢占锁 </summary>
|
||||
private static readonly object _globalPortLock = new();
|
||||
|
||||
#endregion
|
||||
|
||||
// 声明组件
|
||||
#region --- 2. 实例成员与组件引用 (Instance Members) ---
|
||||
|
||||
// 协议功能组件
|
||||
private readonly HikTimeSyncProvider _timeProvider;
|
||||
private readonly HikRebootProvider _rebootProvider;
|
||||
private readonly HikPtzProvider _ptzProvider;
|
||||
|
||||
// ==========================================
|
||||
// 实现 IHikContext (核心数据暴露)
|
||||
// ==========================================
|
||||
public int GetUserId() => _userId; // 暴露父类或私有的 _userId
|
||||
public string GetDeviceIp() => Config.IpAddress;
|
||||
|
||||
// ==========================================
|
||||
// 实现 ITimeSyncFeature (路由转发)
|
||||
// ==========================================
|
||||
// 核心逻辑:全部委托给 _timeProvider 处理,自己不写一行逻辑
|
||||
public Task<DateTime> GetTimeAsync() => _timeProvider.GetTimeAsync();
|
||||
|
||||
public Task SetTimeAsync(DateTime time) => _timeProvider.SetTimeAsync(time);
|
||||
|
||||
public Task RebootAsync() => _rebootProvider.RebootAsync();
|
||||
|
||||
public Task PtzControlAsync(PtzAction action, bool stop, int speed = 4)
|
||||
=> _ptzProvider.PtzControlAsync(action, stop, speed);
|
||||
|
||||
public Task PtzStepAsync(PtzAction action, int durationMs, int speed = 4)
|
||||
=> _ptzProvider.PtzStepAsync(action, durationMs, speed);
|
||||
|
||||
#region --- 实例成员 (Instance Members) ---
|
||||
|
||||
// SDK 句柄与资源
|
||||
private int _userId = -1; // SDK 登录句柄
|
||||
private int _realPlayHandle = -1; // 预览句柄
|
||||
private int _playPort = -1; // 播放端口
|
||||
|
||||
private readonly object _initLock = new();
|
||||
private readonly object _bufferLock = new();
|
||||
// 同步控制
|
||||
private readonly object _initLock = new(); // 登录句柄初始化锁
|
||||
private readonly object _bufferLock = new(); // 帧缓冲锁
|
||||
private volatile int _connectionEpoch = 0; // 连接轮询版本号
|
||||
|
||||
private volatile int _connectionEpoch = 0;
|
||||
|
||||
// 回调委托引用 (防止GC)
|
||||
// 回调委托(强引用防止GC回收)
|
||||
private HikNativeMethods.REALDATACALLBACK? _realDataCallBack;
|
||||
private HikPlayMethods.DECCBFUN? _decCallBack;
|
||||
|
||||
// 内存复用对象
|
||||
// 图像处理资源, 内存复用对象
|
||||
private Mat? _sharedYuvMat;
|
||||
private Mat? _sharedBgrMat; // (如有需要可复用,当前逻辑直接用FramePool)
|
||||
|
||||
private Mat? _sharedBgrMat;
|
||||
private FramePool? _framePool;
|
||||
private bool _isPoolReady = false;
|
||||
|
||||
// 【关键修复 Bug Z】: 删除了这里原本的 "public FrameController Controller..."
|
||||
// 直接使用 BaseVideoSource.Controller
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 构造函数 (Constructor) ---
|
||||
#region --- 3. 构造函数 (Constructor) ---
|
||||
|
||||
/// <summary>
|
||||
/// 海康视频源实现
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
public HikVideoSource(VideoSourceConfig config) : base(config)
|
||||
{
|
||||
// 初始化组件,将 "this" 作为上下文传进去
|
||||
@@ -97,8 +81,70 @@ public class HikVideoSource : BaseVideoSource,
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 核心生命周期 (Core Lifecycle) ---
|
||||
#region --- 4. 接口实现:IHikContext & Features (Interface Impls) ---
|
||||
|
||||
/// <summary>
|
||||
/// 获取登录句柄
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetUserId() => _userId; // 暴露父类或私有的 _userId
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备IP
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetDeviceIp() => Config.IpAddress;
|
||||
|
||||
/// <summary>
|
||||
/// 核心逻辑:全部委托给 _timeProvider 处理,自己不写一行逻辑
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task<DateTime> GetTimeAsync() => _timeProvider.GetTimeAsync();
|
||||
|
||||
/// <summary>
|
||||
/// 设置设备时间
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <returns></returns>
|
||||
public Task SetTimeAsync(DateTime time) => _timeProvider.SetTimeAsync(time);
|
||||
|
||||
/// <summary>
|
||||
/// 重启设备
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task RebootAsync() => _rebootProvider.RebootAsync();
|
||||
|
||||
/// <summary>
|
||||
/// PTZ 控制
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="stop"></param>
|
||||
/// <param name="speed"></param>
|
||||
/// <returns></returns>
|
||||
public Task PtzControlAsync(PtzAction action, bool stop, int speed = 4)
|
||||
=> _ptzProvider.PtzControlAsync(action, stop, speed);
|
||||
|
||||
/// <summary>
|
||||
/// PTZ 步长
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <param name="durationMs"></param>
|
||||
/// <param name="speed"></param>
|
||||
/// <returns></returns>
|
||||
public Task PtzStepAsync(PtzAction action, int durationMs, int speed = 4)
|
||||
=> _ptzProvider.PtzStepAsync(action, durationMs, speed);
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 5. 生命周期重写 (Lifecycle Overrides) ---
|
||||
|
||||
/// <summary>
|
||||
/// 启动逻辑
|
||||
/// </summary>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="CameraException"></exception>
|
||||
/// <exception cref="OperationCanceledException"></exception>
|
||||
protected override async Task OnStartAsync(CancellationToken token)
|
||||
{
|
||||
int currentEpoch = Interlocked.Increment(ref _connectionEpoch);
|
||||
@@ -171,6 +217,10 @@ public class HikVideoSource : BaseVideoSource,
|
||||
}, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止逻辑
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override async Task OnStopAsync()
|
||||
{
|
||||
Interlocked.Increment(ref _connectionEpoch);
|
||||
@@ -184,6 +234,9 @@ public class HikVideoSource : BaseVideoSource,
|
||||
AddAuditLog($"[SDK] Hik 设备已停止. => ID:{_config.Id} IP:{_config.IpAddress} Port:{_config.Port} Name:{_config.Name}, UserID: {_userId}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步清理所有 SDK 资源
|
||||
/// </summary>
|
||||
private void CleanupSync()
|
||||
{
|
||||
lock (_initLock)
|
||||
@@ -268,11 +321,20 @@ public class HikVideoSource : BaseVideoSource,
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取设备元数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override Task<DeviceMetadata> OnFetchMetadataAsync() => Task.FromResult(new DeviceMetadata());
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- [新功能] 动态参数热应用 (Hot Swap) ---
|
||||
#region --- 6. 驱动逻辑:热切换重写 (OnApplyOptions) ---
|
||||
|
||||
// 【关键修复 Feat A】实现基类的抽象方法,处理码流切换
|
||||
/// <summary>
|
||||
/// 配置更新
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
protected override void OnApplyOptions(DynamicStreamOptions options)
|
||||
{
|
||||
// 1. 码流热切换逻辑
|
||||
@@ -343,8 +405,12 @@ public class HikVideoSource : BaseVideoSource,
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 网络取流 (Network Streaming) ---
|
||||
|
||||
#region --- 7. 驱动逻辑:取流与解码 (Streaming & Decoding) ---
|
||||
|
||||
/// <summary>
|
||||
/// 开始预览
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool StartRealPlay()
|
||||
{
|
||||
var previewInfo = new HikNativeMethods.NET_DVR_PREVIEWINFO
|
||||
@@ -361,6 +427,14 @@ public class HikVideoSource : BaseVideoSource,
|
||||
return _realPlayHandle >= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预览数据回调
|
||||
/// </summary>
|
||||
/// <param name="lRealHandle"></param>
|
||||
/// <param name="dwDataType"></param>
|
||||
/// <param name="pBuffer"></param>
|
||||
/// <param name="dwBufSize"></param>
|
||||
/// <param name="pUser"></param>
|
||||
private void SafeOnRealDataReceived(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser)
|
||||
{
|
||||
try
|
||||
@@ -414,11 +488,15 @@ public class HikVideoSource : BaseVideoSource,
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 解码与帧分发 (Decoding) ---
|
||||
|
||||
// 必须同时加上 SecurityCritical
|
||||
/// <summary>
|
||||
/// 必须同时加上 SecurityCritical
|
||||
/// </summary>
|
||||
/// <param name="nPort"></param>
|
||||
/// <param name="pBuf"></param>
|
||||
/// <param name="nSize"></param>
|
||||
/// <param name="pFrameInfo"></param>
|
||||
/// <param name="nReserved1"></param>
|
||||
/// <param name="nReserved2"></param>
|
||||
[HandleProcessCorruptedStateExceptions]
|
||||
[SecurityCritical]
|
||||
private void SafeOnDecodingCallBack(int nPort, IntPtr pBuf, int nSize, ref HikPlayMethods.FRAME_INFO pFrameInfo, int nReserved1, int nReserved2)
|
||||
@@ -536,8 +614,15 @@ public class HikVideoSource : BaseVideoSource,
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 异常处理 ---
|
||||
#region --- 8. 全局异常静态回调 ---
|
||||
|
||||
/// <summary>
|
||||
/// SDK 报警回调
|
||||
/// </summary>
|
||||
/// <param name="dwType"></param>
|
||||
/// <param name="lUserID"></param>
|
||||
/// <param name="lHandle"></param>
|
||||
/// <param name="pUser"></param>
|
||||
private static void StaticOnSdkException(uint dwType, int lUserID, int lHandle, IntPtr pUser)
|
||||
{
|
||||
try
|
||||
@@ -558,6 +643,4 @@ public class HikVideoSource : BaseVideoSource,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override Task<DeviceMetadata> OnFetchMetadataAsync() => Task.FromResult(new DeviceMetadata());
|
||||
}
|
||||
Reference in New Issue
Block a user