Unity接入海康威视SDK(适用于Windows,Android)

从海康威视官网下载对应系统的设备网络SDK:海康开放平台

将下载好的DLL导入到Unity工程中Plugins文件内,如下

注:如果有重复DLL文件,删除即可;安卓环境需要在Plugins下创建Android文件,在导入

再把案例中的CHCNetSDK.cs脚本导入到Unity内

新建脚本HIKCamera,找个对象挂载,调用OpenCamera方法,输入摄像头IP,账号和密码

using PreviewDemo;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using UnityEngine;

public class HIKCamera : MonoBehaviour
{
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_GetPort(ref int nPort);
    [DllImport("PlayCtrl")]
    public static extern uint PlayM4_GetLastError(int nPort);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_SetStreamOpenMode(int nPort, uint nMode);
    //Stream type
    public const int STREAME_REALTIME = 0;
    public const int STREAME_FILE = 1;
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_OpenStream(int nPort, IntPtr pFileHeadBuf, uint nSize, uint nBufPoolSize);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_SetDisplayBuf(int nPort, uint nNum);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_SetOverlayMode(int nPort, int bOverlay, uint colorKey);
    public delegate void DECCBFUN(int nPort, IntPtr pBuf, int nSize, ref Frame_Info pFrameInfo, int nReserved1, int nReserved2);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_SetDecCallBackEx(int nPort, DECCBFUN DecCBFun, IntPtr pDest, int nDestSize);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_Play(int nPort, IntPtr hWnd);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_InputData(int nPort, IntPtr pBuf, uint nSize);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_SetDecCallBack(int nPort, DECCBFUN DecCBFun);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_Stop(int nPort);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_CloseStream(int nPort);
    [DllImport("PlayCtrl")]
    public static extern bool PlayM4_FreePort(int nPort);

    private uint iLastErr = 0;//错误码
    public CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo;//设备信息
    private Int32 m_lUserID = -1;//登录句柄,未登录值为-1
    //RealPlay 返回句柄参数,-1代表实时播放失败。
    private int realHandle = -1;
    private CHCNetSDK.REALDATACALLBACK RealData; //或许可以移到方法内
    private IntPtr m_ptrRealHandle;//CHCNetSDK.NET_DVR_SYSHEAD模式下,解码需要一个句柄
    private DECCBFUN m_fDisplayFun = null;//解码的委托,用于提供回调函数
    int width = 1920;//视屏的宽
    int height = 1080;//视屏的高
    private byte[] VideoData;//YUV格式的视频数据
    [NonSerialized]
    public bool isDataGet = false;//是否获取了一帧
    public Material VideoMaterial;//RawImage使用的材质
    private Int32 m_lPort = -1;
    Texture2D texY, texU, texV;

    private void Start()
    {
        OpenCamera("192.168.5.100", "admin", "123456");
        //OpenCamera("192.168.5.40", "admin", "aa123456");
    }
    private void Update()
    {
        if (isDataGet)
        {
            ReadFrames(width, height, VideoData);
            isDataGet = false;
        }
    }
    void OnDestroy()
    {

        isDataGet = false;
        CloseVideo();
        LogOut();
        print("NVR" + CHCNetSDK.NET_DVR_Cleanup());
        Debug.Log("Quit Success! " + transform.name);
    }


    public void OpenCamera(string ip, string userName, string passWord)//打开摄像头
    {
        if (InitSDK())
        {
            Login(ip, userName, passWord);
        }
    }
    //初始化SDK
    public bool InitSDK()
    {
        bool m_bInitSDK = CHCNetSDK.NET_DVR_Init();
        if (m_bInitSDK == false)
        {
            Debug.Log("初始化失败");
        }
        else
        {
            Debug.Log("初始化成功"); 
        }
        return m_bInitSDK;
    }

