增加大华设备对云台移动、缩放、聚集、光圈、校时、重启的支持

增加海康、大华对预置点的支持
This commit is contained in:
2026-03-03 13:55:37 +08:00
parent 0399871467
commit d1fc94be1c
15 changed files with 683 additions and 65 deletions

View File

@@ -0,0 +1,81 @@
using Serilog;
using Ayay.SerilogLogs;
namespace SHH.CameraSdk.HikFeatures;
/// <summary>
/// [海康功能组件] 预置点管理实现
/// <para>适配说明:使用 NET_DVR_PTZPreset_Other 接口</para>
/// </summary>
public class HikPresetProvider : IPresetFeature
{
private readonly IHikContext _context;
#region --- PTZ ---
private const uint SET_PRESET = 8; // 设置预置点
private const uint CLE_PRESET = 9; // 清除预置点
private const uint GOTO_PRESET = 39; // 转到预置点
#endregion
public HikPresetProvider(IHikContext context)
{
_context = context;
}
/// <summary>跳转到指定预置点</summary>
public async Task GotoPresetAsync(int presetIndex)
{
await ExecutePresetAction(presetIndex, GOTO_PRESET, "调用");
}
/// <summary>将当前位置保存为预置点</summary>
public async Task SetPresetAsync(int presetIndex)
{
await ExecutePresetAction(presetIndex, SET_PRESET, "保存");
}
/// <summary>删除指定的预置点</summary>
public async Task RemovePresetAsync(int presetIndex)
{
await ExecutePresetAction(presetIndex, CLE_PRESET, "删除");
}
/// <summary>统一执行海康预置点 SDK 调用</summary>
private async Task ExecutePresetAction(int index, uint command, string actionName)
{
int userId = _context.GetUserId();
if (userId < 0) return;
// 位置是从 1 开始, 调用 0 会导致设备重启
if (index == 0) return;
// 海康工业相机通道号通常为 1
int channel = 1;
await Task.Run(() =>
{
// Optimized: [原因] 使用 _Other 接口确保在单机多路并发下通道句柄准确
bool result = HikNativeMethods.NET_DVR_PTZPreset_Other(
userId,
channel,
command,
(uint)index
);
if (!result)
{
uint err = HikNativeMethods.NET_DVR_GetLastError();
Log.ForContext("SourceContext", LogModules.HikVisionSdk)
.Warning("[SDK] Hik 预置点{Action}失败. Index: {Index}, Error: {Error}",
actionName, index, err);
}
else
{
Log.ForContext("SourceContext", LogModules.HikVisionSdk)
.Debug("[SDK] Hik 预置点{Action}成功. Index: {Index}", actionName, index);
}
});
}
}

View File

@@ -1,7 +1,12 @@
namespace SHH.CameraSdk.HikFeatures;
using Ayay.SerilogLogs;
using Serilog;
namespace SHH.CameraSdk.HikFeatures;
public class HikRebootProvider : IRebootFeature
{
private ILogger _sdkLog = Log.ForContext("SourceContext", LogModules.HikVisionSdk);
private readonly IHikContext _context;
public HikRebootProvider(IHikContext context)
@@ -9,6 +14,7 @@ public class HikRebootProvider : IRebootFeature
_context = context;
}
/// <summary>执行异步重启</summary>
public async Task RebootAsync()
{
// 1. 检查登录状态
@@ -23,14 +29,12 @@ public class HikRebootProvider : IRebootFeature
if (!result)
{
uint err = HikNativeMethods.NET_DVR_GetLastError();
_sdkLog.Error("[SDK] Hik 重启指令下发失败. Error: {Error}", err);
throw new Exception($"重启指令发送失败,错误码: {err}");
}
});
// 3. 注意:
// 重启指令发送成功后,设备会断开网络。
// 宿主类(HikVideoSource)的保活机制(KeepAlive)会检测到断线,
// 并自动开始尝试重连,直到设备重启完成上线。
// 所以这里我们不需要手动断开连接,交给底层自愈机制即可。
_sdkLog.Information("[SDK] Hik 重启指令下发成功,设备即将断开连接。");
});
}
}

View File

@@ -349,18 +349,14 @@ public static partial class HikNativeMethods
[DllImport(DllName)]
public static extern uint NET_DVR_GetLastError();
/// <summary>
/// 设置网络连接超时时间和连接尝试次数
/// </summary>
/// <summary>设置网络连接超时时间和连接尝试次数</summary>
/// <param name="dwWaitTime">超时时间(毫秒),推荐 3000ms</param>
/// <param name="dwTryTimes">连接尝试次数,推荐 1 次</param>
/// <returns>设置成功返回 true失败返回 false</returns>
[DllImport(DllName)]
public static extern bool NET_DVR_SetConnectTime(uint dwWaitTime, uint dwTryTimes);
/// <summary>
/// 设置自动重连功能
/// </summary>
/// <summary>设置自动重连功能</summary>
/// <param name="dwInterval">重连间隔(毫秒),推荐 10000ms</param>
/// <param name="bEnableRecon">是否启用重连0-禁用1-启用</param>
/// <returns>设置成功返回 true失败返回 false</returns>
@@ -461,9 +457,7 @@ public static partial class HikNativeMethods
#region --- (Exception Callback Interfaces) ---
/// <summary>
/// 设置连接超时时间和重连策略(兼容旧版本)
/// </summary>
/// <summary>设置连接超时时间和重连策略(兼容旧版本)</summary>
/// <param name="dwInterval">重连间隔(毫秒),建议 3000</param>
/// <param name="bEnableRecon">是否启用重连1-启用0-禁用</param>
/// <returns>设置成功返回 true失败返回 false</returns>
@@ -512,11 +506,20 @@ public static partial class HikNativeMethods
[DllImport(DllName)]
public static extern bool NET_DVR_SetDVRConfig(int lUserID, uint dwCommand, int lChannel, System.IntPtr lpInBuffer, uint dwInBufferSize);
/// <summary>
/// 设备重启
/// </summary>
/// <summary>设备重启</summary>
/// <param name="lUserID"></param>
/// <returns></returns>
[DllImport(DllName)]
public static extern bool NET_DVR_RebootDVR(int lUserID);
/// <summary>
/// [海康 SDK 调用] 云台预置点配置(扩展)
/// </summary>
/// <param name="lUserID">NET_DVR_Login_V40 的返回值</param>
/// <param name="lChannel">通道号 (工业相机通常为 1)</param>
/// <param name="dwPTZPresetCmd">预置点操作命令 (见下文枚举)</param>
/// <param name="dwPresetIndex">预置点序号 (1~255)</param>
/// <returns>TRUE表示成功FALSE表示失败</returns>
[DllImport(DllName)]
public static extern bool NET_DVR_PTZPreset_Other(int lUserID, int lChannel, uint dwPTZPresetCmd, uint dwPresetIndex);
}

