海康網路攝像機視訊資料的獲取及使用opencv顯示
阿新 • • 發佈:2019-02-02
最近要使用海康威視攝像機獲取資料做處理。主要是藉助Opencv這個工具,所以做了一下步驟。
我用的是基於Qt+opencv的來顯示海康資料的。本人海康的型號為:DS-2CD2820FD
1、海康sdk開發環境的配置(我只給出我的配置路徑,視具體情況而定)
LIBS += -LD:\Softwares\HaiKang\x64\lib\
-lHCNetSDK \
-lGdiPlus \
-lHCCore \
-lPlayCtrl
LIBS += -LD:\Softwares\HaiKang\x64\lib\HCNetSDKCom\
-lHCAlarm \
-lHCGeneralCfgMgr \
-lHCPreview
2、包含的標頭檔案
#include<stdio.h>
#include<iostream>
#include<time.h>
#include<Windows.h>
#include<HCNetSDK.h>
#include<plaympeg4.h>
#include<cstring>
using namespace std;
#include"./opencv2/opencv.hpp"
using namespace cv;
typedef HWND (WINAPI *PROCGETCONSOLEWINDOW)();
PROCGETCONSOLEWINDOW GetConsoleWindowAPI;
3、具體的實現程式碼如下:
LONG nPort=-1; //全域性的播放庫port號
//資料型別轉換
void yv12toYUV(uchar *outYuv, uchar *inYv12, int width, int height,int widthStep)
{
int col,row;
unsigned int Y,U,V;
int tmp;
int idx;
for (row=0; row<height; row++)
{
idx=row * widthStep;
for (col=0; col<width; col++)
{
tmp = (row/2 )*(width/2)+(col/2);
Y=(unsigned int) inYv12[row*width+col];
U=(unsigned int) inYv12[width*height+width*height/4+tmp];
V=(unsigned int) inYv12[width*height+tmp];
outYuv[idx+col*3] = Y;
outYuv[idx+col*3+1] = U;
outYuv[idx+col*3+2] = V;
}
}
}
////解碼回撥 視訊為YUV資料(YV12)
void CALLBACK DecCBFun(long nPort,char * pBuf,long nSize,FRAME_INFO * pFrameInfo, long nReserved1,long nReserved2)
{
long lFrameType = pFrameInfo->nType;
if(lFrameType ==T_YV12)
{
Mat matYCrCb=Mat(pFrameInfo->nHeight, pFrameInfo->nWidth,CV_8UC3);
Mat matImge=Mat(pFrameInfo->nHeight, pFrameInfo->nWidth,CV_8UC3);
yv12toYUV(matYCrCb.data,(uchar*)pBuf,pFrameInfo->nWidth,pFrameInfo->nHeight,matYCrCb.step);
cvtColor(matYCrCb,matImge,CV_YCrCb2RGB);
imshow("matImge IPCamera",matImge);
waitKey(1);//一定記得加不然會出錯
}
}
void CALLBACK g_RealDataCallBack_V30(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer,DWORD dwBufSize,void* dwUser)
{
HWND hWnd=GetConsoleWindowAPI();
DWORD dRet;
switch (dwDataType)
{
case NET_DVR_SYSHEAD: //系統頭
if (!PlayM4_GetPort(&nPort)) //獲取播放庫未使用的通道號
{
break;
}
if(dwBufSize > 0)
{
if (!PlayM4_OpenStream(nPort,pBuffer,dwBufSize,1024*1024))
{
dRet=PlayM4_GetLastError(nPort);
break;
}
//設定解碼回撥函式 只解碼不顯示
if (!PlayM4_SetDecCallBack(nPort,DecCBFun))
{
dRet=PlayM4_GetLastError(nPort);
break;
}
//設定解碼回撥函式 解碼且顯示
//if (!PlayM4_SetDecCallBackEx(nPort,DecCBFun,NULL,NULL))
//{
// dRet=PlayM4_GetLastError(nPort);
// break;
//}
//開啟視訊解碼
if (!PlayM4_Play(nPort,hWnd))
{
dRet=PlayM4_GetLastError(nPort);
break;
}
//開啟音訊解碼, 需要碼流是複合流
if (!PlayM4_PlaySound(nPort))
{
dRet=PlayM4_GetLastError(nPort);
break;
}
}
break;
case NET_DVR_STREAMDATA: //碼流資料
if (dwBufSize > 0 && nPort != -1)
{
BOOL inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
while (!inData)
{
Sleep(10);
inData=PlayM4_InputData(nPort,pBuffer,dwBufSize);
OutputDebugString(L"PlayM4_InputData failed \n");
}
}
break;
}
}
void CALLBACK g_ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
{
char tempbuf[256] = {0};
switch(dwType)
{
case EXCEPTION_RECONNECT: //預覽時重連
printf("----------reconnect--------%d\n", time(NULL));
break;
default:
break;
}
}
void main() {
//---------------------------------------
// 初始化
NET_DVR_Init();
//設定連線時間與重連時間
NET_DVR_SetConnectTime(2000, 1);
NET_DVR_SetReconnect(10000, true);
//---------------------------------------
//設定異常訊息回撥函式
NET_DVR_SetExceptionCallBack_V30(0, NULL,g_ExceptionCallBack, NULL);
//---------------------------------------
// 獲取控制檯視窗控制代碼
HMODULE hKernel32 = GetModuleHandle(L"kernel32");
GetConsoleWindowAPI = (PROCGETCONSOLEWINDOW)GetProcAddress(hKernel32,"GetConsoleWindow");
//---------------------------------------
// 註冊裝置
LONG lUserID;
//登入引數,包括裝置地址、登入使用者、密碼等
NET_DVR_USER_LOGIN_INFO struLoginInfo = {0};
struLoginInfo.bUseAsynLogin = 0; //同步登入方式
strcpy(struLoginInfo.sDeviceAddress, "192.168.10.64"); //裝置IP地址
struLoginInfo.wPort = 8000; //裝置服務埠
strcpy(struLoginInfo.sUserName, "admin"); //裝置登入使用者名稱
strcpy(struLoginInfo.sPassword, "admin123"); //裝置登入密碼
//裝置資訊, 輸出引數
NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = {0};
lUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
if (lUserID < 0)
{
printf("Login failed, error code: %d\n", NET_DVR_GetLastError());
NET_DVR_Cleanup();
return;
}
//---------------------------------------
//啟動預覽並設定回撥資料流
LONG lRealPlayHandle;
NET_DVR_PREVIEWINFO struPlayInfo = {0};
struPlayInfo.hPlayWnd = NULL; //需要SDK解碼時控制代碼設為有效值,僅取流不解碼時可設為空
struPlayInfo.lChannel = 1; //預覽通道號
struPlayInfo.dwStreamType = 0; //0-主碼流,1-子碼流,2-碼流3,3-碼流4,以此類推
struPlayInfo.dwLinkMode = 0; //0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4-RTP/RTSP,5-RSTP/HTTP
struPlayInfo.bBlocked = 1; //0- 非阻塞取流,1- 阻塞取流
lRealPlayHandle = NET_DVR_RealPlay_V40(lUserID, &struPlayInfo, g_RealDataCallBack_V30, NULL);
if (lRealPlayHandle < 0)
{
printf("NET_DVR_RealPlay_V40 error, %d\n", NET_DVR_GetLastError());
NET_DVR_Logout(lUserID);
NET_DVR_Cleanup();
return;
}
Sleep(-1);
//---------------------------------------
//關閉預覽
NET_DVR_StopRealPlay(lRealPlayHandle);
//登出使用者
NET_DVR_Logout(lUserID);
NET_DVR_Cleanup();
return;
}