根据大华官方的SDK包以及Demo文件(官网可以下载到)实现一些最基本的功能:登陆,注销,实时监视,抓图。先上一下博主自己做的结果图:
本人的环境配置如下:
- 操作系统:Win7 64位
- 开发工具:Visual Studio 2017 ;X86
- 摄像头型号:大华DH-IPC-HFW2233DM-LED
实现流程如下:
- 步骤1 调用SDK包中的相关库文件,完成 SDK 初始化流程,部分代码如下:
#pragma comment(lib , "dhnetsdk.lib")
#pragma comment(lib, "dhconfigsdk.lib")// 也可以在项目路径下添加lib文件,在项目属性中包含目录添加相关路径
// 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK 会调用该函数(必须有)
void __stdcall DisConnectFunc(LONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser){ }
//自动重连回调函数
void __stdcall HaveReConnectFunc(LONG lLoginID, char *pchDVRIP, LONG nDVRPort, DWORD dwUser){ }
//子连接自动重连回调函数
void __stdcall SubHaveReConnectFunc(EM_INTERFACE_TYPE emInterfaceType, BOOL bOnline, LLONG lOperateHandle, LLONG lLoginID, LDWORD dwUser){ }
//SDK初始化
void CRealPlayDlg::InitNetSDK()
{
CLIENT_Init(DisConnectFunc, (LDWORD)this);
//我选择直接在这里设置抓图回调函数
CLIENT_SetSnapRevCallBack(SnapPicRet,(LDWORD)this);
}
- 步骤2 初始化成功后,调用库函数 CLIENT_LoginWithHighLevelSecurity 登录设备。
int g_nPort = 0; // tcp 连接端口,需与期望登录设备页面 tcp 端口配置一致
char g_szUserName[32] = { 0 };//设备用户名
char g_szPasswd[32] = { 0 };//密码
char g_szDevIp[32] = {0};//设备IP
int nChannelID = 0;//预览通道号
void CRealPlayDlg::OnBnClickedLogin()
{
char *pchUserName = (LPSTR)(LPCSTR)g_szUserName;
char *pchPassword = (LPSTR)(LPCSTR)g_szPasswd;
m_nPort = GetDlgItemInt(IDC_EDIT3);
GetDlgItemText(IDC_IPADDRESS1, g_szDevIp, 32);
GetDlgItemText(IDC_EDIT1, pchUserName, 32);
GetDlgItemText(IDC_EDIT2, pchPassword, 32);
NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY stInparam;//登录接口函数输入参数
memset(&stInparam, 0, sizeof(stInparam));// 初始化结构体对象
stInparam.dwSize = sizeof(stInparam);// 结构体大小
// 将设备信息拷贝到登录接口函数输入参数
strncpy(stInparam.szIP, g_szDevIp, sizeof(stInparam.szIP) - 1);
strncpy(stInparam.szPassword, pchPassword, sizeof(stInparam.szPassword) - 1);
strncpy(stInparam.szUserName, pchUserName, sizeof(stInparam.szUserName) - 1);
stInparam.nPort = m_nPort;
stInparam.emSpecCap = EM_LOGIN_SPEC_CAP_TCP;// TCP登陆, 默认方式
NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY stOutparam;//登录接口函数输出参数
memset(&stOutparam, 0, sizeof(stOutparam));// 清空结构体对象
stOutparam.dwSize = sizeof(stOutparam);
//登陆设备
LLONG lRet = CLIENT_LoginWithHighLevelSecurity(&stInparam, &stOutparam);
- 步骤3 登录成功后,调用库函数 CLIENT_RealPlayEx 启动实时监视,参数 hWnd 为有效窗口句柄。并调用 CLIENT_SetSnapRevCallBack 设置抓图回调函数,当 SDK 收到设备端发送过来的抓图数据时,会调用 fSnapRev回调函数回调图片信息及图片数据给用户。
void CRealPlayDlg::OnBnClickedPlay()
{
// 传入有效窗口句柄
HWND play1 = GetDlgItem(IDC_STATIC)->m_hWnd;
//开启实时监视
//int nChannelID = 0; // 预览通道号
DH_RealPlayType emRealPlayType = DH_RType_Realplay; // 实时监视
g_lRealHandle = CLIENT_RealPlayEx(g_lLoginHandle, nChannelID, play1,
emRealPlayType);
}
//抓图回调函数
void CALLBACK SnapPicRet(LLONG ILoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, DWORD CmdSerial, LDWORD dwUser)
{
CRealPlayDlg *pThis = (CRealPlayDlg*)dwUser;
pThis->OnOnePicture(ILoginID, pBuf, RevLen, EncodeType, CmdSerial);
}
- 步骤4 调用 CLIENT_SnapPictureEx 发送抓图命令给前端设备,在 fSnapRev 回调函数中等待设备回复的图片信息。
// 发送抓图命令
void CRealPlayDlg::OnBnClickedcp()
{
// TODO: 在此添加控件通知处理程序代码
// 发送抓图命令给前端设备
UpdateData(TRUE);
SNAP_PARAMS snapParams;
snapParams.Channel = 0;//默认通道 ID 为 0、抓图模式为抓一幅图,用户可根据实际情况自行选择
snapParams.mode = 0;// 抓图模式;-1:表示停止抓图, 0:表示请求一帧, 1:表示定时发送请求, 2:表示连续请求
snapParams.CmdSerial = 0;// 请求序列号,有效值范围 0~65535,超过范围会被截断为 unsigned short
CLIENT_SnapPicture(g_lLoginHandle, snapParams);
}
//抓图保存代码块
void CRealPlayDlg::OnOnePicture(LLONG ILoginID, BYTE *pBuf, UINT RevLen, UINT EncodeType, UINT CmdSerial)
{
//文件保存路径
char path[1000];
int filelen = GetModuleFileName(NULL, path, 1000);//获取程序所在目录,返回32位无符号整数
int i = filelen;
while (path[i] != '\\')
{
i--;
}
path[i + 1] = '\0';
//文件命名
CString filepath(path);
CString filename = "mpeg4.JPG";
CString strfile = filepath + filename;
char *pFileName = strfile.GetBuffer(200);
/* 保存原始图片文件*/
FILE *stream;
if ((stream = fopen((const char*)pFileName, "wb")) != NULL)
{
int numwritten = fwrite(pBuf, sizeof(char), RevLen, stream);
fclose(stream);
}
/*判断图像编码类型。如果是一个I帧的mpeg4,然后调用I帧解码为BMP显示.*/
if (EncodeType == 0)
{
//int iRet = IFrameToBmp("tmp.bmp",pFileName);
//if (iRet == 1)
//{
// ShowBitmap("tmp.bmp");
//}
}
else if (EncodeType == 10)
{
//ShowBitmap(pFileName);
ShowSnapImage(pFileName);
}
}
//抓图展示相关代码
void CRealPlayDlg::ShowSnapImage(LPCSTR szImagePath)
{
USES_CONVERSION;
// 获取展示窗口
CWnd* fullImageWindow = GetDlgItem(IDC_SHOWPICTURE);
if (NULL == fullImageWindow)
{
return;
}
RECT rect;
fullImageWindow->GetWindowRect(&rect);
CDC* pDC = NULL;
pDC = fullImageWindow->GetWindowDC();
if (NULL == pDC)
{
return;
}
// 加载图片
HRESULT hr = S_FALSE;
hr = OleLoadPicturePath(T2OLE(szImagePath), NULL, 0, RESERVED_COLOR, IID_IPicture, (LPVOID*)&m_pPicture);
if (NULL == m_pPicture)
{
fullImageWindow->ReleaseDC(pDC);
return;
}
//显示全图
OLE_XSIZE_HIMETRIC hmWidth;
OLE_YSIZE_HIMETRIC hmHeight;
m_pPicture->get_Width(&hmWidth);
m_pPicture->get_Height(&hmHeight);
hr = m_pPicture->Render(*pDC, 0, 0, rect.right - rect.left, rect.bottom - rect.top, 0, hmHeight, hmWidth, -hmHeight, NULL);
fullImageWindow->ReleaseDC(pDC);
}
- 步骤5 实时监视使用完毕后,调用库函数 CLIENT_StopRealPlayEx 停止实时监视,并调用 CLIENT_Logout 退出设备。
void CRealPlayDlg::OnBnClickedStop()
{
// 停止播放
CLIENT_StopRealPlayEx(g_lRealHandle);
Invalidate();
}
void CRealPlayDlg::OnBnClickedLogout()
{
// 登出设备
if (0 != g_lLoginHandle)
CLIENT_Logout(g_lLoginHandle);
g_lLoginHandle = 0;
}
- 步骤6 SDK 功能使用完后,调用 CLIENT_Cleanup 释放 SDK 资源。
void CRealPlayDlg::OnDestroy()
{
CDialogEx::OnDestroy();
// TODO: 在此处添加消息处理程序代码
CLIENT_Cleanup();
}
以上所展示的代码只是程序中的一个部分,均是基于大华SDK开发手册所写的,相关库函数手册里面都有详细描述,后面我会把车牌识别功能加上去,如果以上有错误还劳烦大佬们指出。