涸彝酰康監(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)
鹤在澹康監(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;
}