using System.Runtime.InteropServices; using System.Text; namespace EC.Util.CameraSDK; public class HiKSdk : ICameraSdk { #region Fields private int LoginId { get; set; } = -1; private int Channel { get; } = 1; #endregion Fields public HiKSdk(CameraInfo cameraInfo) : base(cameraInfo) { } #region Base Method public override bool Init() { bool ret = ConnectSuccess(); if (ret) return true; HiKOriSdk.NET_DVR_USER_LOGIN_INFO loginInfo = new() { bUseAsynLogin = false, sDeviceAddress = new byte[129], wPort = (ushort)CameraInfo.Port, sUserName = new byte[64], sPassword = new byte[64] }; Encoding.Default.GetBytes(CameraInfo.Ip).CopyTo(loginInfo.sDeviceAddress, 0); Encoding.Default.GetBytes(CameraInfo.UserName).CopyTo(loginInfo.sUserName, 0); Encoding.Default.GetBytes(CameraInfo.Password).CopyTo(loginInfo.sPassword, 0); HiKOriSdk.NET_DVR_DEVICEINFO_V40 deviceInfo = new(); LoginId = HiKOriSdk.NET_DVR_Login_V40(ref loginInfo, ref deviceInfo); ret = ConnectSuccess(); if (ret) HiKOriSdk.NET_DVR_SetReconnect(10000, 1); else BuildException(); //HiKOriSdk.NET_DVR_DEVICEINFO_V30 deviceInfo = new(); //LoginId = HiKOriSdk.NET_DVR_Login_V30(CameraInfo.Ip, CameraInfo.Port, CameraInfo.UserName, CameraInfo.Password, ref deviceInfo); return ret; } public override bool Destory() { bool ret = ConnectSuccess(); if (!ret) return true; ret = HiKOriSdk.NET_DVR_Logout(LoginId); if (ret) LoginId = -1; else BuildException(); return ret; } public override bool ConnectSuccess() { return LoginId >= 0; } internal override void BuildException() { uint errCode = HiKOriSdk.NET_DVR_GetLastError(); if (errCode == 0) return; throw CameraException.New(CameraInfo, (int)errCode); } private void BuildPlayCtrlException(int nPort) { string err = $"PlayCtrlSdk failed, error code={PlayCtrlSdk.PlayM4_GetLastError(nPort)}"; throw CameraException.New(CameraInfo, -1, err); } #endregion Base Method #region Ptz 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); } } public override bool TryGetPtzInfo(out PtzInfo ptzInfo) { bool ret = ConnectSuccess(); if (!ret) { ptzInfo = PtzInfo.Default; return false; } 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(); ptzInfo = PtzInfo.Default; return false; } object? objBuf = Marshal.PtrToStructure(ptrBuf, GPIParams.Type); if (objBuf == null) { ptzInfo = PtzInfo.Default; return false; } entity = (HiKOriSdk.NET_DVR_PTZPOS)objBuf; ptzInfo = PtzInfo.New(entity.wPanPos, entity.wTiltPos, entity.wZoomPos); return true; } finally { Marshal.FreeHGlobal(ptrBuf); } } public override bool PtzMove(int cmd, int stop, int speed) { if (!ConnectSuccess()) return false; bool ret = HiKOriSdk.NET_DVR_PTZControlWithSpeed_Other(LoginId, Channel, (uint)cmd, (uint)stop, (uint)speed); if (!ret) BuildException(); return ret; } public override bool PtzPreset(int cmd, int presetId) { if (!ConnectSuccess()) return false; bool ret = HiKOriSdk.NET_DVR_PTZPreset_Other(LoginId, Channel, (uint)cmd, (uint)presetId); if (!ret) BuildException(); return ret; } #endregion Ptz Method #region Video Method private int RealplayHandle { get; set; } = -1; private int RealpalyPort { get; set; } = -1; private IntPtr Hwnd { get; set; } public override void StartPlay(IntPtr hwnd) { if (!ConnectSuccess() || IsPlaying()) return; Hwnd = hwnd; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) StartPlayWindows(); else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) StartPlayLinux(); else Hwnd = IntPtr.Zero; } private void StartPlayWindows() { HiKOriSdk.NET_DVR_PREVIEWINFO previewInfo = new() { hPlayWnd = Hwnd, //预览窗口 lChannel = 1, //预览的设备通道 dwStreamType = 0, //码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推 dwLinkMode = 0, //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP bBlocked = true, //0- 非阻塞取流,1- 阻塞取流 }; IntPtr pUser = new(); //用户数据 RealplayHandle = HiKOriSdk.NET_DVR_RealPlay_V40(LoginId, ref previewInfo, null, pUser); if (RealplayHandle < 0) BuildException(); } private void StartPlayLinux() { if (RealpalyPort < 0) { int nPort = -1; bool ret = PlayCtrlSdk.PlayM4_GetPort(ref nPort); if (!ret) BuildPlayCtrlException(nPort); RealpalyPort = nPort; } HiKOriSdk.NET_DVR_PREVIEWINFO previewInfo = new() { hPlayWnd = IntPtr.Zero, //预览窗口 lChannel = 1, //预览的设备通道 dwStreamType = 0, //码流类型:0-主码流,1-子码流,2-码流3,3-码流4,以此类推 dwLinkMode = 0, //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP bBlocked = true, //0- 非阻塞取流,1- 阻塞取流 }; RealplayHandle = HiKOriSdk.NET_DVR_RealPlay_V40(LoginId, ref previewInfo, RealDataCallBack, IntPtr.Zero); if (RealplayHandle < 0) BuildException(); } private void RealDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser) { if (dwBufSize <= 0) return; switch (dwDataType) { case HiKOriSdk.NET_DVR_SYSHEAD: try { PlayCtrlSdk.PlayM4_SetStreamOpenMode(RealpalyPort, 0); PlayCtrlSdk.PlayM4_OpenStream(RealpalyPort, pBuffer, dwBufSize, 2 * 1024 * 1024); if (!PlayCtrlSdk.PlayM4_Play(RealpalyPort, Hwnd)) BuildPlayCtrlException(RealpalyPort); } catch (Exception) { StopPlay(); throw; } break; case HiKOriSdk.NET_DVR_STREAMDATA: PlayCtrlSdk.PlayM4_InputData(RealpalyPort, pBuffer, dwBufSize); break; } } public override void StopPlay() { if (!IsPlaying()) return; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) StopPlayWindows(); else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) StopPlayLinux(); Hwnd = IntPtr.Zero; } public void StopPlayWindows() { bool ret = HiKOriSdk.NET_DVR_StopRealPlay(RealplayHandle); RealplayHandle = -1; if (!ret) BuildException(); } public void StopPlayLinux() { bool ret = HiKOriSdk.NET_DVR_StopRealPlay(RealplayHandle); RealplayHandle = -1; if (RealpalyPort >= 0) { //if(!PlayCtrlSdk.PlayM4_Stop(RealpalyPort)) BuildPlayCtrlException(RealpalyPort); PlayCtrlSdk.PlayM4_Stop(RealpalyPort); PlayCtrlSdk.PlayM4_CloseStream(RealpalyPort); PlayCtrlSdk.PlayM4_FreePort(RealpalyPort); RealpalyPort = -1; } if (!ret) BuildException(); } public override bool IsPlaying() { return RealplayHandle >= 0; } #endregion Video Method }