    //登录(初始化->登录->获取视屏流)
    public void Login(string Ip, string UserName, string PassWord)
    {
        if (m_lUserID < 0)
        {
            //登录设备
            m_lUserID = CHCNetSDK.NET_DVR_Login_V30(Ip, 8000, UserName, PassWord, ref DeviceInfo);
            if (m_lUserID < 0)
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                Debug.Log("登录失败:错误号+" + iLastErr);
                return;
            }
            else
            {
                Debug.Log("登录成功");
                Play();
            }
        }
    }
    // 登出
    public void LogOut()
    {
        //注销登录 Logout the device
        if (realHandle >= 0)
        {
            Debug.Log("Please stop live view firstly"); //登出前先停止预览 Stop live view before logout
            CloseVideo();
            //return;
        }
        if (!CHCNetSDK.NET_DVR_Logout(m_lUserID))
        {
            iLastErr = CHCNetSDK.NET_DVR_GetLastError();
            Debug.Log("NET_DVR_Logout failed, error code= " + iLastErr);
            return;
        }
        Debug.Log("NET_DVR_Logout success!");
        m_lUserID = -1;
    }

    //开始播放
    public void Play()
    {
        if (m_lUserID < 0)
        {
            Debug.Log("Please login the device firstly!");
            return;
        }

        CHCNetSDK.NET_DVR_PREVIEWINFO previewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
        previewInfo.hPlayWnd = IntPtr.Zero;//如果使用一个窗口播放,这里可以给一个窗口的句柄,但unity本身是一个窗口,不行,所以给空
        previewInfo.lChannel = 1;
        previewInfo.dwStreamType = 0;//码流 0-主  1-子
        previewInfo.dwLinkMode = 0;
        previewInfo.bBlocked = true;
        previewInfo.dwDisplayBufNum = 15;
        RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);
        realHandle = CHCNetSDK.NET_DVR_RealPlay_V40((int)m_lUserID, ref previewInfo, RealData, IntPtr.Zero);
        if (realHandle < 0)
        {
            iLastErr = CHCNetSDK.NET_DVR_GetLastError();
            Debug.Log("预览失败" + iLastErr);
        }
        else
        {
            Debug.Log("实时预览成功");
        }
    }
    //处理视频数据
    private UInt32 dwBufSizes;
    private IntPtr pBuffers;
    //拉取到视频后,解码视频数据
    private void RealDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser)
    {
        dwBufSizes = dwBufSize;
        pBuffers = pBuffer;
        switch (dwDataType)
        {
            case CHCNetSDK.NET_DVR_SYSHEAD:     // sys head
                //Debug.Log("NET_DVR_SYSHEAD!");
                if (dwBufSize > 0)
                {
                    if (m_lPort >= 0)
                    {
                        return; //同一路码流不需要多次调用开流接口
                    }
                    //获取播放句柄 Get the port to play
                    if (!PlayM4_GetPort(ref m_lPort))
                    {
                        iLastErr = PlayM4_GetLastError(m_lPort);
                        Debug.Log("PlayM4_GetPort failed, error code= " + iLastErr);
                        break;
                    }
                    //设置流播放模式 Set the stream mode: real-time stream mode
                    if (!PlayM4_SetStreamOpenMode(m_lPort, STREAME_REALTIME))
                    {
                        iLastErr = PlayM4_GetLastError(m_lPort);
                        Debug.Log("Set STREAME_REALTIME mode failed, error code= " + iLastErr);
                    }
                    //打开码流,送入头数据 Open stream
                    if (!PlayM4_OpenStream(m_lPort, pBuffer, dwBufSize, 2 * 1024 * 1024))
                    {
                        iLastErr = PlayM4_GetLastError(m_lPort);
                        Debug.Log("PlayM4_OpenStream failed, error code= " + iLastErr);
                        break;
                    }

                    //设置显示缓冲区个数 Set the display buffer number
                    if (!PlayM4_SetDisplayBuf(m_lPort, 15))
                    {
                        iLastErr = PlayM4_GetLastError(m_lPort);
                        Debug.Log("PlayM4_SetDisplayBuf failed, error code= " + iLastErr);
                    }
                    //设置显示模式 Set the display mode
                    //if (!PlayM4_SetOverlayMode(m_lPort, 0, 0/* COLORREF(0)*/)) //play off screen 
                    //{
                    //    iLastErr = PlayM4_GetLastError(m_lPort);
                    //    Debug.Log("PlayM4_SetOverlayMode failed, error code= " + iLastErr);
                    //}
                    //设置解码回调函数,获取解码后音视频原始数据 Set callback function of decoded data
                    m_fDisplayFun = new DECCBFUN(DecCallbackFUN);
                    if (!PlayM4_SetDecCallBack(m_lPort, m_fDisplayFun))
                    {
                        Debug.Log("PlayM4 CallBack Failed!");
                    }
                    //开始解码 Start to play                       
                    if (!PlayM4_Play(m_lPort, m_ptrRealHandle))
                    {
                        iLastErr = PlayM4_GetLastError(m_lPort);
                        Debug.Log("PlayM4_Play failed, error code= " + iLastErr);
                        break;
                    }
                }
                break;
            case CHCNetSDK.NET_DVR_STREAMDATA:     // video stream data
                //Debug.Log("GetStreamData!");
                if (dwBufSizes > 0 && m_lPort != -1)
                {
                    for (int i = 0; i < 999; i++)
                    {
                        //送入码流数据进行解码 Input the stream data to decode
                        if (!PlayM4_InputData(m_lPort, pBuffers, dwBufSizes))
                        {
                            iLastErr = PlayM4_GetLastError(m_lPort);
                            Debug.Log("PlayM4_InputData failed, error code= " + iLastErr);
                            Thread.Sleep(2);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                break;
            default:
                //Debug.Log("GetOtherData!");
                if (dwBufSizes > 0 && m_lPort != -1)
                {
                    //送入其他数据 Input the other data
                    for (int i = 0; i < 999; i++)
                    {
                        if (!PlayM4_InputData(m_lPort, pBuffers, dwBufSizes))
                        {
                            iLastErr = PlayM4_GetLastError(m_lPort);
                            Debug.Log("PlayM4_InputData failed, error code= " + iLastErr);
                            Thread.Sleep(2);
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                break;
        }
    }
    // 解码后视屏回调(视频流为YUV格式)
    private void DecCallbackFUN(int nPort, IntPtr pBuf, int nSize, ref Frame_Info pFrameInfo, int nReserved1, int nReserved2)
    {
        if (pFrameInfo.nType == 3) //#define T_YV12 3
        {
            width = pFrameInfo.nWidth;
            height = pFrameInfo.nHeight;

            VideoData = new byte[nSize];
            Marshal.Copy(pBuf, VideoData, 0, nSize);
            isDataGet = true; //因为回调是异步的,不能直接在这里处理图像
        }
    }

    //分离YUV,组成图片
    private void ReadFrames(int Width, int Height, byte[] data)
    {
        if (data.Length > 0)
        {
            byte[] dataY = new byte[Width * Height];
            byte[] dataU = new byte[Width * Height / 4];
            byte[] dataV = new byte[Width * Height / 4];
            Buffer.BlockCopy(data, 0, dataY, 0, Width * Height);
            Buffer.BlockCopy(data, Width * Height, dataU, 0, Width * Height / 4);
            Buffer.BlockCopy(data, Width * Height * 5 / 4, dataV, 0, Width * Height / 4);
            CreateTexture(Width, Height, dataY, dataU, dataV);
        }
    }

    //通过YUV数据创建图片
    private void CreateTexture(int width, int height, byte[] dataY, byte[] dataU, byte[] dataV)
    {
        //Y  
        if (texY == null)
        { 
          texY =  new Texture2D(width, height, TextureFormat.Alpha8, false);
        }
        texY.LoadRawTextureData(dataY);
        texY.Apply();

        //U  
        if (texU == null)
        { 
            texU = new Texture2D(width / 2, height / 2, TextureFormat.Alpha8, false);
        }
        texU.LoadRawTextureData(dataU);
        texU.Apply();
        //V  
        if (texV == null)
        { 
            texV = new Texture2D(width / 2, height / 2, TextureFormat.Alpha8, false);
        }
        texV.LoadRawTextureData(dataV);
        texV.Apply();

        VideoMaterial.SetTexture("_MainTex", texY);
        VideoMaterial.SetTexture("_MainTexU", texU);
        VideoMaterial.SetTexture("_MainTexV", texV);
    }

    // 停止视屏预览
    public void CloseVideo()
    {
        //停止预览 Stop live view 
        if (!CHCNetSDK.NET_DVR_StopRealPlay(realHandle))
        {
            iLastErr = CHCNetSDK.NET_DVR_GetLastError();
            Debug.Log("NET_DVR_StopRealPlay failed, error code= " + iLastErr + "\n" + realHandle);
            return;
        }
        if ((m_lPort >= 0))
        {
            if (!PlayM4_Stop(m_lPort))
            {
                iLastErr = PlayM4_GetLastError(m_lPort);
                Debug.Log("PlayM4_Stop failed, error code= " + iLastErr);
            }
            if (!PlayM4_CloseStream(m_lPort))
            {
                iLastErr = PlayM4_GetLastError(m_lPort);
                Debug.Log("PlayM4_CloseStream failed, error code= " + iLastErr);
            }
            if (!PlayM4_FreePort(m_lPort))
            {
                iLastErr = PlayM4_GetLastError(m_lPort);
                Debug.Log("PlayM4_FreePort failed, error code= " + iLastErr);
            }
            m_lPort = -1;
        }
        Debug.Log("NET_DVR_StopRealPlay succ!");
        realHandle = -1;
        isDataGet = false;
    }
}


public struct Frame_Info
{
    public int nWidth;
    public int nHeight;
    public int nStamp;
    public int nType;
    public int nFrameRate;
    public uint dwFrameNum;
    public void Init()
    {
        nWidth = 0;
        nHeight = 0;
        nStamp = 0;
        nType = 0;
        nFrameRate = 0;
        dwFrameNum = 0;
    }
}

SDK获取到的视频流是YUV格式,此时需要一个Shder转成Unity支持显示的格式,新建一个材质球,选择Shader并挂载在RwaImage或者网格模型(如:Plane,Quad)中,同时在把这个材质球设置到HIK脚本中

注:此Shader不支持URP

所需shader和材质球资源已上传

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值