using FATrace.HKNetLib.Common; using FATrace.HKNetLib.Hardware; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using static FATrace.HKNetLib.Hardware.CHCNetSDK; namespace FATrace.HKNetLib.Wrapper { public class HkCamera : ICamera { private bool _disposedValue; private bool _sdkInit; private int _userId; private string _serailNumber; private CameraLoginInfo _loginInfo = new CameraLoginInfo(); /// /// 初始化海康sdk /// /// public HkCamera() { _sdkInit = CHCNetSDK.NET_DVR_Init(); } static HkCamera() { //设置搜索路径,兼容x86 和 x64 var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); path = Path.Combine(path, "Lib", IntPtr.Size == 8 ? "x64" : "x86"); bool ok = SetDllDirectory(path); if (!ok) throw new System.ComponentModel.Win32Exception(); } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool SetDllDirectory(string path); /// /// 获取最新的错误信息 /// /// public string GetLastError() { var error = CHCNetSDK.NET_DVR_GetLastError(); if (error == 0) { return string.Empty; } if (Enum.TryParse(error.ToString(), out HKErrorCode result)) { return result.GetDesc(); } return $"错误码: {error}"; } public string GetSerialNumber() { return _serailNumber; } public bool Login(CameraLoginInfo cameraLoginInfo) { try { if (_userId >= 0) { Logout(); } _loginInfo = cameraLoginInfo; var loginInfo = new CHCNetSDK.NET_DVR_USER_LOGIN_INFO(); loginInfo.sDeviceAddress = cameraLoginInfo.IP; loginInfo.wPort = cameraLoginInfo.Port; loginInfo.sUserName = cameraLoginInfo.UserName; loginInfo.sPassword = cameraLoginInfo.Password; //是否异步登录:0- 否,1- 是 loginInfo.bUseAsynLogin = false; var _deviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V40(); _userId = CHCNetSDK.NET_DVR_Login_V40(ref loginInfo, ref _deviceInfo); _serailNumber = _deviceInfo.struDeviceV30.sSerialNumber; return _userId >= 0; } catch { return false; } } #region NVR开发 /// /// NVR设备信息 DVR_DEVICEINFO_V30 /// public NET_DVR_DEVICEINFO_V30 DVRDeviceInfoV30; /// /// DVR_IPPARACFG_V40 /// public CHCNetSDK.NET_DVR_IPPARACFG_V40 DVR_IPPARACFG_V40 { get; set; } private uint dwAChanTotalNum { get; set; } = 0; private uint dwDChanTotalNum { get; set; } = 0; public NET_DVR_GET_STREAM_UNION DVR_GET_STREAM_UNION { get; set; } public CHCNetSDK.NET_DVR_IPCHANINFO DVR_IPCHANINFO { get; set; } /// /// 最新的错误信息 /// public string LastMsgErr { get; set; } /// /// 登录的用户Id /// public Int32 m_lUserID { get; set; } = -1; /// /// 选择的通道号 /// 一般是 一个通道对应一个相机 /// public long iSelIndex = 0; /// /// 通道集合 /// [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 96, ArraySubType = UnmanagedType.U4)] public int[] iChannelNum = new int[96]; /// /// 下载的Handle /// public Int32 m_lDownHandle { get; set; } = -1; /// /// 用户登录 /// /// public bool Sdk_NET_DVR_Login_V30(string DVRIPAddress, int DVRPortNumber, string DVRUserName, string DVRPassword) { //登录设备 Login the device m_lUserID = CHCNetSDK.NET_DVR_Login_V30(DVRIPAddress, DVRPortNumber, DVRUserName, DVRPassword, ref DVRDeviceInfoV30); if (m_lUserID < 0) { LastMsgErr = GetLastError(); //MessageBox.Show(str1); return false; } else { //登录成功 //MessageBox.Show("Login Success!"); //btnLogin.Text = "Logout"; dwAChanTotalNum = (uint)DVRDeviceInfoV30.byChanNum; dwDChanTotalNum = (uint)DVRDeviceInfoV30.byIPChanNum + 256 * (uint)DVRDeviceInfoV30.byHighDChanNum; if (dwDChanTotalNum > 0) { InfoIPChannel(); } else { for (int i = 0; i < dwAChanTotalNum; i++) { //ListAnalogChannel(i + 1, 1); iChannelNum[i] = i + (int)DVRDeviceInfoV30.byStartChan; } // MessageBox.Show("This device has no IP channel!"); } } return true; } /// /// 获取通道信息 /// private void InfoIPChannel() { uint dwSize = (uint)Marshal.SizeOf(DVR_IPPARACFG_V40); IntPtr ptrIpParaCfgV40 = Marshal.AllocHGlobal((Int32)dwSize); Marshal.StructureToPtr(DVR_IPPARACFG_V40, ptrIpParaCfgV40, false); uint dwReturn = 0; int iGroupNo = 0; //该Demo仅获取第一组64个通道,如果设备IP通道大于64路,需要按组号0~i多次调用NET_DVR_GET_IPPARACFG_V40获取 if (!CHCNetSDK.NET_DVR_GetDVRConfig(m_lUserID, CHCNetSDK.NET_DVR_GET_IPPARACFG_V40, iGroupNo, ptrIpParaCfgV40, dwSize, ref dwReturn)) { LastMsgErr = GetLastError(); /*str1 = "NET_DVR_GET_IPPARACFG_V40 failed, error code= " + iLastErr; //*/ //获取IP资源配置信息失败,输出错误号 //MessageBox.Show(str1); } else { // succ DVR_IPPARACFG_V40 = (CHCNetSDK.NET_DVR_IPPARACFG_V40)Marshal.PtrToStructure(ptrIpParaCfgV40, typeof(CHCNetSDK.NET_DVR_IPPARACFG_V40)); for (int i = 0; i < dwAChanTotalNum; i++) { //ListAnalogChannel(i + 1, DVR_IPPARACFG_V40.byAnalogChanEnable[i]); iChannelNum[i] = i + (int)DVRDeviceInfoV30.byStartChan; } byte byStreamType; uint iDChanNum = 64; if (dwDChanTotalNum < 64) { iDChanNum = dwDChanTotalNum; //如果设备IP通道小于64路,按实际路数获取 } for (int i = 0; i < iDChanNum; i++) { iChannelNum[i + dwAChanTotalNum] = i + (int)DVR_IPPARACFG_V40.dwStartDChan; byStreamType = DVR_IPPARACFG_V40.struStreamMode[i].byGetStreamType; DVR_GET_STREAM_UNION = DVR_IPPARACFG_V40.struStreamMode[i].uGetStream; switch (byStreamType) { //目前NVR仅支持0- 直接从设备取流一种方式 case 0: dwSize = (uint)Marshal.SizeOf(DVR_GET_STREAM_UNION); IntPtr ptrChanInfo = Marshal.AllocHGlobal((Int32)dwSize); Marshal.StructureToPtr(DVR_GET_STREAM_UNION, ptrChanInfo, false); DVR_IPCHANINFO = (CHCNetSDK.NET_DVR_IPCHANINFO)Marshal.PtrToStructure(ptrChanInfo, typeof(CHCNetSDK.NET_DVR_IPCHANINFO)); //列出IP通道 //ListIPChannel(i + 1, DVR_IPCHANINFO.byEnable, DVR_IPCHANINFO.byIPID); Marshal.FreeHGlobal(ptrChanInfo); break; default: break; } } } Marshal.FreeHGlobal(ptrIpParaCfgV40); } /// /// 根据时间获取DVR统计信息 /// public (bool Result, string Msg) Sdk_NET_DVR_GetFileByTime_V40(DateTime startTime, DateTime endTime, string SaveVideFilePath) { if (m_lDownHandle >= 0) { //MessageBox.Show("Downloading, please stop firstly!");//正在下载,请先停止下载 return (Result: false, Msg: "正在下载,请先停止下载"); } NET_DVR_PLAYCOND struDownPara = new NET_DVR_PLAYCOND(); struDownPara.dwChannel = (uint)iChannelNum[(int)iSelIndex]; //通道号 Channel number //设置下载的开始时间 Set the starting time struDownPara.struStartTime.dwYear = startTime.Year; struDownPara.struStartTime.dwMonth = startTime.Month; struDownPara.struStartTime.dwDay = startTime.Day; struDownPara.struStartTime.dwHour = startTime.Hour; struDownPara.struStartTime.dwMinute = startTime.Minute; struDownPara.struStartTime.dwSecond = startTime.Second; //设置下载的结束时间 Set the stopping time struDownPara.struStopTime.dwYear = endTime.Year; struDownPara.struStopTime.dwMonth = endTime.Month; struDownPara.struStopTime.dwDay = endTime.Day; struDownPara.struStopTime.dwHour = endTime.Hour; struDownPara.struStopTime.dwMinute = endTime.Minute; struDownPara.struStopTime.dwSecond = endTime.Second; //string sVideoFileName; //录像文件保存路径和文件名 the path and file name to save //sVideoFileName = "D:\\Downtest_Channel" + struDownPara.dwChannel + ".mp4"; //按时间下载 Download by time m_lDownHandle = CHCNetSDK.NET_DVR_GetFileByTime_V40(m_lUserID, SaveVideFilePath, ref struDownPara); if (m_lDownHandle < 0) { LastMsgErr = GetLastError(); return (Result: false, Msg: $"[NET_DVR_GetFileByTime_V40] 执行下载失败:{LastMsgErr}"); } uint iOutValue = 0; //该接口指定了当前要下载的录像文件,调用成功后,还需要调用NET_DVR_PlayBackControl_V40接口的开始播放控制命令(NET_DVR_PLAYSTART)才能实现下载。 //V5.0.3.2或以后版本,通过该接口保存录像,保存的录像文件数据超过文件最大限制字节数(默认为1024MB),SDK会自动切片,即新建文件进行保存,文件名命名规则为“在接口传入的文件名基础上增加数字标识(例如:*_1.mp4、*_2.mp4)”。 //可以调用NET_DVR_GetSDKLocalCfg、NET_DVR_SetSDKLocalCfg(配置类型:NET_DVR_LOCAL_CFG_TYPE_GENERAL)获取和设置切片模式和文件最大限制字节数。 if (!CHCNetSDK.NET_DVR_PlayBackControl_V40(m_lDownHandle, CHCNetSDK.NET_DVR_PLAYSTART, IntPtr.Zero, 0, IntPtr.Zero, ref iOutValue)) { LastMsgErr = GetLastError(); return (Result: false, Msg: $"[NET_DVR_PlayBackControl_V40] 执行下载控制失败:{LastMsgErr}"); } return (Result: true, Msg: "下载成功!"); } /// /// 获取下载的进度 /// /// /// public int Sdk_NET_DVR_GetDownloadPos(Int32 downHandle) { return CHCNetSDK.NET_DVR_GetDownloadPos(downHandle); } #endregion public bool IsOnline() { try { return CHCNetSDK.NET_DVR_RemoteControl(_userId, CHCNetSDK.NET_DVR_CHECK_USER_STATUS, IntPtr.Zero, 0); } catch { return false; } } public void Logout() { try { if (_userId >= 0) { CHCNetSDK.NET_DVR_Logout(_userId); _userId = -1; } } catch { } } private bool CheckLogin() { if (IsOnline()) return true; return Login(_loginInfo); } /// /// 控制云台,设备接收到控制命令后直接返回成功。不关心云台是否进行相应的动作 /// /// /// 取值范围[1,7] /// public bool StartPTZControl(PtzCommand cmd, Int32 speed = 4) { try { if (!CheckLogin()) return false; var result = CHCNetSDK.NET_DVR_PTZControlWithSpeed_Other(_userId, _loginInfo.ChannelNo, (uint)cmd, 0, (uint)speed); return result; } catch { return false; } } /// /// 停止云台 /// /// /// public bool StopPTZControl(PtzCommand cmd) { try { if (!CheckLogin()) return false; var result = CHCNetSDK.NET_DVR_PTZControlWithSpeed_Other(_userId, _loginInfo.ChannelNo, (uint)cmd, 1, 4); return result; } catch { return false; } } /// /// 抓图 /// /// /// public bool CapturePicture(string fileName) { if (!CheckLogin()) return false; try { FileInfo fi = new FileInfo(fileName); if (fi.Exists) { File.Delete(fi.FullName); } if (!Directory.Exists(fi.DirectoryName)) { Directory.CreateDirectory(fi.DirectoryName); } CHCNetSDK.NET_DVR_JPEGPARA lpJpegPara = new CHCNetSDK.NET_DVR_JPEGPARA { wPicQuality = 0, wPicSize = 0xff }; return CHCNetSDK.NET_DVR_CaptureJPEGPicture(_userId, _loginInfo.ChannelNo, ref lpJpegPara, fileName); } catch { return false; } } public bool SetFocusMode(FocusModeType focusModeType) { bool res = false; var destMode = focusModeType; CHCNetSDK.NET_DVR_FOCUSMODE_CFG focusmode_cfg = new CHCNetSDK.NET_DVR_FOCUSMODE_CFG(); focusmode_cfg.byRes = new byte[48]; focusmode_cfg.byRes1 = new byte[2]; int nSize = Marshal.SizeOf(focusmode_cfg); focusmode_cfg.dwSize = (uint)nSize; IntPtr ptrDeviceCfg = Marshal.AllocHGlobal(nSize); try { // 获取当前模式 Marshal.StructureToPtr(focusmode_cfg, ptrDeviceCfg, false); uint rSize = (uint)nSize; if (!CHCNetSDK.NET_DVR_GetDVRConfig(_userId, CHCNetSDK.NET_DVR_GET_FOCUSMODECFG, 1, ptrDeviceCfg, (uint)nSize, ref rSize)) { var errorStr = CHCNetSDK.NET_DVR_GetLastError(); return res; } // 如果当前模式与请求模式相同,则直接返回true CHCNetSDK.NET_DVR_FOCUSMODE_CFG getObj = (CHCNetSDK.NET_DVR_FOCUSMODE_CFG)Marshal.PtrToStructure(ptrDeviceCfg, typeof(CHCNetSDK.NET_DVR_FOCUSMODE_CFG)); var curMode = (FocusModeType)getObj.byFocusMode; if (curMode == destMode) { res = true; return res; } // 否则调用设置方法 getObj.fOpticalZoomLevel = 0; getObj.byOpticalZoom = 32; getObj.byFocusMode = (byte)destMode; IntPtr ptrDeviceCfg1 = Marshal.AllocHGlobal((int)getObj.dwSize); Marshal.StructureToPtr(getObj, ptrDeviceCfg1, false); res = CHCNetSDK.NET_DVR_SetDVRConfig(_userId, CHCNetSDK.NET_DVR_SET_FOCUSMODECFG, 1, ptrDeviceCfg1, focusmode_cfg.dwSize); if (!res) { var errorStr = CHCNetSDK.NET_DVR_GetLastError(); } } catch (Exception ex) { throw ex; } finally { Marshal.FreeHGlobal(ptrDeviceCfg); } return res; } /// /// 获取对焦距模式 /// /// public FocusModeType GetFocusMode() { FocusModeType retValue = FocusModeType.None; CHCNetSDK.NET_DVR_FOCUSMODE_CFG focusmode_cfg = new CHCNetSDK.NET_DVR_FOCUSMODE_CFG { byRes = new byte[48], byRes1 = new byte[2] }; int nSize = Marshal.SizeOf(focusmode_cfg); focusmode_cfg.dwSize = (uint)nSize; IntPtr ptrDeviceCfg = Marshal.AllocHGlobal(nSize); try { Marshal.StructureToPtr(focusmode_cfg, ptrDeviceCfg, false); uint rSize = (uint)nSize; if (CHCNetSDK.NET_DVR_GetDVRConfig(this._userId, CHCNetSDK.NET_DVR_GET_FOCUSMODECFG, 1, ptrDeviceCfg, (uint)nSize, ref rSize)) { CHCNetSDK.NET_DVR_FOCUSMODE_CFG getObj = (CHCNetSDK.NET_DVR_FOCUSMODE_CFG)Marshal.PtrToStructure(ptrDeviceCfg, typeof(CHCNetSDK.NET_DVR_FOCUSMODE_CFG)); retValue = (FocusModeType)getObj.byFocusMode; } } catch (Exception ex) { throw ex; } finally { Marshal.FreeHGlobal(ptrDeviceCfg); } return retValue; } public bool Shutdown() { try { if (!CheckLogin()) return false; return CHCNetSDK.NET_DVR_ShutDownDVR(_userId); } catch { return false; } } public bool Reboot() { try { if (!CheckLogin()) return false; return CHCNetSDK.NET_DVR_RebootDVR(_userId); } catch { return false; } } #region 释放接口 protected virtual void Dispose(bool disposing) { if (!_disposedValue) { if (disposing) { // TODO: 释放托管状态(托管对象) } if (_sdkInit) { if (_userId >= 0) { Logout(); } try { CHCNetSDK.NET_DVR_Cleanup(); } catch { } } _disposedValue = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } #endregion } }