海康视频流获取技术总结

作者: Jay_Guo | 来源:发表于2017-09-21 10:43 被阅读268次

    海康监控设备在国内相关领域占有很大的份额,至少目前我接触到的项目或公司都是使用海康设备进行监控的。所以本文主要针对海康设备来进行视频流的获取。

    视频流

    1 概念说明

    硬盘录像机:海康产品的硬盘录像机分为DVR、NVR和CVR三种,DVR是模拟机和同轴缆信号的硬盘录像机,不需要配置IP;NVR是网络型录像机,必须配置IP;CVR是更高级的NVR或者DVR,数据集中存储的NVR(预研用硬盘录像机为CVR)。

    2 技术实现

    技术实现

    海康监控设备视频流获取技术以上技术路线图所示,首先初始化SDK,其次设置连接超时时间、重连时间与异常消息回调函数;接着通过提供硬盘录像机IP、账号、密码、端口号等信息进行登录;然后通过设置播放句柄、通道、流类型、连接方式、是否阻塞等播放信息来进行播放,同时通过设置播放回调函数来获取实时视频流;之后通过软解码技术将视频流逐帧解码为YU12格式,然后编写算法将YU12格式数据转换为RGBA数据,从而完成整个过程的操作。

    3 示例代码

    该技术用到的海康SDK包括HCNetSDK.lib、HCNetSDK.dll、PlayCtrl.lib、PlayCtr.dll,并使用opencv进行视频的试试显示。具体示例代码如下所示:

    #include "Windows.h"
    #include "HCNetSDK.h"
    #include <stdio.h>
    #include <time.h>
    #include "plaympeg4.h"
    #include "opencv/cv.h"
    #include "opencv2/photo.hpp"
    #include "opencv2/imgproc.hpp"
    #include "opencv2/highgui.hpp"
    
    
    
    
    void CALLBACK g_ExceptionCallBack(DWORD dwType, LONG IUserID, LONG IHandle, void *pUser)
    {
        char tempbuf[256] = {};
        switch (dwType)
        {
    
        case EXCEPTION_RECONNECT:
            printf("--------reconnect-------%d\n", time(NULL));
            break;
        default:
            break;
        }
    }
    
    bool YV12_to_RGB32(unsigned char* pYV12, unsigned char* pRGB32, int iWidth, int iHeight)
    {
        if (!pYV12 || !pRGB32)
            return false;
    
        const long nYLen = long(iHeight * iWidth);
        const int nHfWidth = (iWidth >> 1);
    
        if (nYLen < 1 || nHfWidth < 1)
            return false;
    
        unsigned char* yData = pYV12;
        unsigned char* vData = pYV12 + iWidth*iHeight + (iHeight / 2)*(iWidth / 2);//&vData[nYLen >> 2];  
        unsigned char* uData = pYV12 + iWidth*iHeight;// &yData[nYLen];  
        if (!uData || !vData)
            return false;
    
        int rgb[4];
        int jCol, iRow;
        for (iRow = 0; iRow < iHeight; iRow++)
        {
            for (jCol = 0; jCol < iWidth; jCol++)
            {
                rgb[3] = 1;
    
                int Y = yData[iRow*iWidth + jCol];
                int U = uData[(iRow / 2)*(iWidth / 2) + (jCol / 2)];
                int V = vData[(iRow / 2)*(iWidth / 2) + (jCol / 2)];
                int R = Y + (U - 128) + (((U - 128) * 103) >> 8);
                int G = Y - (((V - 128) * 88) >> 8) - (((U - 128) * 183) >> 8);
                int B = Y + (V - 128) + (((V - 128) * 198) >> 8);
    
                // r分量值   
                R = R < 0 ? 0 : R;
                rgb[2] = R > 255 ? 255 : R;
                // g分量值  
                G = G < 0 ? 0 : G;
                rgb[1] = G > 255 ? 255 : G;
                // b分量值   
                B = B < 0 ? 0 : B;
                rgb[0] = B > 255 ? 255 : B;
                pRGB32[4 * (iRow*iWidth + jCol) + 0] = rgb[0];
                pRGB32[4 * (iRow*iWidth + jCol) + 1] = rgb[1];
                pRGB32[4 * (iRow*iWidth + jCol) + 2] = rgb[2];
                pRGB32[4 * (iRow*iWidth + jCol) + 3] = rgb[3];
            }
        }
    
        return true;
    }
    
    void CALLBACK g_DecCBFun(long nPort, char* pBuf, long nSize, FRAME_INFO* pFrameInfo, long nReserved1, long nReserved2)
    {
        long lFrameType = pFrameInfo->nType;
        if (lFrameType == T_AUDIO16)
        {
            //printf("Audio nStap:%d\n", pFrameInfo->nStamp);
        }
        else if (lFrameType == T_YV12)
        {
        
        
            char* rgba = new char[pFrameInfo->nHeight * pFrameInfo->nWidth * 4];
    
            //  YV12_to_RGB24((unsigned char*)pBuf, (unsigned char*)rgb, pFrameInfo->nWidth, pFrameInfo->nHeight);
            YV12_to_RGB32((unsigned char*)pBuf, (unsigned char*)rgba, pFrameInfo->nWidth, pFrameInfo->nHeight);
    
            cv::Mat img(pFrameInfo->nHeight,pFrameInfo->nWidth,CV_8UC4,rgba);
            cv::resize(img, img, cv::Size(img.size().width*0.5, img.size().height*0.5));
            cv::imshow("video", img);
            cv::waitKey(1);
        
        }
    }
    
    LONG nPort = -1;
    
    void CALLBACK g_RealDataCallBack(LONG IRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void* pUser)
    {
        DWORD dRet = 0;
        BOOL inData = FALSE;
    
        switch (dwDataType)
        {
        case NET_DVR_SYSHEAD:
            if (!PlayM4_GetPort(&nPort))
            {
                break;
            }
    
            if (!PlayM4_OpenStream(nPort,pBuffer,dwBufSize,1024*1024))
            {
                dRet = PlayM4_GetLastError(nPort);
                break;
            }
    
            if (!PlayM4_SetDecCallBack(nPort,g_DecCBFun))
            {
                dRet = PlayM4_GetLastError(nPort);
                break;
            }
    
            if (!PlayM4_Play(nPort,NULL))
            {
                dRet = PlayM4_GetLastError(nPort);
                break;
            }
        case NET_DVR_STREAMDATA:
            if (dwBufSize > 0 && nPort != -1)
            {
                inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
                while (!inData)
                {
                    Sleep(10);
                    inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
                    printf("PlayM4_InputData faild %d\n",PlayM4_GetLastError(nPort));
    
                }
            }
            break;
        default:
            inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
            while (!inData)
            {
                Sleep(10);
                inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);
                OutputDebugString("PlayM4_InputData failed 2\n");
            }
            break;
        }
    }
    
    void main()
    {
        //init sdk
        NET_DVR_Init();
    
        //set reconnect time
        NET_DVR_SetConnectTime(2000, 1);
        NET_DVR_SetReconnect(10000, true);
    
    
    
        //set recall func
        NET_DVR_SetExceptionCallBack_V30(0, NULL, g_ExceptionCallBack, NULL);
    
        //get console handler
    
    
        //register device
        LONG IUserID;
        NET_DVR_USER_LOGIN_INFO struLoginInfo = { 0 };
        NET_DVR_DEVICEINFO_V40 struDeviceInfo = { 0 };
    
        strcpy_s((char*)struLoginInfo.sDeviceAddress, sizeof(struLoginInfo.sDeviceAddress), "192.168.3.62");
        strcpy_s((char*)struLoginInfo.sUserName,sizeof(struLoginInfo.sUserName), "admin");
        strcpy_s((char*)struLoginInfo.sPassword,sizeof(struLoginInfo.sPassword), "abcd-1234");
        struLoginInfo.wPort = 8000;
        struLoginInfo.bUseAsynLogin = 0;
    
        IUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfo);
        if (IUserID < 0)
        {
            printf("login failed, error code:%d\n", NET_DVR_GetLastError());
            NET_DVR_Cleanup();
            return;
        }
    
    //  printf("channel num:%d\n", struDeviceInfo.struDeviceV30.byChanNum);
    //  printf("start channel:%d\n", struDeviceInfo.struDeviceV30.byStartChan);
        NET_DVR_IPPARACFG_V40 IpAccessCfg;
        memset(&IpAccessCfg, 0, sizeof(IpAccessCfg));
        DWORD  dwReturned;
    
        if (!NET_DVR_GetDVRConfig(IUserID, NET_DVR_GET_IPPARACFG_V40, 0, &IpAccessCfg, sizeof(NET_DVR_IPPARACFG_V40), &dwReturned))
        {
            return;
        }
        LONG channel;
        for (int i = 0; i < MAX_IP_CHANNEL; ++i)
        {
            if (IpAccessCfg.struStreamMode[i].uGetStream.struChanInfo.byEnable)
            {
                channel = i + IpAccessCfg.dwStartDChan;
                break;
            }
        }
    
    
    
        //display
        LONG IRealPlayHandle;
    
        NET_DVR_PREVIEWINFO struPlayInfo = { 0 };
        struPlayInfo.hPlayWnd = NULL;
        struPlayInfo.lChannel = channel;
        struPlayInfo.dwStreamType = 0;
        struPlayInfo.dwLinkMode = 0;
        struPlayInfo.bBlocked = 1;
    
    
        //
    //  NET_DVR_CLIENTINFO ClientInfo;
    //  ClientInfo.hPlayWnd = hWnd;
    //  ClientInfo.lChannel = 0;
    //  ClientInfo.lLinkMode = 0;
    //  ClientInfo.sMultiCastIP = NULL;
    //  //TRACE("Channel number:%d\n", ClientInfo.lChannel);
    //  IRealPlayHandle = NET_DVR_RealPlay_V30(IUserID, &ClientInfo, NULL, NULL, TRUE);
    
        IRealPlayHandle = NET_DVR_RealPlay_V40(IUserID, &struPlayInfo, g_RealDataCallBack, NULL);
        if (IRealPlayHandle<0)
        {
            printf("play failed, error code:%d\n", NET_DVR_GetLastError());
            NET_DVR_Logout(IUserID);
            NET_DVR_Cleanup();
            return;
        }
    
        Sleep(10000000000000000);
    
        //close display
        NET_DVR_StopRealPlay(IRealPlayHandle);
        //logout
        NET_DVR_Logout(IUserID);
        //release
        NET_DVR_Cleanup();
        return;
    
    }

    相关文章

      网友评论

        本文标题:海康视频流获取技术总结

        本文链接:https://www.haomeiwen.com/subject/hqczsxtx.html