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
}
}