Unity による Hikvision カメラ SDK へのアクセス (ナニー レベル)

Unity による Hikvision Camera SDK へのアクセス (2023/6/21)

1. 問題の説明: Hikvision カメラを制御して操作します (遠焦点、近焦点、上下、左右の移動など)。
2. 準備: 公式 Web サイトから SDK をダウンロードします: https://open.hikvision.com/#home
プラットフォームのコード言語開発に適した SDK を選択し、ライブラリで
開ける
表示できるデモで対応するケースをダウンロードします。
ClientDemoDll ファイルを除くファイルをunityPluginsにドラッグし、重複したDllファイルを2つ
dll
削除できます(OpenAL、AudioRender)。数が多すぎる場合は、不要なものに応じてゆっくり削除できます。
3. スクリプトを開始します( 2つのスクリプト)
(1) DLLを参照するスクリプト

public class HCNetSDK
{
    
    
    #region HCNetSDK.dll function definition
    // function definition
    /* The SDK initialization function */

    // 初始化SDK,调用其他SDK函数的前提
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_Init();

    // 启用日志文件写入接口
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_SetLogToFile(int nLogLevel, IntPtr strLogDir, bool bAutoDel);

    // 返回最后操作的错误码
    [DllImport(@"HCNetSDK.dll")]
    public static extern uint NET_DVR_GetLastError();

    // 释放SDK资源,在程序结束之前调用
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_Cleanup();

    // 登录接口 v40
    [DllImport(@"HCNetSDK.dll")]
    public static extern int NET_DVR_Login_V40(ref NET_DVR_USER_LOGIN_INFO pLoginInfo, ref NET_DVR_DEVICEINFO_V40 lpDeviceInfo);
    
    // 用户注销
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_Logout(int lUserID);

    // 回调函数声明,登录状态回调函数
    public delegate void LoginResultCallBack(int lUserID, uint dwResult, ref NET_DVR_DEVICEINFO_V30 lpDeviceInfo, IntPtr pUser);


    //云台控制
    [DllImport(@"HCNetSDK.dll")]
    public static extern bool NET_DVR_PTZControlWithSpeed_Other(int lUserID, int lChannel, uint dwPTZCommand, uint dwStop, uint dwSpeed);

    #endregion

    #region HCNetSDK.dll structure definition

    [StructLayout(LayoutKind.Sequential)]
    public struct NET_DVR_USER_LOGIN_INFO
    {
    
    
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_DEV_ADDRESS_MAX_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] sDeviceAddress;
        public byte byUseTransport;
        public ushort wPort;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_LOGIN_USERNAME_MAX_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] sUserName;
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = NET_DVR_LOGIN_PASSWD_MAX_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] sPassword;
        public LoginResultCallBack cbLoginResult;
        public IntPtr pUser;
        public bool bUseAsynLogin;
        public byte byProxyType; //0:不使用代理,1:使用标准代理,2:使用EHome代理
        public byte byUseUTCTime;    //0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换
        public byte byLoginMode; //0-Private, 1-ISAPI, 2-自适应
        public byte byHttps;    //0-不适用tls,1-使用tls 2-自适应
        public uint iProxyID;    //代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值
        public byte byVerifyMode;  //认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效;    
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 119, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes3;
    }

    public const int NET_DVR_DEV_ADDRESS_MAX_LEN = 129; //device address max length
    public const int NET_DVR_LOGIN_USERNAME_MAX_LEN = 64;   //login username max length
    public const int NET_DVR_LOGIN_PASSWD_MAX_LEN = 64; //login password max length

    public struct NET_DVR_DEVICEINFO_V40
    {
    
    
        public NET_DVR_DEVICEINFO_V30 struDeviceV30;
        public byte bySupportLock;        //设备支持锁定功能,该字段由SDK根据设备返回值来赋值的。bySupportLock为1时,dwSurplusLockTime和byRetryLoginTime有效
        public byte byRetryLoginTime;       //剩余可尝试登陆的次数,用户名,密码错误时,此参数有效
        public byte byPasswordLevel;      //admin密码安全等级0-无效,1-默认密码,2-有效密码,3-风险较高的密码。当用户的密码为出厂默认密码(12345)或者风险较高的密码时,上层客户端需要提示用户更改密码。      
        public byte byProxyType;//代理类型,0-不使用代理, 1-使用socks5代理, 2-使用EHome代理
        public uint dwSurplusLockTime;  //剩余时间,单位秒,用户锁定时,此参数有效
        public byte byCharEncodeType;     //字符编码类型(SDK所有接口返回的字符串编码类型,透传接口除外):0- 无字符编码信息(老设备),1- GB2312(简体中文),2- GBK,3- BIG5(繁体中文),4- Shift_JIS(日文),5- EUC-KR(韩文),6- UTF-8,7- ISO8859-1,8- ISO8859-2,9- ISO8859-3,…,依次类推,21- ISO8859-15(西欧) 
        public byte bySupportDev5;//支持v50版本的设备参数获取,设备名称和设备类型名称长度扩展为64字节
        public byte bySupport;  //能力集扩展,位与结果:0- 不支持,1- 支持
                                // bySupport & 0x1:  保留
                                // bySupport & 0x2:  0-不支持变化上报 1-支持变化上报
        public byte byLoginMode; //登录模式 0-Private登录 1-ISAPI登录
        public int dwOEMCode;
        public int iResidualValidity;   //该用户密码剩余有效天数,单位:天,返回负值,表示密码已经超期使用,例如“-3表示密码已经超期使用3天”
        public byte byResidualValidity; // iResidualValidity字段是否有效,0-无效,1-有效
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 243, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes2;
    }

    public const int SERIALNO_LEN = 48;//序列号长度
    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;		//保留
    }

    #endregion
}