View File

@@ -19,7 +19,7 @@ namespace SHH.CameraSdk;
/// <para>✅ 4. [Feat C] 性能优化:在解码回调中使用 <see cref="Monitor.TryEnter"/> 竞争锁,有效规避在设备断开瞬间可能产生的驱动层死锁</para>
/// </summary>
public class HikVideoSource : BaseVideoSource,
IHikContext, ITimeSyncFeature, IRebootFeature, IPtzFeature
IHikContext, ITimeSyncFeature, IRebootFeature, IPtzFeature, IPresetFeature
{
#region --- 1. (Static Resources) ---
@@ -43,6 +43,7 @@ public class HikVideoSource : BaseVideoSource,
private readonly HikTimeSyncProvider _timeProvider;
private readonly HikRebootProvider _rebootProvider;
private readonly HikPtzProvider _ptzProvider;
private readonly HikPresetProvider _presetProvider;
// SDK 句柄与资源
private int _userId = -1; // SDK 登录句柄
@@ -68,9 +69,7 @@ public class HikVideoSource : BaseVideoSource,
#region --- 3. (Constructor) ---
/// <summary>
/// 海康视频源实现
/// </summary>
/// <summary>海康视频源实现</summary>
/// <param name="config"></param>
public HikVideoSource(VideoSourceConfig config) : base(config)
{
@@ -78,6 +77,7 @@ public class HikVideoSource : BaseVideoSource,
_timeProvider = new HikTimeSyncProvider(this);
_rebootProvider = new HikRebootProvider(this);
_ptzProvider = new HikPtzProvider(this);
_presetProvider = new HikPresetProvider(this);
// Modified: [Fix GC Crash] 移除此处的 new REALDATACALLBACK
// 直接使用构造函数初始化的 _realDataCallBack保证委托地址在整个对象生命周期内不变
@@ -89,15 +89,11 @@ public class HikVideoSource : BaseVideoSource,
#region --- 4. IHikContext & Features (Interface Impls) ---
/// <summary>
/// 获取登录句柄
/// </summary>
/// <summary>获取登录句柄</summary>
/// <returns></returns>
public int GetUserId() => _userId; // 暴露父类或私有的 _userId
/// <summary>
/// 获取设备IP
/// </summary>
/// <summary>获取设备IP</summary>
/// <returns></returns>
public string GetDeviceIp() => Config.IpAddress;
@@ -107,22 +103,16 @@ public class HikVideoSource : BaseVideoSource,
/// <returns></returns>
public Task<DateTime> GetTimeAsync() => _timeProvider.GetTimeAsync();
/// <summary>
/// 设置设备时间
/// </summary>
/// <summary>设置设备时间</summary>
/// <param name="time"></param>
/// <returns></returns>
public Task SetTimeAsync(DateTime time) => _timeProvider.SetTimeAsync(time);
/// <summary>
/// 重启设备
/// </summary>
/// <summary>重启设备</summary>
/// <returns></returns>
public Task RebootAsync() => _rebootProvider.RebootAsync();
/// <summary>
/// PTZ 控制
/// </summary>
/// <summary>PTZ 控制</summary>
/// <param name="action"></param>
/// <param name="stop"></param>
/// <param name="speed"></param>
@@ -130,9 +120,7 @@ public class HikVideoSource : BaseVideoSource,
public Task PtzControlAsync(PtzAction action, bool stop, int speed = 4)
=> _ptzProvider.PtzControlAsync(action, stop, speed);
/// <summary>
/// PTZ 步长
/// </summary>
/// <summary>PTZ 步长</summary>
/// <param name="action"></param>
/// <param name="durationMs"></param>
/// <param name="speed"></param>
@@ -140,6 +128,18 @@ public class HikVideoSource : BaseVideoSource,
public Task PtzStepAsync(PtzAction action, int durationMs, int speed = 4)
=> _ptzProvider.PtzStepAsync(action, durationMs, speed);
/// <summary>跳转到预置点</summary>
public Task GotoPresetAsync(int presetIndex)
=> _presetProvider.GotoPresetAsync(presetIndex);
/// <summary>设置/保存当前位置为预置点</summary>
public Task SetPresetAsync(int presetIndex)
=> _presetProvider.SetPresetAsync(presetIndex);
/// <summary>删除预置点</summary>
public Task RemovePresetAsync(int presetIndex)
=> _presetProvider.RemovePresetAsync(presetIndex);
#endregion
#region --- 5. (Lifecycle Overrides) ---