在使用海康sdk进行开发的所有流程都是:
1、 初始化sdk
2、 登录设备
3、 执行具体操作(实时预览、录像回放、录像查询、PTZ控制等操作)
4、 退出设备
5、 销毁sdk
录像回放过程
特别说明:由于sdk长期迭代,所以能看到很多类似的方法,后面跟着 "_Vxxx",例如登录方法有NET_DVR_Login、NET_DVR_Login_V30、NET_DVR_Login_V40,一般我们选用数字更大的方法,支持的功能更全面。
1、初始化sdk
在实际开发中,初始化完成之后,一般都会在初始化完成之后设置超时、重连、日志、异常回调等信息
用到的方法:
NET_DVR_API BOOL __stdcall NET_DVR_Init();
NET_DVR_API BOOL __stdcall NET_DVR_SetConnectTime(DWORD dwWaitTime = 3000, DWORD dwTryTimes = 3);
NET_DVR_API BOOL __stdcall NET_DVR_SetReconnect(DWORD dwInterval = 30000, BOOL bEnableRecon = TRUE);
NET_DVR_API BOOL __stdcall NET_DVR_SetLogToFile(DWORD nLogLevel = 0, char * strLogDir = NULL, BOOL bAutoDel = TRUE);
NET_DVR_API BOOL __stdcall NET_DVR_SetExceptionCallBack_V30(UINT reserved1, void* reserved2, void (CALLBACK* fExceptionCallBack)(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser), void *pUser);
2、登录设备
登录用到的方法NET_DVR_Login_V40,需要提供登录设备的地址、端口、用户名、密码。端口一般情况下是8000。
返回值表示登录句柄,不小于0表示成功,句柄需要保存起来,后续所有的对设备的操作都要用到这个句柄。返回登录成功之后,出参会获取到一些设备信息。
以下是登录示例代码:
NET_DVR_USER_LOGIN_INFO loginInfo;
NET_DVR_DEVICEINFO_V40 deviceInfo;
loginInfo.wPort = 8000;
strcpy(loginInfo.sDeviceAddress, "192.168.1.100");
strcpy(loginInfo.sUserName, "admin");
strcpy(loginInfo.sPassword, "123456");
LONG lUserID = NET_DVR_Login_V40(&loginInfo, &deviceInfo);
if (lRet < 0) {
printf("Login failed, error code: %s\n", NET_DVR_GetLastError());
}
3、录像查找
录像查找分三步:
1、 使用NET_DVR_FindFile_V50方法执行查找操作,成功返回查找句柄。
2、 循环使用NET_DVR_FindNextFile_V50方法通过查找句柄获取查找结果。
NET_DVR_FindNextFile_V50返回值取值:
#define NET_DVR_FILE_SUCCESS 1000 //获得文件信息
#define NET_DVR_FILE_NOFIND 1001 //没有文件
#define NET_DVR_ISFINDING 1002 //正在查找文件
#define NET_DVR_NOMOREFILE 1003 //查找文件时没有更多的文件
#define NET_DVR_FILE_EXCEPTION 1004 //查找文件时异常
#define NET_DVR_FIND_TIMEOUT 1005 //查找文件超时
3、 查找结束使用NET_DVR_FindClose_V30关闭查找句柄。
示例:
//查找条件
NET_DVR_FILECOND_V50 struFileCond;
int lFindHandle = NET_DVR_FindFile_V50(lUserID, &struFileCond);
if (lFindHandle >= 0)
{
//逐个获取查询文件结果
NET_DVR_FINDDATA_V50 struFileData;
while (true)
{
int result = NET_DVR_FindNextFile_V50(lFindHandle, &struFileData);
if (result == NET_DVR_ISFINDING)
{
continue;
}
else if (result == NET_DVR_FILE_SUCCESS)
{
continue;
}
else if (result == NET_DVR_FILE_NOFIND || result == NET_DVR_NOMOREFILE)
{
break;
}
else
{
printf("find file fail for illegal get file state");
break;
}
}
//停止查找,释放资源
NET_DVR_FindClose_V30(lFindHandle);
}
4、播放录像
需要用到的方法:
1、 按时间回放:NET_DVR_PlayBackByTime_V50
2、 设置码流回调:
回调ES流:NET_DVR_SetPlayBackESCallBack
回调封装过的流:NET_DVR_SetPlayDataCallBack_V40
3、 回放控制:NET_DVR_PlayBackControl_V40
示例:
NET_DVR_VOD_PARA_V50 vodPara;
// 按时间回放
int hPlayback = NET_DVR_PlayBackByTime_V50(ptReq->lUserId, &vodPara);
if (hPlayback < 0) {
ErrorL << "NET_DVR_PlayBackByTime_V40 error, " << NET_DVR_GetLastError();
return -1;
}
//(可选)设置ES码流回调,
NET_DVR_SetPlayBackESCallBack(
hPlayback ,
[](LONG lPlayHandle, NET_DVR_PACKET_INFO_EX *pstruPackInfo, void *pUserData) {},
NULL);
//(可选)设置封装码流回调
NET_DVR_SetPlayDataCallBack_V40(
mSdkPlayHandle,
[](LONG lPlayHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser) {},
NULL);
// 开始播放
NET_DVR_PlayBackControl_V40(hPlayback , NET_DVR_PLAYSTART);
特别说明:
调用完回放方法之后,一定需要调用回放控制方法传NET_DVR_PLAYSTART(开始播放命令)才会真正开始播放
4.1、码流回调
如果回放参数填了播放窗口句柄,则画面可以直接在窗口播放,否则需要设置码流回调自己处理码流
码流回调示例:
void dataCallback(LONG lPlayHandle, DWORD dwDataType, BYTE *pBuffer,DWORD dwBufSize,DWORD dwUser) {
switch (dwDataType) {
case NET_DVR_SYSHEAD: { //系统头数据
}
break;
case NET_DVR_STREAMDATA: { //流数据(包括复合流或音视频分开的视频流数据)
}
break;
case NET_DVR_AUDIOSTREAMDATA: { //音频数据
}
break;
case NET_DVR_PRIVATE_DATA: { //私有数据,包括智能信息
}
break;
default:
break;
}
}
ES流回调示例:
void esDataCallback(LONG lPlayHandle, NET_DVR_PACKET_INFO_EX *struPackInfo, void* pUser) {
// 0系统头; 1、2、3视频;10音频
if (0 == pstruPackInfo->dwPacketType) {
} else if (1 == pstruPackInfo->dwPacketType
|| 2 == pstruPackInfo->dwPacketType
|| 3 == pstruPackInfo->dwPacketType
|| 10 == pstruPackInfo->dwPacketType) {
}
}
遇到的问题:
当播放参数请求没有传递窗口句柄时,码流回调会以最大码率发送,表现效果就是可能一分钟就把几十分钟的录像全部回调播放完。
解决办法:
1、 通过回放控制方法传NET_DVR_SETSPEED(设置码率命令),将回调码率设置成当前的视频码率就行。
2、 非常规办法,曾经遇到过设置码率没有效果的情况,改成在ES流回调里面判断回调码流的时间戳,结合前后回调的时间戳以及本地时间,计算出时间差之后,通过sleep实现延缓码流回调
5、停止播放
停止播放用到的方法只有一个NET_DVR_StopPlayBack,入参为录像回放方法返回的句柄
函数原型:
NET_DVR_API BOOL __stdcall NET_DVR_StopPlayBack(LONG lPlayHandle);
6、登出设备
登出设备只需调用NET_DVR_Logout_V30方法,参数传登录时获取到的登录句柄。
函数原型:
NET_DVR_API BOOL __stdcall NET_DVR_Logout_V30(LONG lUserID);
7、销毁sdk
退出很简单,只需调用NET_DVR_Cleanup方法
函数原型:
NET_DVR_API BOOL __stdcall NET_DVR_Cleanup();