海康視頻流獲取技術(shù)總結(jié)

涸彝酰康監(jiān)控設備在國內(nèi)相關(guān)領域占有很大的份額推盛,至少目前我接觸到的項目或公司都是使用海康設備進行監(jiān)控的谦铃。所以本文主要針對盒』保康設備來進行視頻流的獲取。

視頻流

1 概念說明

硬盤錄像機:汉稍康產(chǎn)品的硬盤錄像機分為DVR凿跳、NVR和CVR三種疮方,DVR是模擬機和同軸纜信號的硬盤錄像機,不需要配置IP疆栏;NVR是網(wǎng)絡型錄像機惫谤,必須配置IP;CVR是更高級的NVR或者DVR若专,數(shù)據(jù)集中存儲的NVR(預研用硬盤錄像機為CVR)调衰。

2 技術(shù)實現(xiàn)

技術(shù)實現(xiàn)

鹤在澹康監(jiān)控設備視頻流獲取技術(shù)以上技術(shù)路線圖所示沛豌,首先初始化SDK,其次設置連接超時時間、重連時間與異常消息回調(diào)函數(shù)跳芳;接著通過提供硬盤錄像機IP筛严、賬號桨啃、密碼檬输、端口號等信息進行登錄;然后通過設置播放句柄析命、通道鹃愤、流類型完域、連接方式、是否阻塞等播放信息來進行播放凹耙,同時通過設置播放回調(diào)函數(shù)來獲取實時視頻流肖抱;之后通過軟解碼技術(shù)將視頻流逐幀解碼為YU12格式意述,然后編寫算法將YU12格式數(shù)據(jù)轉(zhuǎn)換為RGBA數(shù)據(jù),從而完成整個過程的操作欲险。

3 示例代碼

該技術(shù)用到的海康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;

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末郭变,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诉濒,更是在濱河造成了極大的恐慌未荒,老刑警劉巖撇他,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異划纽,居然都是意外死亡锌畸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門比默,熙熙樓的掌柜王于貴愁眉苦臉地迎上來命咐,“玉大人醋奠,你說我怎么就攤上這事榛臼∨嫔疲” “怎么了金刁?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵尤蛮,是天一觀的道長笙蒙。 經(jīng)常有香客問我捅位,道長,這世上最難降的妖魔是什么尿扯? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任衷笋,我火速辦了婚禮辟宗,結(jié)果婚禮上泊脐,老公的妹妹穿的比我還像新娘。我一直安慰自己容客,他們只是感情好缩挑,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布供置。 她就那樣靜靜地躺著绽快,像睡著了一般悲关。 火紅的嫁衣襯著肌膚如雪娄柳。 梳的紋絲不亂的頭發(fā)上赤拒,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天挎挖,我揣著相機與錄音蕉朵,去河邊找鬼阳掐。 笑死缭保,一個胖子當著我的面吹牛艺骂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播别伏,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼厘肮,長吁一口氣:“原來是場噩夢啊……” “哼轴脐!你這毒婦竟也來了抡砂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厦瓢,沒想到半個月后提揍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劳跃,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年夹姥,在試婚紗的時候發(fā)現(xiàn)自己被綠了杉武。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡辙售,死狀恐怖轻抱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旦部,我是刑警寧澤祈搜,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站志鹃,受9級特大地震影響夭问,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜曹铃,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一缰趋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陕见,春花似錦、人聲如沸灰粮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秽荞。三九已至,卻和暖如春胁住,著一層夾襖步出監(jiān)牢的瞬間娱挨,已是汗流浹背跷坝。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工贴届, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人元潘。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像上沐,于是被迫代替她去往敵國和親龄广。 傳聞我的和親對象是個殘疾皇子择同,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容