众所周知,大华网络摄像头没有直接提供相应的ROS驱动包,所以我们理论上有两个办法在C++中获取网络摄像头图像:
一是通过OpenCV(FFmpeg)的videocapture类去抓取图像;
二是通过大华官方提供的SDK,自己封装一个抓图工具类。
这里主要讲述第二种方法。
大华SDK下载地址
supporthttps://support.dahuatech.com/tools/sdkExploit/24
1、先搞一个放数据结构的类
#ifndef USERDEFINE_H
#define USERDEFINE_H
#include "dhnetsdk.h"
#include "dhconfigsdk.h"
#include
#include
typedef struct
{
LLONG lRealPlayHandle;
unsigned long dwStatistic;
} DH_Channel_Info;
typedef struct
{
LLONG lLoginHandle;
int nChannelCount;
char szDevIp[32];
int nPort;
char szUserName[32];
char szPassWord[32];
DH_Channel_Info channel[16];
} DH_Device_Info;
typedef std::list DEVICE_LIST;
extern DEVICE_LIST g_DeviceList;
typedef std::vector ONE_IMAGE_BUFFER;
extern ONE_IMAGE_BUFFER g_ImageBuffer;
extern bool g_SnapSuccFlag;
#endif
2、再搞一个接口类,用来封装SDK的API
#include "UserDefine.h"
#include
#include
#include
#include
#include
#include
#include
3、再来看一下类的具体实现吧
#include "DHCamera.h"
DEVICE_LIST g_DeviceList;
ONE_IMAGE_BUFFER g_ImageBuffer;
bool g_SnapSuccFlag = false;
static bool g_bNetSDKInitFlag = false;
static short g_nCmdSerial = 0;
void CALLBACK DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser)
{
DHCamera* pThis = (DHCamera *)dwUser;
if(NULL == pThis)
{
return;
}
printf("Call DisConnectFunc\n");
printf("lLoginID[0x%x]", lLoginID);
if (NULL != pchDVRIP)
{
printf("pchDVRIP[%s]\n", pchDVRIP);
}
printf("nDVRPort[%d]\n", nDVRPort);
printf("dwUser[%p]\n", dwUser);
printf("\n");
return;
}
void CALLBACK HaveReConnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, LDWORD dwUser)
{
printf("Call HaveReConnect\n");
printf("lLoginID[0x%x]", lLoginID);
if (NULL != pchDVRIP)
{
printf("pchDVRIP[%s]\n", pchDVRIP);
}
printf("nDVRPort[%d]\n", nDVRPort);
printf("dwUser[%p]\n", dwUser);
printf("\n");
}
void CALLBACK SnapRev(LLONG lLoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser)
{
std::vector current_frame(pBuf, pBuf+RevLen);
g_ImageBuffer.swap(current_frame);
g_SnapSuccFlag = true;
}
DHCamera::DHCamera()
{
}
DHCamera::~DHCamera()
{
DEVICE_LIST::iterator it = g_DeviceList.begin();
while (it != g_DeviceList.end())
{
DH_Device_Info *pDeviceInfo = (*it);
if (pDeviceInfo != nullptr)
{
delete pDeviceInfo;
pDeviceInfo = nullptr;
}
it++;
}
g_DeviceList.clear();
}
bool DHCamera::initSDKClient()
{
g_bNetSDKInitFlag = CLIENT_Init(DisConnectFunc, (LDWORD)this);
CLIENT_SetAutoReconnect(HaveReConnect, 0);
return g_bNetSDKInitFlag;
}
void DHCamera::initDeviceInfo(DH_Device_Info &stDeviceInfo)
{
stDeviceInfo.lLoginHandle = 0UL;
stDeviceInfo.nChannelCount = 0;
stDeviceInfo.nPort = 0;
memset(&stDeviceInfo.szDevIp , 0 , sizeof(stDeviceInfo.szDevIp));
memset(&stDeviceInfo.szUserName , 0 , sizeof(stDeviceInfo.szUserName));
memset(&stDeviceInfo.szPassWord , 0 , sizeof(stDeviceInfo.szPassWord));
memset(&stDeviceInfo.channel , 0 , sizeof(stDeviceInfo.channel));
}
void DHCamera::loadDeviceInfo()
{
DEVICE_LIST::iterator it = g_DeviceList.begin();
while (it != g_DeviceList.end())
{
DH_Device_Info *pDeviceInfo = (*it);
if (pDeviceInfo != nullptr)
{
delete pDeviceInfo;
pDeviceInfo = nullptr;
}
it++;
}
g_DeviceList.clear();
int start_ip = 150;
int connect_num = 12;
int port = 37777;
for(int i = start_ip; i < (start_ip + connect_num); i++)
{
DH_Device_Info* device_info = new DH_Device_Info;
initDeviceInfo(*device_info);
std::string ip = "192.168.1.";
strncpy(device_info->szDevIp, (ip+std::to_string(i)).c_str(), sizeof(device_info->szDevIp)-1);
device_info->nPort = port;
strncpy(device_info->szUserName, "admin", sizeof(device_info->szUserName)-1);
strncpy(device_info->szPassWord, "admin123", sizeof(device_info->szPassWord)-1);
g_DeviceList.push_back(device_info);
}
printf("Init Dev's Num : %d\n", g_DeviceList.size());
}
void DHCamera::loginDev()
{
DEVICE_LIST::iterator it = g_DeviceList.begin();
while(it != g_DeviceList.end())
{
DH_Device_Info *pDeviceInfo = (*it);
if(pDeviceInfo == NULL)
{
it++;
continue;
}
NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stInparam;
memset(&stInparam, 0, sizeof(stInparam));
stInparam.dwSize = sizeof(stInparam);
strncpy(stInparam.szIP, pDeviceInfo->szDevIp, sizeof(stInparam.szIP) - 1);
strncpy(stInparam.szPassword, pDeviceInfo->szPassWord, sizeof(stInparam.szPassword) - 1);
strncpy(stInparam.szUserName, pDeviceInfo->szUserName, sizeof(stInparam.szUserName) - 1);
stInparam.nPort = pDeviceInfo->nPort;
stInparam.emSpecCap = EM_LOGIN_SPEC_CAP_TCP;
NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stOutparam;
memset(&stOutparam, 0, sizeof(stOutparam));
stOutparam.dwSize = sizeof(stOutparam);
pDeviceInfo->lLoginHandle = CLIENT_LoginWithHighLevelSecurity(&stInparam, &stOutparam);
if(pDeviceInfo->lLoginHandle != 0)
{
devHandles_map.emplace(pDeviceInfo->szDevIp, pDeviceInfo->lLoginHandle);
printf("CLIENT_LoginWithHighLevelSecurity %s[%d] Success\n" , pDeviceInfo->szDevIp , pDeviceInfo->nPort);
usleep(500000);
}
else {
printf("Failed to login IP[%s]\n", pDeviceInfo->szDevIp);
}
}
}
void DHCamera::logoutDev()
{
DEVICE_LIST::iterator it = g_DeviceList.begin();
while(it != g_DeviceList.end())
{
if((*it)->lLoginHandle != 0)
{
CLIENT_Logout((*it)->lLoginHandle);
}
}
if (TRUE == g_bNetSDKInitFlag)
{
CLIENT_Cleanup();
g_bNetSDKInitFlag = FALSE;
}
}
void DHCamera::grabCamImage(long loginHandle)
{
if (0 == loginHandle)
{
return;
}
// 设置抓图回调函数
CLIENT_SetSnapRevCallBack(SnapRev, NULL);
//事例中默认通道 ID 为 0、抓图模式为抓一幅图,用户可根据实际情况自行选择
int nChannelId = 0;
int nSnapType = 0; // 抓图模式;-1:表示停止抓图, 0:表示请求一帧, 1:表示定时发送请求, 2:表示连续请求
// 发送抓图命令给前端设备
SNAP_PARAMS stuSnapParams;
stuSnapParams.Channel = nChannelId;
stuSnapParams.mode = nSnapType;
stuSnapParams.CmdSerial = ++g_nCmdSerial; // 请求序列号,有效值范围 0~65535,超过范围会被截断为 unsigned short
if (FALSE == CLIENT_SnapPictureEx(loginHandle, &stuSnapParams))
{
printf("CLIENT_SnapPictureEx Failed!Last Error[%x]\n", CLIENT_GetLastError());
return;
}
else
{
printf("CLIENT_SnapPictureEx succ\n");
}
}
如果这篇博客对你有帮助,就点个赞呗!