在使用海康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();