(2) Hikvision カメラを制御するスクリプト

public class Camera_HK : MonoBehaviour
{
    
    
    public Text showMesText;

    private uint iLastErr = 0;
    private int m_lUserID = -1;
    private HCNetSDK.NET_DVR_USER_LOGIN_INFO struLogInfo;
    private HCNetSDK.NET_DVR_DEVICEINFO_V40 DeviceInfo;
    private string str;

    HCNetSDK.LoginResultCallBack LoginCallBack = null;

    public Button up_Button;
    public Button dow_Button;
    public Button lef_Button;
    public Button rig_Button;
    public Button zoomOut_Button;//焦距小
    public Button zoomIn_Button;

    
    Thread thread;
    void Start()
    {
    
    

        bool m_bInitSDK = HCNetSDK.NET_DVR_Init();
        if (m_bInitSDK == false)
        {
    
    
            Debug.Log("初始化失败!");
            // showMesText.text += "初始化失败!";
            return;
        }
        else
        {
    
    
            Debug.Log("初始化成功!");

            // showMesText.text += "初始化成功!";
        }

        LoginCameraHK();      

    }


    #region 按钮事件  

    /// <summary>
    /// 云控制台
    /// </summary>
    /// <param name="登录成功返回的ID"></param>
    /// <param name="默认1"></param>
    /// <param name="平台控制命令"></param>
    /// <param name="开始/停止"></param>
    /// <param name="速度"></param>
    /// <param name="备注"></param>
    private void ControlHead(int lUserID, int lChannel, uint dwPTZCommand, uint dwStop, uint dwSpeed,string remarks="")
    {
    
    
        if (HCNetSDK.NET_DVR_PTZControlWithSpeed_Other(lUserID, lChannel, dwPTZCommand, dwStop, dwSpeed))
        {
    
    
            Debug.Log("控制云台成功!"+ remarks);
        }
        else
        {
    
    
            Debug.Log("控制云台失败...");
            ViewErrorInfo("初始化失败!", HCNetSDK.NET_DVR_GetLastError());
        }
    }
    //Button 按钮  Event Trigger 组件 按下开始做操作 抬起 停止
    public void up_ButtonDownEvent()
    {
    
           
        ControlHead(m_lUserID, 1, 21, 0, 2, "开始上仰");
    }
    public void up_ButtonUpEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 21, 1, 2, "关闭上仰");
    }
    
    public void dow_ButtonDownEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 22, 0, 2, "开始下俯");
    }

    public void dow_ButtonUpEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 22, 1, 2, "关闭下俯");
    }
    
    public void lef_ButtonDownEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 23, 0, 2, "开始左转");
    }

    public void lef_ButtonUpEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 23, 1, 2, "关闭左转");
    }

    public void rig_ButtonDownEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 24, 0, 2, "开始右转");
    }

    public void rig_ButtonUpEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 24, 1, 2, "关闭右转");
    }

    public void zoomOut_ButtonDownEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 11, 0, 2, "开始焦距变小");
    }

    public void zoomOut_ButtonUpEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 11, 1, 2, "关闭焦距变小");
    }
    
    public void zoomIn_ButtonDownEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 12, 0, 2, "开始焦距变大");
    }

    public void zoomIn_ButtonUpEvent()
    {
    
    
        ControlHead(m_lUserID, 1, 12, 1, 2, "关闭焦距变大");
    }

   
    #endregion
    private void ViewErrorInfo(string errorMessage, uint errorCode)
    {
    
    
        Debug.Log(errorMessage + ", 错误代码: " + errorCode);
    }
    public void LoginCameraHK()
    {
    
    
        struLogInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();

        if (m_lUserID < 0)
        {
    
    
            //从textBox文本框读取字符串,转成byte数组之后,赋值给结构体对象中对应字段
            //设备IP地址或者域名
            byte[] byIP = System.Text.Encoding.Default.GetBytes("192.168.0.201"); //改成自己的
            struLogInfo.sDeviceAddress = new byte[129];
            byIP.CopyTo(struLogInfo.sDeviceAddress, 0);

            //设备用户名
            byte[] byUserName = System.Text.Encoding.Default.GetBytes("admin"); // 改成自己的
            struLogInfo.sUserName = new byte[64];
            byUserName.CopyTo(struLogInfo.sUserName, 0);

            //设备密码
            byte[] byPassword = System.Text.Encoding.Default.GetBytes("q123456.");///改成自己的
            struLogInfo.sPassword = new byte[64];
            byPassword.CopyTo(struLogInfo.sPassword, 0);

            struLogInfo.wPort = ushort.Parse("8000");//设备服务端口号   ///改成自己的  这边注意视频流554 等不是端口 ,端口需要进海康相机自带平台去看一下

            if (LoginCallBack == null)
            {
    
    
                LoginCallBack = new HCNetSDK.LoginResultCallBack(cbLoginCallBack);//注册回调函数                    
            }
            struLogInfo.cbLoginResult = LoginCallBack;
            struLogInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是 

            DeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();

            //登录设备 Login the device
            m_lUserID = HCNetSDK.NET_DVR_Login_V40(ref struLogInfo, ref DeviceInfo);



            if (m_lUserID < 0)
            {
    
    
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_Login_V40 failed, error code= " + iLastErr; //登录失败,输出错误号\     
                Debug.Log(str);
                // showMesText.text += str;
                return;
            }
            else
            {
    
    
                Debug.Log("m_lUserID:" + m_lUserID);
                //登录成功         
                Debug.Log("登陆成功!");
                // showMesText.text += "登陆成功!";
            }
        }
        else
        {
    
    
            //注销登录 Logout the device                
            if (!HCNetSDK.NET_DVR_Logout(m_lUserID))
            {
    
    
                iLastErr = HCNetSDK.NET_DVR_GetLastError();
                str = "NET_DVR_Logout failed, error code= " + iLastErr;
                Debug.LogWarning(str);
                return;
            }
            m_lUserID = -1;          

        }



    }

    private void cbLoginCallBack(int lUserID, uint dwResult, ref HCNetSDK.NET_DVR_DEVICEINFO_V30 lpDeviceInfo, IntPtr pUser)
    {
    
    
        string strLoginCallBack = "登录设备,lUserID:" + lUserID + ",dwResult:" + dwResult;
        Debug.Log("cbLoginCallBack:" + strLoginCallBack);
        //  showMesText.text += strLoginCallBack;
    }
  
    private void OnApplicationQuit()
    {
    
    
        Debug.Log("用户注销...");
        HCNetSDK.NET_DVR_Logout(m_lUserID);
        m_lUserID = -1;
        Debug.Log("SDK资源卸载...");
        HCNetSDK.NET_DVR_Cleanup();
       
    }

詳細については、Hikvision が提供するインターフェイス テキストを確認してください。
ここに画像の説明を挿入
参考記事: Unity3d C# が Hikvision カメラ SDK に接続してインターフェイス制御機能を実現します (例: PTZ の制御) 著者: Shiyaobujin

おすすめ

転載: blog.csdn.net/quailchivalrous/article/details/131323262