目录
1. 文章背景
项目中需要使用大华的网络摄像头,之前为了图方便,我是通过opencv打开rtsp地址,从而显示和存图,但由于客户后期更换了摄像头,且希望采图效率更高,预估rtsp难以达到,所以考虑从大华官方SDK下手,就有了这篇文章。
2. 主要模块
其实官方的例程已经写得很详细了,不过官方的Demo是用MFC写的,考虑到一些朋友对MFC不是很熟(主要是指我自己 0-0),我就用qt c++写了这部分功能,因为基于QT,所以我的很多代码习惯是qt的,比如实时图像显示的窗体句柄,我是直接取的Qt上的一个QLbel的句柄。
2.1 初始化SDK
初始SDK:CLIENT_Init,就一个接口,没啥好说的。
// 初始化 SDK
g_bNetSDKInitFlag = CLIENT_Init((fDisConnect)DisConnectFunc, 0);
QString logInfo = QSC("SDK初始化%1。").arg(g_bSnapPictureFlag ? QSC("成功") : QSC("失败"));
qDebug() << logInfo;
2.2 登录账号
按摄像头信息登录:CLIENT_LoginWithHighLevelSecurity,这里需要注意的就是把ip,port,用户,密码这些信息按照固定格式存进输入参数结构里,再调相应的接口就好了。
//获取登录信息
strcpy(D_Ip, ip.toLatin1().data());
strcpy(D_UserName, name.toLatin1().data());
strcpy(D_Pasdwd, password.toLatin1().data());
D_Port = port;
strncpy(stInparam.szIP, D_Ip, sizeof(stInparam.szIP) - 1);
strncpy(stInparam.szUserName, D_UserName, sizeof(stInparam.szUserName) - 1);
strncpy(stInparam.szPassword, D_Pasdwd, sizeof(stInparam.szPassword) - 1);
stInparam.nPort = D_Port;
stInparam.emSpecCap = EM_LOGIN_SPEC_CAP_TCP;
// 登录设备
tagNET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stOutparam;
LoginHandle = CLIENT_LoginWithHighLevelSecurity(&stInparam, &stOutparam);
QString logInfo = QSC("设备登录%1:%2 %3。").arg(ip).arg(D_Port).arg(LoginHandle? QSC("成功") : QSC("失败,错误码[%1]").arg(QString::number(CLIENT_GetLastError(), 16)));
qDebug() << logInfo;
2.3 捕获图片
捕获图片要做两个动作:
1. 首先是设置回调函数:CLIENT_SetSnapRevCallBack(回调函数名, NULL); 回调函数的内容在后面我会贴出来。
2. 然后在你想抓图的时候调抓图接口:CLIENT_SnapPictureEx(登录句柄, &stuSnapParams);
// 设置抓图回调函数
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 = 0;//++g_nCmdSerial; // 请求序列号,有效值范围 0~65535,超过范围会被截断为 unsigned short
g_bSnapPictureFlag = CLIENT_SnapPictureEx(LoginHandle, &stuSnapParams);
QString logInfo = QSC("SDK抓图%1。").arg(g_bSnapPictureFlag? QSC("成功") : QSC("失败,错误码[%1]").arg(QString::number(CLIENT_GetLastError(), 16)));
qDebug() << logInfo;
2.4 实时显示
实时显示有两种方式:一是直接在某个窗体句柄下显示;二是存起来,用其他方式解码。
我这里只是为了能实时看到,所以是用了一个QLabel来显示,首先获取这个控件的句柄:winId(),然后在你想看实时图像的时候调实时预览的接口:CLIENT_RealPlayEx(登录句柄, 通道号, 用于显示图像的控件句柄, 也可以不写默认就是实时监视);
// 实现实时监视功能业务
// 获取控制台窗口句柄
// 1.例程中的方法
// HMODULE hKernel32 = GetModuleHandle("kernel32");
// GetConsoleWindow = (PROCGETCONSOLEWINDOW)GetProcAddress(hKernel32,"GetConsoleWindow");
// HWND hWnd = GetConsoleWindow();// NULL;
// 2.获取qt控件的方法
HWND hWnd = (HWND)ui->label_RealDisplay->winId();
//开启实时监视
int nChannelID = 0; // 预览通道号
DH_RealPlayType emRealPlayType = DH_RType_Realplay; // 实时监视
lHandle = CLIENT_RealPlayEx(LoginHandle, nChannelID, hWnd, emRealPlayType);
QString logInfo = QSC("实时显示开启%1。").arg(lHandle ? QSC("成功") : QSC("失败,错误码[%1]").arg(QString::number(CLIENT_GetLastError(), 16)));
qDebug() << logInfo;
2.5 断开时释放
我个人觉得有一个好的习惯是很重要的,就像指针一样,一定要有new 有delete,当然如果你懒得写相应的函数,你也可以把它们写在析构里。
// 关闭预览
if (lHandle)
{
bool lHandleFlag = CLIENT_StopRealPlayEx(lHandle);
QString logInfo = QSC("实时显示关闭%1。").arg(lHandleFlag ? QSC("成功") : QSC("失败,错误码[%1]").arg(QString::number(CLIENT_GetLastError(), 16)));
qDebug() << logInfo;
if(lHandleFlag)
lHandle = false;
}
// 退出设备
if (LoginHandle)
{
bool LoginHandleFlag = CLIENT_Logout(LoginHandle);
QString logInfo = QSC("实时显示关闭%1。").arg(LoginHandleFlag ? QSC("成功") : QSC("失败,错误码[%1]").arg(QString::number(CLIENT_GetLastError(), 16)));
qDebug() << logInfo;
if(LoginHandleFlag)
LoginHandle = false;
}
// 清理初始化资源
if (g_bNetSDKInitFlag)
{
CLIENT_Cleanup();
g_bNetSDKInitFlag = false;
}
2.6 回调函数
能正常显示的前提还需要一些回调函数,断开重连那几个都一样,你如果需要是连了很多个摄像头,可以在回调函数里把一些信息log出来,我这里暂时是连一个,所以就没打印信息,只是打印了一下调用信息。
//断线回调
void CALLBACK MainWidget::DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser)
{
qDebug() << QSC("断线回调\n");
}
//重连回调
void CALLBACK MainWidget::HaveReConnect(LLONG lLoginID,char *pchDVRIP,LONG nDVRPort,LDWORD dwUser)
{
qDebug() << QSC("重连回调\n");
}
抓图回调里面可以设置抓图的路径
//抓图回调
void CALLBACK MainWidget::SnapRev(LLONG lLoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser)
{
qDebug() << QSC("抓图回调\n");
qDebug() << QSC("抓图句柄:") << lLoginID;
// if(lLoginID =&