diff --git a/Cis.sln b/Cis.sln
index 3ce8f72..cbb9209 100644
--- a/Cis.sln
+++ b/Cis.sln
@@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cis.Core", "Cis.Core\Cis.Co
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cis.Web.Entry", "Cis.Web.Entry\Cis.Web.Entry.csproj", "{9826E365-EEE9-4721-A738-B02AB64D47E5}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EC.Helper", "EC.Helper\EC.Helper.csproj", "{C2A5AEC8-F4FB-4D57-AE32-80502979FB9E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +35,10 @@ Global
{9826E365-EEE9-4721-A738-B02AB64D47E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9826E365-EEE9-4721-A738-B02AB64D47E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9826E365-EEE9-4721-A738-B02AB64D47E5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C2A5AEC8-F4FB-4D57-AE32-80502979FB9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C2A5AEC8-F4FB-4D57-AE32-80502979FB9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C2A5AEC8-F4FB-4D57-AE32-80502979FB9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C2A5AEC8-F4FB-4D57-AE32-80502979FB9E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/EC.Helper/CameraSDK/Common/CameraStruct.cs b/EC.Helper/CameraSDK/Common/CameraStruct.cs
new file mode 100644
index 0000000..42f6e27
--- /dev/null
+++ b/EC.Helper/CameraSDK/Common/CameraStruct.cs
@@ -0,0 +1,164 @@
+namespace EC.Helper.CameraSDK;
+
+///
+/// 相机信息
+///
+public class CameraInfo
+{
+ #region Attr
+
+ ///
+ /// 相机类型
+ ///
+ public int Type { get; set; }
+
+ ///
+ /// ip 地址
+ ///
+ public string Ip { get; set; } = string.Empty;
+
+ ///
+ /// 端口
+ ///
+ public int Port { get; set; }
+
+ ///
+ /// 账号
+ ///
+ public string UserName { get; set; } = string.Empty;
+
+ ///
+ /// 密码
+ ///
+ public string Password { get; set; } = string.Empty;
+
+ #endregion Attr
+
+ public static CameraInfo New(int type, string ip, int port, string userName, string password)
+ {
+ CameraInfo info = new() { Type = type, Ip = ip, Port = port, UserName = userName, Password = password };
+ if (port <= 0)
+ throw new Exception("Camera type not support.");
+ return info;
+ }
+
+ public static CameraInfo New(int type, string ip, string userName, string password)
+ {
+ CameraInfo info = new() { Type = type, Ip = ip, UserName = userName, Password = password };
+ int port = (CameraType)type switch
+ {
+ CameraType.HiK => CameraPort.HiK,
+ CameraType.DaHua => CameraPort.DaHua,
+ CameraType.YuShi => CameraPort.YuShi,
+ _ => -1,
+ };
+ info.Port = port;
+ if (port <= 0)
+ throw new Exception("Camera type not support.");
+ return info;
+ }
+}
+
+///
+/// 相机类型
+///
+public enum CameraType
+{
+ HiK = 0,
+ DaHua = 1,
+ YuShi = 2,
+}
+
+///
+/// 相机默认连接端口
+///
+public class CameraPort
+{
+ public const int HiK = 8000;
+ public const int DaHua = 37777;
+ public const int YuShi = 8800;
+}
+
+///
+/// Ptz 信息
+///
+public class PtzInfo
+{
+ #region Attr
+
+ public double Pan { get; set; }
+ public double Tilt { get; set; }
+ public double Zoom { get; set; }
+
+ #endregion Attr
+
+ public PtzInfo(double pan, double tilt, double zoom)
+ {
+ Pan = pan;
+ Tilt = tilt;
+ Zoom = zoom;
+ }
+
+ public static PtzInfo Default
+ {
+ get { return new(0, 0, 0); }
+ }
+
+ public static PtzInfo New(double pan, double tilt, double zoom)
+ {
+ return new PtzInfo(pan, tilt, zoom);
+ }
+}
+
+///
+/// 相机异常
+///
+public class CameraException : Exception
+{
+ public CameraException() : base()
+ {
+ }
+
+ public CameraException(string? message) : base(message)
+ {
+ }
+
+ public CameraException(string? message, Exception? innerException) : base(message, innerException)
+ {
+ }
+
+ protected class CameraExceptionObj
+ {
+ public CameraType Type { get; set; }
+
+ public int ErrCode { get; set; }
+
+ public string? ErrMsg { get; set; }
+
+ public override string? ToString()
+ {
+ return $"Type:{Type}, ErrCode:{ErrCode}, ErrMsg:{ErrMsg}";
+ }
+ }
+
+ public static CameraException New(CameraType type, int errCode)
+ {
+ CameraExceptionObj obj = new()
+ {
+ Type = type,
+ ErrCode = errCode
+ };
+ return new CameraException(obj.ToString());
+ }
+
+ public static CameraException New(CameraType type, int errCode, string errMsg)
+ {
+ CameraExceptionObj obj = new()
+ {
+ Type = type,
+ ErrCode = errCode,
+ ErrMsg = errMsg
+ };
+ return new CameraException(obj.ToString());
+ }
+}
\ No newline at end of file
diff --git a/EC.Helper/CameraSDK/Common/ICameraSDK.cs b/EC.Helper/CameraSDK/Common/ICameraSDK.cs
new file mode 100644
index 0000000..b23107a
--- /dev/null
+++ b/EC.Helper/CameraSDK/Common/ICameraSDK.cs
@@ -0,0 +1,52 @@
+namespace EC.Helper.CameraSDK;
+
+public abstract class ICameraSDK
+{
+ #region Attr
+
+ protected CameraInfo CameraInfo { get; set; }
+
+ #endregion Attr
+
+ public ICameraSDK(CameraInfo cameraInfo)
+ {
+ CameraInfo = cameraInfo;
+ }
+
+ #region Base Method
+
+ ///
+ /// 初始化资源
+ ///
+ ///
+ public abstract bool Init();
+
+ ///
+ /// 释放资源
+ ///
+ ///
+ public abstract bool Destory();
+
+ ///
+ /// 连接是否成功
+ ///
+ ///
+ public abstract bool ConnectSuccess();
+
+ ///
+ /// 处理异常
+ ///
+ public abstract void BuildException();
+
+ #endregion Base Method
+
+ #region Main Method
+
+ ///
+ /// 获取 ptz
+ ///
+ ///
+ public abstract PtzInfo GetPtzInfo();
+
+ #endregion Main Method
+}
\ No newline at end of file
diff --git a/EC.Helper/CameraSDK/DaHua/DaHuaOriSDK.cs b/EC.Helper/CameraSDK/DaHua/DaHuaOriSDK.cs
new file mode 100644
index 0000000..0d1154c
--- /dev/null
+++ b/EC.Helper/CameraSDK/DaHua/DaHuaOriSDK.cs
@@ -0,0 +1,848 @@
+//#define Linux32
+//#define Linux64
+//#define Win32
+//#define Win64
+
+using System.Runtime.InteropServices;
+
+namespace EC.Helper.CameraSDK;
+
+public static class DaHuaOriSDK
+{
+ #region Lib Attr
+
+#if (Linux32)
+ private const string LibDhNetSDK = @"./libs/dahua/linux32/libdhnetsdk.so";
+#elif (Linux64)
+ private const string LibDhNetSDK = @"./libs/dahua/linux64/libdhnetsdk.so";
+#elif (Win32)
+ private const string LibDhNetSDK = @"./libs/dahua/win32/dhnetsdk.dll";
+#elif (Win64)
+ private const string LibDhNetSDK = @"./libs/dahua/win64/dhnetsdk.dll";
+#endif
+
+ #endregion Lib Attr
+
+ static DaHuaOriSDK()
+ {
+ GlobalInit();
+ }
+
+ #region Global
+
+ public static bool InitSuccess { get; private set; }
+
+ public static bool GlobalInit()
+ {
+ if (InitSuccess) return true;
+ bool ret = CLIENT_InitEx(null, IntPtr.Zero, IntPtr.Zero);
+ InitSuccess = ret;
+ if (!ret) throw new Exception("DaHuaOriSDK global init failure.");
+ return ret;
+ }
+
+ public static bool GlobalDestory()
+ {
+ if (!InitSuccess) return true;
+ CLIENT_Cleanup();
+ InitSuccess = false;
+ return true;
+ }
+
+ #endregion Global
+
+ #region SDK Enum
+
+ ///
+ /// login device mode enumeration
+ /// 登陆设备方式枚举
+ ///
+ public enum EM_LOGIN_SPAC_CAP_TYPE
+ {
+ ///
+ /// TCP login, default
+ /// TCP登陆, 默认方式
+ ///
+ TCP = 0,
+
+ ///
+ /// No criteria login
+ /// 无条件登陆
+ ///
+ ANY = 1,
+
+ ///
+ /// auto sign up login
+ /// 主动注册的登入
+ ///
+ SERVER_CONN = 2,
+
+ ///
+ /// multicast login, default
+ /// 组播登陆
+ ///
+ MULTICAST = 3,
+
+ ///
+ /// UDP method login
+ /// UDP方式下的登入
+ ///
+ UDP = 4,
+
+ ///
+ /// only main connection login
+ /// 只建主连接下的登入
+ ///
+ MAIN_CONN_ONLY = 6,
+
+ ///
+ /// SSL encryption login
+ /// SSL加密方式登陆
+ ///
+ SSL = 7,
+
+ ///
+ /// login IVS box remote device
+ /// 登录智能盒远程设备
+ ///
+ INTELLIGENT_BOX = 9,
+
+ ///
+ /// login device do not config
+ /// 登录设备后不做取配置操作
+ ///
+ NO_CONFIG = 10,
+
+ ///
+ /// USB key device login
+ /// 用U盾设备的登入
+ ///
+ U_LOGIN = 11,
+
+ ///
+ /// LDAP login
+ /// LDAP方式登录
+ ///
+ LDAP = 12,
+
+ ///
+ /// AD login
+ /// AD(ActiveDirectory)登录方式
+ ///
+ AD = 13,
+
+ ///
+ /// Radius login
+ /// Radius 登录方式
+ ///
+ RADIUS = 14,
+
+ ///
+ /// Socks5 login
+ /// Socks5登陆方式
+ ///
+ SOCKET_5 = 15,
+
+ ///
+ /// cloud login
+ /// 云登陆方式
+ ///
+ CLOUD = 16,
+
+ ///
+ /// dual authentication loin
+ /// 二次鉴权登陆方式
+ ///
+ AUTH_TWICE = 17,
+
+ ///
+ /// TS stream client login
+ /// TS码流客户端登陆方式
+ ///
+ TS = 18,
+
+ ///
+ /// web private login
+ /// 为P2P登陆方式
+ ///
+ P2P = 19,
+
+ ///
+ /// mobile client login
+ /// 手机客户端登陆
+ ///
+ MOBILE = 20,
+
+ ///
+ /// invalid login
+ /// 无效的登陆方式
+ ///
+ INVALID = 21,
+ }
+
+ ///
+ /// device type enumeration
+ /// 设备类型枚举
+ ///
+ public enum EM_NET_DEVICE_TYPE
+ {
+ ///
+ /// Unknow
+ // 未知
+ ///
+ NET_PRODUCT_NONE = 0,
+
+ ///
+ /// Non real-time MACE
+ /// 非实时MACE
+ ///
+ NET_DVR_NONREALTIME_MACE,
+
+ ///
+ /// Non real-time
+ /// 非实时
+ ///
+ NET_DVR_NONREALTIME,
+
+ ///
+ /// Network video server
+ /// 网络视频服务器
+ ///
+ NET_NVS_MPEG1,
+
+ ///
+ /// MPEG1 2-ch DVR
+ /// MPEG1二路录像机
+ ///
+ NET_DVR_MPEG1_2,
+
+ ///
+ /// MPEG1 8-ch DVR
+ /// MPEG1八路录像机
+ ///
+ NET_DVR_MPEG1_8,
+
+ ///
+ /// MPEG4 8-ch DVR
+ /// MPEG4八路录像机
+ ///
+ NET_DVR_MPEG4_8,
+
+ ///
+ /// MPEG4 16-ch DVR
+ /// MPEG4 十六路录像机
+ ///
+ NET_DVR_MPEG4_16,
+
+ ///
+ /// LB series DVR
+ /// LB系列录像机
+ ///
+ NET_DVR_MPEG4_SX2,
+
+ ///
+ /// GB series DVR
+ /// GB系列录像机
+ ///
+ NET_DVR_MEPG4_ST2,
+
+ ///
+ /// HB series DVR
+ /// HB系列录像机
+ ///
+ NET_DVR_MEPG4_SH2,
+
+ ///
+ /// GBE series DVR
+ /// GBE系列录像机
+ ///
+ NET_DVR_MPEG4_GBE,
+
+ ///
+ /// II network video server
+ /// II代网络视频服务器
+ ///
+ NET_DVR_MPEG4_NVSII,
+
+ ///
+ /// New standard configuration protocol
+ /// 新标准配置协议
+ ///
+ NET_DVR_STD_NEW,
+
+ ///
+ /// DDNS server
+ /// DDNS服务器
+ ///
+ NET_DVR_DDNS,
+
+ ///
+ /// ATM series
+ /// ATM机
+ ///
+ NET_DVR_ATM,
+
+ ///
+ /// 2nd non real-time NB series DVR
+ /// 二代非实时NB系列机器
+ ///
+ NET_NB_SERIAL,
+
+ ///
+ /// LN series
+ /// LN系列产品
+ ///
+ NET_LN_SERIAL,
+
+ ///
+ /// BAV series
+ /// BAV系列产品
+ ///
+ NET_BAV_SERIAL,
+
+ ///
+ /// SDIP series
+ /// SDIP系列产品
+ ///
+ NET_SDIP_SERIAL,
+
+ ///
+ /// IPC series
+ /// IPC系列产品
+ ///
+ NET_IPC_SERIAL,
+
+ ///
+ /// NVS B series
+ /// NVS B系列
+ ///
+ NET_NVS_B,
+
+ ///
+ /// NVS H series
+ /// NVS H系列
+ ///
+ NET_NVS_C,
+
+ ///
+ /// NVS S series
+ /// NVS S系列
+ ///
+ NET_NVS_S,
+
+ ///
+ /// NVS E series
+ /// NVS E系列
+ ///
+ NET_NVS_E,
+
+ ///
+ /// Search device type from QueryDevState. it is in string format
+ /// 从QueryDevState中查询设备类型,以字符串格式
+ ///
+ NET_DVR_NEW_PROTOCOL,
+
+ ///
+ /// NVD
+ /// 解码器
+ ///
+ NET_NVD_SERIAL,
+
+ ///
+ /// N5
+ /// N5
+ ///
+ NET_DVR_N5,
+
+ ///
+ /// HDVR
+ /// 混合DVR
+ ///
+ NET_DVR_MIX_DVR,
+
+ ///
+ /// SVR series
+ /// SVR系列
+ ///
+ NET_SVR_SERIAL,
+
+ ///
+ /// SVR-BS
+ /// SVR-BS
+ ///
+ NET_SVR_BS,
+
+ ///
+ /// NVR series
+ /// NVR系列
+ ///
+ NET_NVR_SERIAL,
+
+ ///
+ /// N51
+ /// N51
+ ///
+ NET_DVR_N51,
+
+ ///
+ /// ITSE Intelligent Analysis Box
+ /// ITSE 智能分析盒
+ ///
+ NET_ITSE_SERIAL,
+
+ ///
+ /// Intelligent traffic camera equipment
+ /// 智能交通像机设备
+ ///
+ NET_ITC_SERIAL,
+
+ ///
+ /// radar speedometer HWS
+ /// 雷达测速仪HWS
+ ///
+ NET_HWS_SERIAL,
+
+ ///
+ /// portable video record
+ /// 便携式音视频录像机
+ ///
+ NET_PVR_SERIAL,
+
+ ///
+ /// IVS(intelligent video server series)
+ /// IVS(智能视频服务器系列)
+ ///
+ NET_IVS_SERIAL,
+
+ ///
+ /// universal intelligent detect video server series
+ /// 通用智能视频侦测服务器
+ ///
+ NET_IVS_B,
+
+ ///
+ /// face recognisation server
+ /// 人脸识别服务器
+ ///
+ NET_IVS_F,
+
+ ///
+ /// video quality diagnosis server
+ /// 视频质量诊断服务器
+ ///
+ NET_IVS_V,
+
+ ///
+ /// matrix
+ /// 矩阵
+ ///
+ NET_MATRIX_SERIAL,
+
+ ///
+ /// N52
+ /// N52
+ ///
+ NET_DVR_N52,
+
+ ///
+ /// N56
+ /// N56
+ ///
+ NET_DVR_N56,
+
+ ///
+ /// ESS
+ /// ESS
+ ///
+ NET_ESS_SERIAL,
+
+ ///
+ /// 人数统计服务器
+ ///
+ NET_IVS_PC,
+
+ ///
+ /// pc-nvr
+ /// pc-nvr
+ ///
+ NET_PC_NVR,
+
+ ///
+ /// screen controller
+ /// 大屏控制器
+ ///
+ NET_DSCON,
+
+ ///
+ /// network video storage server
+ /// 网络视频存储服务器
+ ///
+ NET_EVS,
+
+ ///
+ /// an embedded intelligent video analysis system
+ /// 嵌入式智能分析视频系统
+ ///
+ NET_EIVS,
+
+ ///
+ /// DVR-N6
+ /// DVR-N6
+ ///
+ NET_DVR_N6,
+
+ ///
+ /// K-Lite Codec Pack
+ /// 万能解码器
+ ///
+ NET_UDS,
+
+ ///
+ /// Bank alarm host
+ /// 银行报警主机
+ ///
+ NET_AF6016,
+
+ ///
+ /// Video network alarm host
+ /// 视频网络报警主机
+ ///
+ NET_AS5008,
+
+ ///
+ /// Network alarm host
+ /// 网络报警主机
+ ///
+ NET_AH2008,
+
+ ///
+ /// Alarm host series
+ /// 报警主机系列
+ ///
+ NET_A_SERIAL,
+
+ ///
+ /// Access control series of products
+ /// 门禁系列产品
+ ///
+ NET_BSC_SERIAL,
+
+ ///
+ /// NVS series product
+ /// NVS系列产品
+ ///
+ NET_NVS_SERIAL,
+
+ ///
+ /// VTO series product
+ /// VTO系列产品
+ ///
+ NET_VTO_SERIAL,
+
+ ///
+ /// VTNC series product
+ /// VTNC系列产品
+ ///
+ NET_VTNC_SERIAL,
+
+ ///
+ /// TPC series product, it is the thermal device
+ /// TPC系列产品, 即热成像设备
+ ///
+ NET_TPC_SERIAL,
+
+ ///
+ /// ASM series product
+ /// 无线中继设备
+ ///
+ NET_ASM_SERIAL,
+
+ ///
+ /// VTS series product
+ /// 管理机
+ ///
+ NET_VTS_SERIAL,
+
+ ///
+ /// Alarm host-ARC2016C
+ /// 报警主机ARC2016C
+ ///
+ NET_ARC2016C,
+
+ ///
+ /// ASA Attendance machine
+ /// 考勤机
+ ///
+ NET_ASA,
+
+ ///
+ /// Industry terminal walkie-talkie
+ /// 行业对讲终端
+ ///
+ NET_VTT_SERIAL,
+
+ ///
+ /// Alarm column
+ /// 报警柱
+ ///
+ NET_VTA_SERIAL,
+
+ ///
+ /// SIP Server
+ /// SIP服务器
+ ///
+ NET_VTNS_SERIAL,
+
+ ///
+ /// Indoor unit
+ /// 室内机
+ ///
+ NET_VTH_SERIAL,
+ }
+
+ ///
+ /// 查询设备信息参数
+ ///
+ public enum EM_DEVICE_STATE
+ {
+ ///
+ /// Query device online state(return a DWORD value, 1-online, 0-offline)
+ /// 查询设备的在线状态(返回一个DWORD, 1表示在线, 0表示断线)
+ ///
+ ONLINE = 0x0035,
+
+ ///
+ /// Query ptz state(struct DH_PTZ_LOCATION_INFO)
+ /// 查询云台状态信息(对应结构体 DH_PTZ_LOCATION_INFO)
+ ///
+ PTZ_LOCATION = 0x0036,
+ }
+
+ ///
+ /// 预置点状态枚举
+ ///
+ public enum EM_DH_PTZ_PRESET_STATUS
+ {
+ UNKNOWN, // 未知
+ REACH, // 预置点到达
+ UNREACH, // 预置点未到达
+ }
+
+ #endregion SDK Enum
+
+ #region SDK Struct
+
+ ///
+ /// CLIENT_LoginWithHighLevelSecurity 输入参数
+ ///
+ public struct NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY
+ {
+ public uint dwSize;// 结构体大小
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
+ public string szIP; // IP
+
+ public int nPort; // 端口
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
+ public string szUserName; // 用户名
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
+ public string szPassword; // 密码
+
+ public EM_LOGIN_SPAC_CAP_TYPE emSpecCap; // 登录模式
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public byte[] byReserved; // 字节对齐
+
+ public IntPtr pCapParam; // 见 CLIENT_LoginEx 接口 pCapParam 与 nSpecCap 关系
+ }
+
+ ///
+ /// device information structure
+ /// 设备信息结构体
+ ///
+ public struct NET_DEVICEINFO_Ex
+ {
+ ///
+ /// serial number
+ /// 序列号
+ ///
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 48)]
+ public string sSerialNumber;
+
+ ///
+ /// count of alarm input
+ /// 报警输入个数
+ ///
+ public int nAlarmInPortNum;
+
+ ///
+ /// count of alarm output
+ /// 报警输出个数
+ ///
+ public int nAlarmOutPortNum;
+
+ ///
+ /// number of disk
+ /// 硬盘个数
+ ///
+ public int nDiskNum;
+
+ ///
+ /// device type, refer to EM_NET_DEVICE_TYPE
+ /// 设备类型,见枚举NET_DEVICE_TYPE
+ ///
+ public EM_NET_DEVICE_TYPE nDVRType;
+
+ ///
+ /// number of channel
+ /// 通道个数
+ ///
+ public int nChanNum;
+
+ ///
+ /// Online Timeout, Not Limited Access to 0, not 0 Minutes Limit Said
+ /// 在线超时时间,为0表示不限制登陆,非0表示限制的分钟数
+ ///
+ public byte byLimitLoginTime;
+
+ ///
+ /// When login failed due to password error, notice user by this parameter.This parameter is invalid when remaining login times is zero
+ /// 当登陆失败原因为密码错误时,通过此参数通知用户,剩余登陆次数,为0时表示此参数无效
+ ///
+ public byte byLeftLogTimes;
+
+ ///
+ /// keep bytes for aligned
+ /// 保留字节,字节对齐
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ public byte[] bReserved;
+
+ ///
+ /// when log in failed,the left time for users to unlock (seconds), -1 indicate the device haven't set the parameter
+ /// 当登陆失败,用户解锁剩余时间(秒数), -1表示设备未设置该参数
+ ///
+ public int nLockLeftTime;
+
+ ///
+ /// reserved
+ /// 保留字节
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
+ public byte[] Reserved;
+ }
+
+ ///
+ /// CLIENT_LoginWithHighLevelSecurity 输出参数
+ ///
+ public struct NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY
+ {
+ public uint dwSize;// 结构体大小
+ public NET_DEVICEINFO_Ex stuDeviceInfo; // 设备信息
+ public int nError; // 错误码,见 CLIENT_Login 接口错误码
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)]
+ public byte[] byReserved; // 保留字节
+ }
+
+ ///
+ /// 云台定位中非归一化坐标和变倍
+ ///
+ public struct NET_PTZSPACE_UNNORMALIZED
+ {
+ public int nPosX; // x坐标
+ public int nPosY; // y坐标
+ public int nZoom; // 放大倍率
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 52)]
+ public byte[] byReserved; // 预留字节
+ }
+
+ ///
+ /// 云台定位信息
+ ///
+ //云台定位信息
+ public struct DH_PTZ_LOCATION_INFO
+ {
+ public int nChannelID; // 通道号
+ public int nPTZPan; // 云台水平运动位置,有效范围:[0,3600]
+ public int nPTZTilt; // 云台垂直运动位置,有效范围:[-1800,1800]
+ public int nPTZZoom; // 云台光圈变动位置,有效范围:[0,128]
+ public byte bState; // 云台运动状态, 0-未知 1-运动 2-空闲
+ public byte bAction; // 云台动作,255-未知,0-预置点,1-线扫,2-巡航,3-巡迹,4-水平旋转,5-普通移动,6-巡迹录制,7-全景云台扫描,8-热度图
+
+ // 9-精确定位,10-设备校正,11-智能配置,12-云台重启
+ public byte bFocusState; // 云台聚焦状态, 0-未知, 1-运动状态, 2-空闲
+
+ public byte bEffectiveInTimeSection; // 在时间段内预置点状态是否有效
+
+ //如果当前上报的预置点是时间段内的预置点,则为1,其他情况为0
+ public int nPtzActionID; // 巡航ID号
+
+ public uint dwPresetID; // 云台所在预置点编号
+ public float fFocusPosition; // 聚焦位置
+ public byte bZoomState; // 云台ZOOM状态,0-未知,1-ZOOM,2-空闲
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public byte[] bReserved; // 对齐
+
+ public uint dwSequence; // 包序号,用于校验是否丢包
+ public uint dwUTC; // 对应的UTC(1970-1-1 00:00:00)秒数。
+ public EM_DH_PTZ_PRESET_STATUS emPresetStatus; // 预置点位置
+
+ ///
+ /// 保留字段
+ ///
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 248)]
+ public int[] reserved;
+ };
+
+ #endregion SDK Struct
+
+ #region Common Method
+
+ ///
+ /// network disconnection callback function original shape
+ /// 断线回调函数
+ ///
+ /// user LoginID:Login's returns value 登陆ID
+ /// device IP 设备IP
+ /// device prot 设备端口
+ /// user data from Init function 用户数据
+ public delegate void fDisConnectCallBack(IntPtr lLoginID, IntPtr pchDVRIP, int nDVRPort, IntPtr dwUser);
+
+ ///
+ /// network re-connection callback function original shape
+ /// 重连回调函数
+ ///
+ /// user LoginID:Login's returns value 登陆ID
+ /// device IP,string type 设备IP
+ /// device prot 设备端口
+ /// user data from SetAutoReconnect function 用户数据
+ public delegate void fHaveReConnectCallBack(IntPtr lLoginID, IntPtr pchDVRIP, int nDVRPort, IntPtr dwUser);
+
+ [DllImport(LibDhNetSDK)]
+ public static extern bool CLIENT_InitEx(fDisConnectCallBack? cbDisConnect, IntPtr dwUser, IntPtr lpInitParam);
+
+ [DllImport(LibDhNetSDK)]
+ public static extern void CLIENT_Cleanup();
+
+ [DllImport(LibDhNetSDK)]
+ public static extern int CLIENT_GetLastError();
+
+ [DllImport(LibDhNetSDK)]
+ public static extern IntPtr CLIENT_LoginWithHighLevelSecurity(ref NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam, ref NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam);
+
+ [DllImport(LibDhNetSDK)]
+ public static extern bool CLIENT_Logout(IntPtr lLoginID);
+
+ [DllImport(LibDhNetSDK)]
+ public static extern void CLIENT_SetAutoReconnect(fHaveReConnectCallBack cbAutoConnect, IntPtr dwUser);
+
+ [DllImport(LibDhNetSDK)]
+ public static extern bool CLIENT_QueryDevState(IntPtr lLoginID, int nType, IntPtr pBuf, int nBufLen, ref int pRetLen, int waittime);
+
+ #endregion Common Method
+}
\ No newline at end of file
diff --git a/EC.Helper/CameraSDK/DaHua/DaHuaSDK.cs b/EC.Helper/CameraSDK/DaHua/DaHuaSDK.cs
new file mode 100644
index 0000000..478746e
--- /dev/null
+++ b/EC.Helper/CameraSDK/DaHua/DaHuaSDK.cs
@@ -0,0 +1,111 @@
+using System.Runtime.InteropServices;
+
+namespace EC.Helper.CameraSDK;
+
+public class DaHuaSDK : ICameraSDK
+{
+ #region Attr
+
+ private IntPtr LoginId { get; set; } = IntPtr.Zero;
+
+ #endregion Attr
+
+ public DaHuaSDK(CameraInfo cameraInfo) : base(cameraInfo)
+ {
+ }
+
+ #region Base Method
+
+ public override bool Init()
+ {
+ bool ret = ConnectSuccess();
+ if (ret) return true;
+
+ DaHuaOriSDK.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stuInParam = new();
+ stuInParam.dwSize = (uint)Marshal.SizeOf(stuInParam);
+ stuInParam.szIP = CameraInfo.Ip;
+ stuInParam.nPort = CameraInfo.Port;
+ stuInParam.szUserName = CameraInfo.UserName;
+ stuInParam.szPassword = CameraInfo.Password;
+ stuInParam.emSpecCap = DaHuaOriSDK.EM_LOGIN_SPAC_CAP_TYPE.TCP;
+ stuInParam.pCapParam = IntPtr.Zero;
+ DaHuaOriSDK.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stuOutParam = new();
+ stuOutParam.dwSize = (uint)Marshal.SizeOf(stuOutParam);
+ LoginId = DaHuaOriSDK.CLIENT_LoginWithHighLevelSecurity(ref stuInParam, ref stuOutParam);
+ ret = ConnectSuccess();
+ if (ret) DaHuaOriSDK.CLIENT_SetAutoReconnect(delegate (IntPtr lLoginID, IntPtr pchDVRIP, int nDVRPort, IntPtr dwUser)
+ {
+ LoginId = lLoginID;
+ }, IntPtr.Zero);
+
+ return ret;
+ }
+
+ public override bool Destory()
+ {
+ bool ret = ConnectSuccess();
+ if (!ret) return true;
+
+ ret = DaHuaOriSDK.CLIENT_Logout(LoginId);
+ if (ret) LoginId = IntPtr.Zero;
+
+ return ret;
+ }
+
+ public override bool ConnectSuccess()
+ {
+ return LoginId != IntPtr.Zero;
+ }
+
+ public override void BuildException()
+ {
+ uint errCode = (uint)DaHuaOriSDK.CLIENT_GetLastError();
+ if (errCode == 0) return;
+ errCode -= 0x80000000;
+ throw CameraException.New(CameraType.DaHua, (int)errCode);
+ }
+
+ #endregion Base Method
+
+ #region Main Method
+
+ private static class GPIParams
+ {
+ public static int Size { get; private set; }
+ public static Type Type { get; private set; }
+
+ static GPIParams()
+ {
+ DaHuaOriSDK.DH_PTZ_LOCATION_INFO info = new();
+ Size = Marshal.SizeOf(info);
+ Type = info.GetType();
+ }
+ }
+
+ public override PtzInfo GetPtzInfo()
+ {
+ bool ret = ConnectSuccess();
+ if (!ret) return PtzInfo.Default;
+
+ DaHuaOriSDK.DH_PTZ_LOCATION_INFO entity = new();
+ int nBufLen = GPIParams.Size;
+ int pRetLen = 0;
+ IntPtr ptrBuf = Marshal.AllocHGlobal(GPIParams.Size);
+ Marshal.StructureToPtr(entity, ptrBuf, true);
+ try
+ {
+ ret = DaHuaOriSDK.CLIENT_QueryDevState(LoginId, (int)DaHuaOriSDK.EM_DEVICE_STATE.PTZ_LOCATION, ptrBuf, nBufLen, ref pRetLen, 3000);
+ if (!ret) { BuildException(); return PtzInfo.Default; }
+ object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type);
+ if (objBuf == null) return PtzInfo.Default;
+ entity = (DaHuaOriSDK.DH_PTZ_LOCATION_INFO)objBuf;
+ return PtzInfo.New(entity.nPTZPan, entity.nPTZTilt, entity.nPTZZoom);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(ptrBuf);
+ }
+ }
+
+ #endregion Main Method
+}
\ No newline at end of file
diff --git a/EC.Helper/CameraSDK/HiK/HiKOriSDK.cs b/EC.Helper/CameraSDK/HiK/HiKOriSDK.cs
new file mode 100644
index 0000000..8d3a435
--- /dev/null
+++ b/EC.Helper/CameraSDK/HiK/HiKOriSDK.cs
@@ -0,0 +1,226 @@
+//#define Linux32
+//#define Linux64
+//#define Win32
+//#define Win64
+
+using System.Runtime.InteropServices;
+
+namespace EC.Helper.CameraSDK;
+
+public static class HiKOriSDK
+{
+ #region Lib Attr
+
+#if (Linux32)
+ public const string LibHcNetSDK = @"./libs/hik/linux32/libhcnetsdk.so";
+#elif (Linux64)
+ public const string LibHcNetSDK = @"./libs/hik/linux64/libhcnetsdk.so";
+#elif (Win32)
+ public const string LibHcNetSDK = @"./libs/hik/win32/HCNetSDK.dll";
+#elif (Win64)
+ public const string LibHcNetSDK = @"./libs/hik/win64/HCNetSDK.dll";
+#endif
+
+ #endregion Lib Attr
+
+ static HiKOriSDK()
+ {
+ GlobalInit();
+ }
+
+ #region Global
+
+ public static bool InitSuccess { get; private set; }
+
+ public static bool GlobalInit()
+ {
+ if (InitSuccess) return true;
+ bool ret = NET_DVR_Init();
+ InitSuccess = ret;
+ if (!ret) throw new Exception("HiKOriSDK global init failure.");
+ return ret;
+ }
+
+ public static bool GlobalDestory()
+ {
+ if (!InitSuccess) return true;
+ bool ret = NET_DVR_Cleanup();
+ if (ret) InitSuccess = false;
+ return ret;
+ }
+
+ #endregion Global
+
+ #region SDK Const
+
+ public const int SERIALNO_LEN = 48; //序列号长度
+
+ #region 用于 NET_DVR_SetDVRConfig 和 NET_DVR_GetDVRConfig
+
+ public const int NET_DVR_SET_PTZPOS = 292; //云台设置PTZ位置
+ public const int NET_DVR_GET_PTZPOS = 293; //云台获取PTZ位置
+ public const int NET_DVR_GET_PTZSCOPE = 294; //云台获取PTZ范围
+
+ #endregion 用于 NET_DVR_SetDVRConfig 和 NET_DVR_GetDVRConfig
+
+ #endregion SDK Const
+
+ #region SDK Struct
+
+ //NET_DVR_Login()参数结构
+ [StructLayoutAttribute(LayoutKind.Sequential)]
+ public struct NET_DVR_DEVICEINFO
+ {
+ [MarshalAsAttribute(
+ UnmanagedType.ByValArray,
+ SizeConst = SERIALNO_LEN,
+ ArraySubType = UnmanagedType.I1
+ )]
+ public byte[] sSerialNumber; //序列号
+
+ public byte byAlarmInPortNum; //DVR报警输入个数
+ public byte byAlarmOutPortNum; //DVR报警输出个数
+ public byte byDiskNum; //DVR硬盘个数
+ public byte byDVRType; //DVR类型, 1:DVR 2:ATM DVR 3:DVS ......
+ public byte byChanNum; //DVR 通道个数
+ public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1
+ }
+
+ //NET_DVR_Login_V30()参数结构
+ [StructLayoutAttribute(LayoutKind.Sequential)]
+ public struct NET_DVR_DEVICEINFO_V30
+ {
+ [MarshalAsAttribute(
+ UnmanagedType.ByValArray,
+ SizeConst = SERIALNO_LEN,
+ ArraySubType = UnmanagedType.I1
+ )]
+ public byte[] sSerialNumber; //序列号
+
+ public byte byAlarmInPortNum; //报警输入个数
+ public byte byAlarmOutPortNum; //报警输出个数
+ public byte byDiskNum; //硬盘个数
+ public byte byDVRType; //设备类型, 1:DVR 2:ATM DVR 3:DVS ......
+ public byte byChanNum; //模拟通道个数
+ public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1
+ public byte byAudioChanNum; //语音通道数
+ public byte byIPChanNum; //最大数字通道个数,低位
+ public byte byZeroChanNum; //零通道编码个数 //2010-01-16
+ public byte byMainProto; //主码流传输协议类型 0-private, 1-rtsp,2-同时支持private和rtsp
+ public byte bySubProto; //子码流传输协议类型0-private, 1-rtsp,2-同时支持private和rtsp
+ public byte bySupport; //能力,位与结果为0表示不支持,1表示支持,
+
+ //bySupport & 0x1, 表示是否支持智能搜索
+ //bySupport & 0x2, 表示是否支持备份
+ //bySupport & 0x4, 表示是否支持压缩参数能力获取
+ //bySupport & 0x8, 表示是否支持多网卡
+ //bySupport & 0x10, 表示支持远程SADP
+ //bySupport & 0x20, 表示支持Raid卡功能
+ //bySupport & 0x40, 表示支持IPSAN 目录查找
+ //bySupport & 0x80, 表示支持rtp over rtsp
+ public byte bySupport1; // 能力集扩充,位与结果为0表示不支持,1表示支持
+
+ //bySupport1 & 0x1, 表示是否支持snmp v30
+ //bySupport1 & 0x2, 支持区分回放和下载
+ //bySupport1 & 0x4, 是否支持布防优先级
+ //bySupport1 & 0x8, 智能设备是否支持布防时间段扩展
+ //bySupport1 & 0x10, 表示是否支持多磁盘数(超过33个)
+ //bySupport1 & 0x20, 表示是否支持rtsp over http
+ //bySupport1 & 0x80, 表示是否支持车牌新报警信息2012-9-28, 且还表示是否支持NET_DVR_IPPARACFG_V40结构体
+ public byte bySupport2; /*能力,位与结果为0表示不支持,非0表示支持
+
+ bySupport2 & 0x1, 表示解码器是否支持通过URL取流解码
+ bySupport2 & 0x2, 表示支持FTPV40
+ bySupport2 & 0x4, 表示支持ANR
+ bySupport2 & 0x8, 表示支持CCD的通道参数配置
+ bySupport2 & 0x10, 表示支持布防报警回传信息(仅支持抓拍机报警 新老报警结构)
+ bySupport2 & 0x20, 表示是否支持单独获取设备状态子项
+ bySupport2 & 0x40, 表示是否是码流加密设备*/
+ public ushort wDevType; //设备型号
+ public byte bySupport3; //能力集扩展,位与结果为0表示不支持,1表示支持
+
+ //bySupport3 & 0x1, 表示是否多码流
+ // bySupport3 & 0x4 表示支持按组配置, 具体包含 通道图像参数、报警输入参数、IP报警输入、输出接入参数、
+ // 用户参数、设备工作状态、JPEG抓图、定时和时间抓图、硬盘盘组管理
+ //bySupport3 & 0x8为1 表示支持使用TCP预览、UDP预览、多播预览中的"延时预览"字段来请求延时预览(后续都将使用这种方式请求延时预览)。而当bySupport3 & 0x8为0时,将使用 "私有延时预览"协议。
+ //bySupport3 & 0x10 表示支持"获取报警主机主要状态(V40)"。
+ //bySupport3 & 0x20 表示是否支持通过DDNS域名解析取流
+
+ public byte byMultiStreamProto; //是否支持多码流,按位表示,0-不支持,1-支持,bit1-码流3,bit2-码流4,bit7-主码流,bit-8子码流
+ public byte byStartDChan; //起始数字通道号,0表示无效
+ public byte byStartDTalkChan; //起始数字对讲通道号,区别于模拟对讲通道号,0表示无效
+ public byte byHighDChanNum; //数字通道个数,高位
+ public byte bySupport4;
+ public byte byLanguageType; // 支持语种能力,按位表示,每一位0-不支持,1-支持
+
+ // byLanguageType 等于0 表示 老设备
+ // byLanguageType & 0x1表示支持中文
+ // byLanguageType & 0x2表示支持英文
+ [MarshalAsAttribute(
+ UnmanagedType.ByValArray,
+ SizeConst = 9,
+ ArraySubType = UnmanagedType.I1
+ )]
+ public byte[] byRes2; //保留
+ }
+
+ //球机位置信息
+ [StructLayoutAttribute(LayoutKind.Sequential)]
+ public struct NET_DVR_PTZPOS
+ {
+ public ushort wAction; //获取时该字段无效
+ public ushort wPanPos; //水平参数
+ public ushort wTiltPos; //垂直参数
+ public ushort wZoomPos; //变倍参数
+ }
+
+ //球机范围信息
+ [StructLayoutAttribute(LayoutKind.Sequential)]
+ public struct NET_DVR_PTZSCOPE
+ {
+ public ushort wPanPosMin; //水平参数min
+ public ushort wPanPosMax; //水平参数max
+ public ushort wTiltPosMin; //垂直参数min
+ public ushort wTiltPosMax; //垂直参数max
+ public ushort wZoomPosMin; //变倍参数min
+ public ushort wZoomPosMax; //变倍参数max
+ }
+
+ #endregion SDK Struct
+
+ #region Common Method
+
+ [DllImport(LibHcNetSDK)]
+ public static extern bool NET_DVR_Init();
+
+ [DllImport(LibHcNetSDK)]
+ public static extern bool NET_DVR_Cleanup();
+
+ [DllImport(LibHcNetSDK)]
+ public static extern uint NET_DVR_GetLastError();
+
+ [DllImport(LibHcNetSDK)]
+ public static extern int NET_DVR_Login_V30(
+ string sDVRIP,
+ int wDVRPort,
+ string sUserName,
+ string sPassword,
+ ref NET_DVR_DEVICEINFO_V30 lpDeviceInfo
+ );
+
+ [DllImport(LibHcNetSDK)]
+ public static extern bool NET_DVR_Logout(int iUserID);
+
+ //参数配置 begin
+ [DllImport(LibHcNetSDK)]
+ public static extern bool NET_DVR_GetDVRConfig(
+ int lUserID,
+ uint dwCommand,
+ int lChannel,
+ IntPtr lpOutBuffer,
+ uint dwOutBufferSize,
+ ref uint lpBytesReturned
+ );
+
+ #endregion Common Method
+}
\ No newline at end of file
diff --git a/EC.Helper/CameraSDK/HiK/HiKSDK.cs b/EC.Helper/CameraSDK/HiK/HiKSDK.cs
new file mode 100644
index 0000000..1185f37
--- /dev/null
+++ b/EC.Helper/CameraSDK/HiK/HiKSDK.cs
@@ -0,0 +1,97 @@
+using System.Runtime.InteropServices;
+
+namespace EC.Helper.CameraSDK;
+
+public class HiKSDK : ICameraSDK
+{
+ #region Attr
+
+ private int LoginId { get; set; } = -1;
+
+ #endregion Attr
+
+ public HiKSDK(CameraInfo cameraInfo) : base(cameraInfo)
+ {
+ }
+
+ #region Base Method
+
+ public override bool Init()
+ {
+ bool ret = ConnectSuccess();
+ if (ret) return true;
+
+ HiKOriSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new();
+ LoginId = HiKOriSDK.NET_DVR_Login_V30(CameraInfo.Ip, CameraInfo.Port, CameraInfo.UserName, CameraInfo.Password, ref deviceInfo);
+ ret = ConnectSuccess();
+
+ return ret;
+ }
+
+ public override bool Destory()
+ {
+ bool ret = ConnectSuccess();
+ if (!ret) return true;
+
+ ret = HiKOriSDK.NET_DVR_Logout(LoginId);
+ if (ret) LoginId = -1;
+
+ return ret;
+ }
+
+ public override bool ConnectSuccess()
+ {
+ return LoginId >= 0;
+ }
+
+ public override void BuildException()
+ {
+ uint errCode = HiKOriSDK.NET_DVR_GetLastError();
+ if (errCode == 0) return;
+ throw CameraException.New(CameraType.HiK, (int)errCode);
+ }
+
+ #endregion Base Method
+
+ #region Main Method
+
+ private static class GPIParams
+ {
+ public static int Size { get; private set; }
+ public static Type Type { get; private set; }
+
+ static GPIParams()
+ {
+ HiKOriSDK.NET_DVR_PTZPOS ptzPos = new();
+ Size = Marshal.SizeOf(ptzPos);
+ Type = ptzPos.GetType();
+ }
+ }
+
+ public override PtzInfo GetPtzInfo()
+ {
+ bool ret = ConnectSuccess();
+ if (!ret) return PtzInfo.Default;
+
+ HiKOriSDK.NET_DVR_PTZPOS entity = new();
+ int dwSize = GPIParams.Size;
+ uint dwReturned = 0;
+ IntPtr ptrBuf = Marshal.AllocHGlobal(dwSize);
+ Marshal.StructureToPtr(entity, ptrBuf, true);
+ try
+ {
+ ret = HiKOriSDK.NET_DVR_GetDVRConfig(LoginId, HiKOriSDK.NET_DVR_GET_PTZPOS, 0, ptrBuf, (uint)dwSize, ref dwReturned);
+ if (!ret) { BuildException(); return PtzInfo.Default; }
+ object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type);
+ if (objBuf == null) return PtzInfo.Default;
+ entity = (HiKOriSDK.NET_DVR_PTZPOS)objBuf;
+ return PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos);
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(ptrBuf);
+ }
+ }
+
+ #endregion Main Method
+}
\ No newline at end of file
diff --git a/EC.Helper/CameraSDK/YuShi/YuShiOriSDK.cs b/EC.Helper/CameraSDK/YuShi/YuShiOriSDK.cs
new file mode 100644
index 0000000..140c86b
--- /dev/null
+++ b/EC.Helper/CameraSDK/YuShi/YuShiOriSDK.cs
@@ -0,0 +1,150 @@
+//#define Linux32
+//#define Linux64
+//#define Win32
+//#define Win64
+
+using System.Runtime.InteropServices;
+
+namespace EC.Helper.CameraSDK;
+
+public static class YuShiOriSDK
+{
+ #region Lib Attr
+
+#if (Linux32)
+ public const string LibYsNetSDK = @"./libs/yushi/linux64/libNetDEVSDK.so";
+#elif (Linux64)
+ public const string LibYsNetSDK = @"./libs/yushi/linux64/libNetDEVSDK.so";
+#elif (Win32)
+ public const string LibYsNetSDK = @"./libs/yushi/win32/NetDEVSDK.dll";
+#elif (Win64)
+ public const string LibYsNetSDK = @"./libs/yushi/win64/NetDEVSDK.dll";
+#endif
+
+ #endregion Lib Attr
+
+ static YuShiOriSDK()
+ {
+ GlobalInit();
+ }
+
+ #region Global
+
+ public static bool InitSuccess { get; private set; }
+
+ public static bool GlobalInit()
+ {
+ if (InitSuccess) return true;
+ bool ret = NETDEV_Init();
+ InitSuccess = ret;
+ if (!ret) throw new Exception("YuShiOriSDK global init failure.");
+ return ret;
+ }
+
+ public static bool GlobalDestory()
+ {
+ if (!InitSuccess) return true;
+ bool ret = NETDEV_Cleanup();
+ if (ret) InitSuccess = false;
+ return ret;
+ }
+
+ #endregion Global
+
+ #region SDK Const
+
+ /* Common length */
+ public const int NETDEV_LEN_64 = 64;
+ public const int NETDEV_LEN_128 = 128;
+ public const int NETDEV_LEN_132 = 132;
+ public const int NETDEV_LEN_260 = 260;
+
+ #endregion SDK Const
+
+ #region SDK Struct
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct NETDEV_DEVICE_LOGIN_INFO_S
+ {
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_260)]
+ public string szIPAddr; /* IP地址/域名 */
+
+ public Int32 dwPort; /* 端口号 */
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_132)]
+ public string szUserName; /* 用户名 */
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_128)]
+ public string szPassword; /* 密码 */
+
+ public Int32 dwLoginProto; /* 登录协议, 参见NETDEV_LOGIN_PROTO_E */
+ public Int32 dwDeviceType; /* 设备类型, 参见NETDEV_DEVICE_TYPE_E */
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
+ public byte[] byRes; /* Reserved */
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct NETDEV_SELOG_INFO_S
+ {
+ public Int32 dwSELogCount;
+ public Int32 dwSELogTime;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
+ public byte[] byRes;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct NETDEV_VIDEO_CHL_DETAIL_INFO_S
+ {
+ public Int32 dwChannelID;
+ public Int32 bPtzSupported; /* Whether ptz is supported */
+ public Int32 enStatus; /* Channel status */
+ public Int32 dwStreamNum; /* Number of streams */
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NETDEV_LEN_64)]
+ public string szChnName; /* Device serial number */
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public byte[] szReserve;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct NETDEV_PTZ_STATUS_S
+ {
+ public float fPanTiltX; /* 绝对水平坐标 Absolute horizontal coordinates*/
+ public float fPanTiltY; /* 绝对竖直坐标 Absolute vertical coordinates*/
+ public float fZoomX; /* 绝对聚焦倍数 Absolute multiples*/
+ public Int32 enPanTiltStatus;/* 云台状态 PTZ Status*/
+ public Int32 enZoomStatus; /* 聚焦状态 Focus Status*/
+ };
+
+ #endregion SDK Struct
+
+ #region Common Method
+
+ [DllImport(LibYsNetSDK, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ public static extern bool NETDEV_Init();
+
+ [DllImport(LibYsNetSDK, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ public static extern bool NETDEV_Cleanup();
+
+ [DllImport(LibYsNetSDK, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ public static extern int NETDEV_GetLastError();
+
+ [DllImport(LibYsNetSDK, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ public static extern IntPtr NETDEV_Login_V30(ref NETDEV_DEVICE_LOGIN_INFO_S pstDevLoginInfo, ref NETDEV_SELOG_INFO_S pstSELogInfo);
+
+ [DllImport(LibYsNetSDK, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ public static extern bool NETDEV_Logout(IntPtr lpUserID);
+
+ [DllImport(LibYsNetSDK, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ public static extern Int32 NETDEV_QueryVideoChlDetailList(IntPtr lpUserID, ref int pdwChlCount, IntPtr pstVideoChlList);
+
+ [DllImport(LibYsNetSDK, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ public static extern bool NETDEV_PTZGetStatus(IntPtr lpUserID, int dwChannelID, ref NETDEV_PTZ_STATUS_S pstPTZStaus);
+
+ //public boolean NETDEV_GetDevConfig(Pointer lpUserID, int dwChannelID, int dwCommand, Pointer lpOutBuffer, int dwOutBufferSize, IntByReference pdwBytesReturned);
+
+ #endregion Common Method
+}
\ No newline at end of file
diff --git a/EC.Helper/CameraSDK/YuShi/YuShiSDK.cs b/EC.Helper/CameraSDK/YuShi/YuShiSDK.cs
new file mode 100644
index 0000000..0d810d8
--- /dev/null
+++ b/EC.Helper/CameraSDK/YuShi/YuShiSDK.cs
@@ -0,0 +1,74 @@
+namespace EC.Helper.CameraSDK;
+
+public class YuShiSDK : ICameraSDK
+{
+ #region Attr
+
+ private IntPtr LoginId { get; set; } = IntPtr.Zero;
+
+ #endregion Attr
+
+ public YuShiSDK(CameraInfo cameraInfo) : base(cameraInfo)
+ {
+ }
+
+ #region Base Method
+
+ public override bool Init()
+ {
+ bool ret = ConnectSuccess();
+ if (ret) return true;
+
+ YuShiOriSDK.NETDEV_DEVICE_LOGIN_INFO_S loginInfo = new();
+ loginInfo.szIPAddr = CameraInfo.Ip;
+ loginInfo.dwPort = CameraInfo.Port;
+ loginInfo.szUserName = CameraInfo.UserName;
+ loginInfo.szPassword = CameraInfo.Password;
+ YuShiOriSDK.NETDEV_SELOG_INFO_S logInfo = new();
+ LoginId = YuShiOriSDK.NETDEV_Login_V30(ref loginInfo, ref logInfo);
+ ret = ConnectSuccess();
+
+ return ret;
+ }
+
+ public override bool Destory()
+ {
+ bool ret = ConnectSuccess();
+ if (!ret) return true;
+
+ ret = YuShiOriSDK.NETDEV_Logout(LoginId);
+ if (ret) LoginId = IntPtr.Zero;
+
+ return ret;
+ }
+
+ public override bool ConnectSuccess()
+ {
+ return LoginId != IntPtr.Zero;
+ }
+
+ public override void BuildException()
+ {
+ int errCode = YuShiOriSDK.NETDEV_GetLastError();
+ if (errCode == 0) return;
+ throw CameraException.New(CameraType.YuShi, (int)errCode);
+ }
+
+ #endregion Base Method
+
+ #region Main Method
+
+ public override PtzInfo GetPtzInfo()
+ {
+ bool ret = ConnectSuccess();
+ if (!ret) return PtzInfo.Default;
+
+ YuShiOriSDK.NETDEV_PTZ_STATUS_S entity = new();
+ ret = YuShiOriSDK.NETDEV_PTZGetStatus(LoginId, 1, ref entity);
+ if (!ret) { BuildException(); return PtzInfo.Default; }
+
+ return PtzInfo.New(entity.fPanTiltX, entity.fPanTiltY, entity.fZoomX);
+ }
+
+ #endregion Main Method
+}
\ No newline at end of file
diff --git a/EC.Helper/EC.Helper.csproj b/EC.Helper/EC.Helper.csproj
new file mode 100644
index 0000000..808b2db
--- /dev/null
+++ b/EC.Helper/EC.Helper.csproj
@@ -0,0 +1,151 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+ $(DefineConstants)TRACE;Win64
+
+
+
+ $(DefineConstants)TRACE;Win64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
diff --git a/EC.Helper/Test/CameraSDKTest.cs b/EC.Helper/Test/CameraSDKTest.cs
new file mode 100644
index 0000000..b7d44ac
--- /dev/null
+++ b/EC.Helper/Test/CameraSDKTest.cs
@@ -0,0 +1,124 @@
+using EC.Helper.CameraSDK;
+
+namespace EC.Helper.Test;
+
+public class CameraSDKTest
+{
+ public static void Test()
+ {
+ //HiKTest();
+ //DaHuaTest();
+ //YuShiTest();
+ }
+
+ public static void HiKTest()
+ {
+ Console.WriteLine("====HiK==========================");
+
+ try
+ {
+ string ip = "192.168.1.65";
+ string username = "admin";
+ string password = "hk123456";
+ int type = (int)CameraType.HiK;
+ CameraInfo cameraInfo = CameraInfo.New(type, ip, username, password);
+ ICameraSDK sdk = new HiKSDK(cameraInfo);
+ ICameraSDK sdk2 = new HiKSDK(cameraInfo);
+ sdk.Init();
+ sdk2.Init();
+
+ PtzInfo ptzInfo = sdk.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+
+ sdk.Destory();
+
+ Thread.Sleep(1000);
+
+ ptzInfo = sdk.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+
+ ptzInfo = sdk2.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.ToString());
+ throw;
+ }
+ Console.WriteLine("=================================");
+ }
+
+ public static void DaHuaTest()
+ {
+ Console.WriteLine("====DaHua========================");
+
+ try
+ {
+ string ip = "192.168.1.71";
+ string username = "admin";
+ string password = "hk123456";
+ int type = (int)CameraType.DaHua;
+ CameraInfo cameraInfo = CameraInfo.New(type, ip, username, password);
+ ICameraSDK sdk = new DaHuaSDK(cameraInfo);
+ ICameraSDK sdk2 = new DaHuaSDK(cameraInfo);
+ sdk.Init();
+ sdk2.Init();
+ PtzInfo ptzInfo = sdk.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+
+ sdk.Destory();
+
+ Thread.Sleep(1000);
+
+ ptzInfo = sdk.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+
+ ptzInfo = sdk2.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.ToString());
+ throw;
+ }
+
+ Console.WriteLine("=================================");
+ }
+
+ public static void YuShiTest()
+ {
+ Console.WriteLine("====YuShi========================");
+
+ try
+ {
+ string ip = "192.168.1.109";
+ string username = "admin";
+ string password = "hk123456";
+ int type = (int)CameraType.YuShi;
+ CameraInfo cameraInfo = CameraInfo.New(type, ip, username, password);
+ ICameraSDK sdk = new YuShiSDK(cameraInfo);
+ ICameraSDK sdk2 = new YuShiSDK(cameraInfo);
+ sdk.Init();
+ sdk2.Init();
+ PtzInfo ptzInfo = sdk.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+
+ sdk.Destory();
+
+ Thread.Sleep(1000);
+
+ ptzInfo = sdk.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+
+ ptzInfo = sdk2.GetPtzInfo();
+ Console.WriteLine($"{ptzInfo.Pan}, {ptzInfo.Tilt}, {ptzInfo.Zoom}");
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e.ToString());
+ throw;
+ }
+
+ Console.WriteLine("=================================");
+ }
+}
\ No newline at end of file
diff --git a/EC.Helper/libs/dahua/linux32/libdhnetsdk.so b/EC.Helper/libs/dahua/linux32/libdhnetsdk.so
new file mode 100644
index 0000000..785f8b7
Binary files /dev/null and b/EC.Helper/libs/dahua/linux32/libdhnetsdk.so differ
diff --git a/EC.Helper/libs/dahua/linux64/libdhnetsdk.so b/EC.Helper/libs/dahua/linux64/libdhnetsdk.so
new file mode 100644
index 0000000..2bae458
Binary files /dev/null and b/EC.Helper/libs/dahua/linux64/libdhnetsdk.so differ
diff --git a/EC.Helper/libs/dahua/win32/dhnetsdk.dll b/EC.Helper/libs/dahua/win32/dhnetsdk.dll
new file mode 100644
index 0000000..f6464d6
Binary files /dev/null and b/EC.Helper/libs/dahua/win32/dhnetsdk.dll differ
diff --git a/EC.Helper/libs/dahua/win64/dhnetsdk.dll b/EC.Helper/libs/dahua/win64/dhnetsdk.dll
new file mode 100644
index 0000000..aa3a5e4
Binary files /dev/null and b/EC.Helper/libs/dahua/win64/dhnetsdk.dll differ
diff --git a/EC.Helper/libs/hik/linux32/HCNetSDKCom/libHCCoreDevCfg.so b/EC.Helper/libs/hik/linux32/HCNetSDKCom/libHCCoreDevCfg.so
new file mode 100644
index 0000000..c0ba2c3
Binary files /dev/null and b/EC.Helper/libs/hik/linux32/HCNetSDKCom/libHCCoreDevCfg.so differ
diff --git a/EC.Helper/libs/hik/linux32/HCNetSDKCom/libHCPreview.so b/EC.Helper/libs/hik/linux32/HCNetSDKCom/libHCPreview.so
new file mode 100644
index 0000000..0266618
Binary files /dev/null and b/EC.Helper/libs/hik/linux32/HCNetSDKCom/libHCPreview.so differ
diff --git a/EC.Helper/libs/hik/linux32/libHCCore.so b/EC.Helper/libs/hik/linux32/libHCCore.so
new file mode 100644
index 0000000..a20f02d
Binary files /dev/null and b/EC.Helper/libs/hik/linux32/libHCCore.so differ
diff --git a/EC.Helper/libs/hik/linux32/libcrypto.so.1.1 b/EC.Helper/libs/hik/linux32/libcrypto.so.1.1
new file mode 100644
index 0000000..3a7f179
Binary files /dev/null and b/EC.Helper/libs/hik/linux32/libcrypto.so.1.1 differ
diff --git a/EC.Helper/libs/hik/linux32/libhcnetsdk.so b/EC.Helper/libs/hik/linux32/libhcnetsdk.so
new file mode 100644
index 0000000..88817a0
Binary files /dev/null and b/EC.Helper/libs/hik/linux32/libhcnetsdk.so differ
diff --git a/EC.Helper/libs/hik/linux32/libssl.so.1.1 b/EC.Helper/libs/hik/linux32/libssl.so.1.1
new file mode 100644
index 0000000..3b5628e
Binary files /dev/null and b/EC.Helper/libs/hik/linux32/libssl.so.1.1 differ
diff --git a/EC.Helper/libs/hik/linux64/HCNetSDKCom/libHCCoreDevCfg.so b/EC.Helper/libs/hik/linux64/HCNetSDKCom/libHCCoreDevCfg.so
new file mode 100644
index 0000000..402b4dc
Binary files /dev/null and b/EC.Helper/libs/hik/linux64/HCNetSDKCom/libHCCoreDevCfg.so differ
diff --git a/EC.Helper/libs/hik/linux64/HCNetSDKCom/libHCPreview.so b/EC.Helper/libs/hik/linux64/HCNetSDKCom/libHCPreview.so
new file mode 100644
index 0000000..9df6065
Binary files /dev/null and b/EC.Helper/libs/hik/linux64/HCNetSDKCom/libHCPreview.so differ
diff --git a/EC.Helper/libs/hik/linux64/libHCCore.so b/EC.Helper/libs/hik/linux64/libHCCore.so
new file mode 100644
index 0000000..49ce40f
Binary files /dev/null and b/EC.Helper/libs/hik/linux64/libHCCore.so differ
diff --git a/EC.Helper/libs/hik/linux64/libcrypto.so.1.1 b/EC.Helper/libs/hik/linux64/libcrypto.so.1.1
new file mode 100644
index 0000000..88c3746
Binary files /dev/null and b/EC.Helper/libs/hik/linux64/libcrypto.so.1.1 differ
diff --git a/EC.Helper/libs/hik/linux64/libhcnetsdk.so b/EC.Helper/libs/hik/linux64/libhcnetsdk.so
new file mode 100644
index 0000000..89a8d7d
Binary files /dev/null and b/EC.Helper/libs/hik/linux64/libhcnetsdk.so differ
diff --git a/EC.Helper/libs/hik/linux64/libssl.so.1.1 b/EC.Helper/libs/hik/linux64/libssl.so.1.1
new file mode 100644
index 0000000..f3e4481
Binary files /dev/null and b/EC.Helper/libs/hik/linux64/libssl.so.1.1 differ
diff --git a/EC.Helper/libs/hik/win32/HCCore.dll b/EC.Helper/libs/hik/win32/HCCore.dll
new file mode 100644
index 0000000..997aba4
Binary files /dev/null and b/EC.Helper/libs/hik/win32/HCCore.dll differ
diff --git a/EC.Helper/libs/hik/win32/HCNetSDK.dll b/EC.Helper/libs/hik/win32/HCNetSDK.dll
new file mode 100644
index 0000000..4ab572c
Binary files /dev/null and b/EC.Helper/libs/hik/win32/HCNetSDK.dll differ
diff --git a/EC.Helper/libs/hik/win32/HCNetSDKCom/HCCoreDevCfg.dll b/EC.Helper/libs/hik/win32/HCNetSDKCom/HCCoreDevCfg.dll
new file mode 100644
index 0000000..08ace5e
Binary files /dev/null and b/EC.Helper/libs/hik/win32/HCNetSDKCom/HCCoreDevCfg.dll differ
diff --git a/EC.Helper/libs/hik/win32/HCNetSDKCom/HCPreview.dll b/EC.Helper/libs/hik/win32/HCNetSDKCom/HCPreview.dll
new file mode 100644
index 0000000..b8bf1f5
Binary files /dev/null and b/EC.Helper/libs/hik/win32/HCNetSDKCom/HCPreview.dll differ
diff --git a/EC.Helper/libs/hik/win32/libcrypto-1_1.dll b/EC.Helper/libs/hik/win32/libcrypto-1_1.dll
new file mode 100644
index 0000000..872a807
Binary files /dev/null and b/EC.Helper/libs/hik/win32/libcrypto-1_1.dll differ
diff --git a/EC.Helper/libs/hik/win32/libssl-1_1.dll b/EC.Helper/libs/hik/win32/libssl-1_1.dll
new file mode 100644
index 0000000..331f43b
Binary files /dev/null and b/EC.Helper/libs/hik/win32/libssl-1_1.dll differ
diff --git a/EC.Helper/libs/hik/win64/HCCore.dll b/EC.Helper/libs/hik/win64/HCCore.dll
new file mode 100644
index 0000000..266afa3
Binary files /dev/null and b/EC.Helper/libs/hik/win64/HCCore.dll differ
diff --git a/EC.Helper/libs/hik/win64/HCNetSDK.dll b/EC.Helper/libs/hik/win64/HCNetSDK.dll
new file mode 100644
index 0000000..0c4ef60
Binary files /dev/null and b/EC.Helper/libs/hik/win64/HCNetSDK.dll differ
diff --git a/EC.Helper/libs/hik/win64/HCNetSDKCom/HCCoreDevCfg.dll b/EC.Helper/libs/hik/win64/HCNetSDKCom/HCCoreDevCfg.dll
new file mode 100644
index 0000000..63a8836
Binary files /dev/null and b/EC.Helper/libs/hik/win64/HCNetSDKCom/HCCoreDevCfg.dll differ
diff --git a/EC.Helper/libs/hik/win64/HCNetSDKCom/HCPreview.dll b/EC.Helper/libs/hik/win64/HCNetSDKCom/HCPreview.dll
new file mode 100644
index 0000000..92a3cf9
Binary files /dev/null and b/EC.Helper/libs/hik/win64/HCNetSDKCom/HCPreview.dll differ
diff --git a/EC.Helper/libs/hik/win64/libcrypto-1_1-x64.dll b/EC.Helper/libs/hik/win64/libcrypto-1_1-x64.dll
new file mode 100644
index 0000000..6731338
Binary files /dev/null and b/EC.Helper/libs/hik/win64/libcrypto-1_1-x64.dll differ
diff --git a/EC.Helper/libs/hik/win64/libssl-1_1-x64.dll b/EC.Helper/libs/hik/win64/libssl-1_1-x64.dll
new file mode 100644
index 0000000..ac5e8fd
Binary files /dev/null and b/EC.Helper/libs/hik/win64/libssl-1_1-x64.dll differ
diff --git a/EC.Helper/libs/yushi/linux64/libNetDEVSDK.so b/EC.Helper/libs/yushi/linux64/libNetDEVSDK.so
new file mode 100644
index 0000000..6363434
Binary files /dev/null and b/EC.Helper/libs/yushi/linux64/libNetDEVSDK.so differ
diff --git a/EC.Helper/libs/yushi/win32/NetDEVSDK.dll b/EC.Helper/libs/yushi/win32/NetDEVSDK.dll
new file mode 100644
index 0000000..4d40904
Binary files /dev/null and b/EC.Helper/libs/yushi/win32/NetDEVSDK.dll differ
diff --git a/EC.Helper/libs/yushi/win64/NetDEVSDK.dll b/EC.Helper/libs/yushi/win64/NetDEVSDK.dll
new file mode 100644
index 0000000..b705019
Binary files /dev/null and b/EC.Helper/libs/yushi/win64/NetDEVSDK.dll differ