视频监控系统视频上云解决方案EasyCVR集成海康EHome私有协议系列——设备录像回看说明
之前的博文讲过EasyCVR集成海康EHome私有协议语音对讲操作流程以及Ehome协议调用流程介绍,有兴趣的用户可以移步看一下,本文我们还是来说EasyCVR集成海康EHome中的注意点——设备录像回看说明。
回放即播放已存储并搜索到的视频文件,EasyCVR集成海康EHome协议通过ISUPSDK实现回放需依赖于中心管理服务(CMS)、流媒体服务(SMS)和播放库。
回放接口调用流程图
操作的基本步骤
1、调用NET_ECMS_XMLConfig和命令GetDevAbility获取设备能力并判断是否支持回放。设备能力集由pOutBuf返回。如果支持,将返回节点,可继续下面步骤。否则,请结束该任务。
2、调用NET_ESTREAM_StartListenPlayBack开启SMS监听服务并接收来自设备的连接请求。
3、调用NET_ESTREAM_SetExceptionCallBack为SMS注册异常回调函数,异常信息会被回调至该注册的回调函数中,请及时处理异常避免阻塞。
4、调用NET_ECMS_StartPlayBack将回放开始请求从CMS发送给设备。发送SMS的地址和端口号给设备,并会自动为CMS分配一个会话ID。
5、调用NET_ESTREAM_SetPlayBackDataCB为SMS注册回调函数用于接收来自设备的回放码流。
6、调用NET_ECMS_StartPushPlayBack将码流传输请求从CMS发送给设备。
7、调用NET_ESTREAM_StopPlayBack停止SMS的码流转发
8、调用NET_ECMS_StopPlayBack将回放停止请求从CMS发送给设备
9、调用NET_ESTREAM_StopListenPlayBack停止SMS监听服务并断开其与设备的连接
示例代码:
// //注册回调函数 BOOL CALLBACK RegisterCallBack(LONG lUserID, DWORD dwDataType, void *pOutBuffer, DWORD dwOutLen, void *pInBuffer, DWORD dwInLen, void *pUser) { if (ENUM_DEV_ON == dwDataType) { NET_EHOME_DEV_REG_INFO *pDevInfo = (NET_EHOME_DEV_REG_INFO *)pOutBuffer; if (pDevInfo != NULL) { lLoginID = lUserID; printf("On-line, lUserID: %d, Device ID: %s\n", lLoginID, pDevInfo->byDeviceID); } //输入参数 NET_EHOME_SERVER_INFO *pServerInfo = (NET_EHOME_SERVER_INFO *)pInBuffer; pServerInfo->dwTimeOutCount = 6; //心跳超时次数 pServerInfo->dwKeepAliveSec = 15; //心跳间隔 } else if (ENUM_DEV_OFF == dwDataType) { printf("Off-line, lUserID: %d\n", lUserID); NET_ECMS_ForceLogout(lUserID); } else { } return TRUE; } // //处理文件流数据 BOOL InputStreamData(BYTE byDataType, char* pBuffer, int iDataLen) { if(Videofile == NULL) { Videofile = fopen("Test.mp4","wb"); printf("Save data to file: Test.mp4!"); } if(Videofile!= NULL) { fwrite(pBuffer,iDataLen,1,Videofile); //下载视频文件 } //调用播放库解码并显示码流实现回放 /* if(1 == byDataType) { if (!PlayM4_GetPort(&m_lPort)) { return FALSE; } if (!PlayM4_SetStreamOpenMode(m_lPort, STREAME_REALTIME)) { return FALSE; } //Enter first 40-byte header if(!PlayM4_OpenStream(m_lPort, (unsigned char *)pBuffer, (DWORD)iDataLen, 2*1024*1024)) { return FALSE; } if(!PlayM4_Play(m_lPort, hWnd)) { return FALSE; } } else { for (int i=0; i<1000; i++) { BOOL bRet = PlayM4_InputData(m_lPort,(unsigned char *)pBuffer, (DWORD)iDataLen); if (!bRet) { if ( i >=999) { printf("PlayM4_InputData failed, error code: %d!", PlayM4_GetLastError(m_lPort)); } Sleep(2); } } } */ return TRUE; } // //注册回放码流回调函数 BOOL CALLBACK fnPLAYBACK_DATA_CB(LONG lPlayBackLinkHandle, NET_EHOME_PLAYBACK_DATA_CB_INFO *pDataCBInfo, void *pUserData) { if (NULL == pDataCBInfo) { return FALSE; } lPlayHandle = lPlayBackLinkHandle; InputStreamData(pDataCBInfo->dwType, (char*)pDataCBInfo->pData, pDataCBInfo->dwDataLen); return TRUE; } // //注册回访请求的响应回调函数 BOOL CALLBACK fnPLAYBACK_NEWLINK_CB(LONG lPlayBackLinkHandle, NET_EHOME_PLAYBACK_NEWLINK_CB_INFO *pNewLinkCBMsg, void *pUserData) { lLinkHandle = lPlayBackLinkHandle; printf("Callback of playback listening, Device ID: %s\n", pNewLinkCBMsg->szDeviceID); //回放数据的回调参数 NET_EHOME_PLAYBACK_DATA_CB_PARAM struDataCB = {0}; struDataCB.fnPlayBackDataCB = fnPLAYBACK_DATA_CB; struDataCB.byStreamFormat = 0;//封装格式:0-PS格式 if (!NET_ESTREAM_SetPlayBackDataCB(lPlayBackLinkHandle, &struDataCB)) { printf("NET_ESTREAM_SetPlayBackDataCB failed, error code: %d\n", NET_ESTREAM_GetLastError()); return FALSE; } printf("NET_ESTREAM_SetPlayBackDataCB!\n"); return TRUE; } / //设置异常回调 NET_ESTREAM_SetExceptionCallBack(0, 0, StreamExceptionCallback, NULL); void CALLBACK StreamExceptionCallback(DWORD dwType, LONG iUserID, LONG iHandle, void* pUser) { if(EHOME_PREVIEW_EXCEPTION == dwType) { //预览异常 printf("Preview exception, handle=%d, Error:%d", iHandle, dwError); } else if (EHOME_PLAYBACK_EXCEPTION == dwType) { //回放异常 printf("Playback exception, handle=%d, Error:%d", iHandle, dwError); } else if (EHOME_AUDIOTALK_EXCEPTION == dwType) { //语音对讲(转发)异常 printf("Stream VoiceTalk exception, handle=%d, Error:%d", iHandle, dwError); } } void main(){ //SMS在开启监听服务后获取码流 //初始化SMS库 NET_ESTREAM_Init(); //回放的监听参数 NET_EHOME_PLAYBACK_LISTEN_PARAM struListen = {0}; memcpy(struListen.struIPAdress.szIP,"10.16.2.123", sizeof("10.16.2.123")); struListen.struIPAdress.wPort = 8003; //SMS的监听端口号 struListen.fnNewLinkCB = fnPLAYBACK_NEWLINK_CB; //回放请求的回调函数 struListen.pUserData = NULL; struListen.byLinkMode = 0; //0-TCP, 1-UDP(保留) //开启监听服务 LONG lHandle = NET_ESTREAM_StartListenPlayBack(&struListen); if(lHandle < -1) { printf("NET_ESTREAM_StartListenPlayBack failed, error code: %d\n", NET_ESTREAM_GetLastError()); NET_ESTREAM_Fini(); return; } printf("NET_ESTREAM_StartListenPlayBack!\n"); // //注册和回放请求 //初始化CMS库 NET_ECMS_Init(); //注册的监听参数 NET_EHOME_CMS_LISTEN_PARAM struCMSListenPara = {0}; memcpy(struCMSListenPara.struAddress.szIP, "0.0.0.0", sizeof("0.0.0.0")); struCMSListenPara.struAddress.wPort = 7660; struCMSListenPara.fnCB = RegisterCallBack; //开启监听服务并接收设备注册信息 LONG lListen = NET_ECMS_StartListen(&struCMSListenPara); if(lListen < -1) { printf("NET_ECMS_StartListen failed, error code: %d\n", NET_ECMS_GetLastError()); NET_ECMS_Fini(); return; } printf("NET_ECMS_StartListen!\n"); while(1) { Sleep(1000); //以下操作需在注册完成后再进行 if(lLoginID >= 0) { break; } } //查找视频文件 NET_EHOME_REC_FILE_COND struFindCond = {0}; struFindCond.dwChannel =1; //通道号,从1开始 struFindCond.dwRecType = 0xff; //所有类型 struFindCond.dwStartIndex = 0; //查找起始位置 struFindCond.dwMaxFileCountPer = 5; //单次搜索的最多文件数量 //查找开始时间 struFindCond.struStartTime.wYear = (WORD)2015; struFindCond.struStartTime.byMonth = (BYTE)5; struFindCond.struStartTime.byDay = (BYTE)18; struFindCond.struStartTime.byHour = (BYTE)10; struFindCond.struStartTime.byMinute = (BYTE)0; struFindCond.struStartTime.bySecond = (BYTE)0; //查找结束时间 struFindCond.struStopTime.wYear = (WORD)2015; struFindCond.struStopTime.byMonth = (BYTE)5; struFindCond.struStopTime.byDay = (BYTE)18; struFindCond.struStopTime.byHour = (BYTE)12; struFindCond.struStopTime.byMinute = (BYTE)59; struFindCond.struStopTime.bySecond = (BYTE)59; LONG lSearchType = 0; //查找文件 LONG lFileHandle = NET_ECMS_StartFindFile_V11(lLoginID, lSearchType, &struFindCond, sizeof(struFindCond)); //Start file search if (lFileHandle < 0) { printf("NET_ECMS_StartFindFile_V11 failed, error code: %d\n", NET_ECMS_GetLastError()); NET_ECMS_Fini(); return; } printf("NET_ECMS_StartFindFile_V11!\n"); LONG lRet = -1; char csTmp[256] = {0}; char szFileName[MAX_FILE_NAME_LEN] = {0}; NET_EHOME_REC_FILE struFileInfo = {0}; //可在线程中搜索文件 while(1) { lRet = NET_ECMS_FindNextFile_V11(lFileHandle, &struFileInfo, sizeof(struFileInfo));//逐个获取搜索结果 if (lRet == ENUM_GET_NEXT_STATUS_SUCCESS) { if (struFileInfo.dwFileSize / 1024 == 0) { sprintf(csTmp,"%d",struFileInfo.dwFileSize); } else if (struFileInfo.dwFileSize / 1024 > 0 && struFileInfo.dwFileSize /(1024*1024) == 0) { sprintf(csTmp,"%dK",struFileInfo.dwFileSize/1024); } else { sprintf(csTmp,"%dM",struFileInfo.dwFileSize /1024/1024); } printf("Filename[%s], Filesize[%s], StarTime[%04d-%02d-%02d %02d:%02d:%02d], StopTime[%04d-%02d-%02d %02d:%02d:%02d] \n", \ struFileInfo.szFileName, csTmp, struFileInfo.struStartTime.wYear, struFileInfo.struStartTime.byMonth, \ struFileInfo.struStartTime.byDay, struFileInfo.struStartTime.byHour, struFileInfo.struStartTime.byMinute,\ struFileInfo.struStartTime.bySecond, struFileInfo.struStopTime.byDay, struFileInfo.struStopTime.byHour, \ struFileInfo.struStopTime.byMinute, struFileInfo.struStopTime.bySecond);//Searched file information memcpy(szFileName, struFileInfo.sFileName, MAX_FILE_NAME_LEN); } else { if (lRet == ENUM_GET_NETX_STATUS_NEED_WAIT) { Sleep(5); continue; } if ((lRet == ENUM_GET_NETX_STATUS_NO_FILE) || (lRet == ENUM_GET_NEXT_STATUS_FINISH)) { printf("No more file!\n"); break; } else if(lRet == ENUM_GET_NEXT_STATUS_NOT_SUPPORT) { printf("Device does not support!\n"); break; } else { printf("Failed to find a file, for the server is busy or network failure!\n"); break; } } } //回放请求的输入参数 NET_EHOME_PLAYBACK_INFO_IN struPlayBackIn = {0}; struPlayBackIn.dwSize = sizeof(struPlayBackIn); struPlayBackIn.dwChannel = 1; //通道号 struPlayBackIn.byPlayBackMode = 0; //回放模式:0-按文件名回放,1-按时间回放(保留) struPlayBackIn.unionPlayBackMode.struPlayBackbyName.dwSeekType = 0; //0-按字节长度计算,1-按秒数计算 struPlayBackIn.unionPlayBackMode.struPlayBackbyName.dwFileOffset = 0; //当dwSeekType为0时,偏移量按字节计算;当dwSeekType等于1时,偏移量按秒数计算 struPlayBackIn.unionPlayBackMode.struPlayBackbyName.dwFileSpan = 0; //已下载的文件大小,如果大小为0,说明文件已下载完成 memcpy(struPlayBackIn.unionPlayBackMode.struPlayBackbyName.szFileName, szFileName, MAX_FILE_NAME_LEN);//需要进行回放的文件名称 memcpy(struPlayBackIn.struStreamSever.szIP, "10.16.2.123", sizeof("10.16.2.123")); //SMS的IP地址 struPlayBackIn.struStreamSever.wPort = 8003; //SMS的端口号,需和监听端口号一致 //回放请求的输出参数 NET_EHOME_PLAYBACK_INFO_OUT struPlayBackOut = {0}; //回放请求 if(!NET_ECMS_StartPlayBack(lLoginID, &struPlayBackIn, &struPlayBackOut)) { printf("NET_ECMS_StartPlayBack failed, error code: %d\n", NET_ECMS_GetLastError()); NET_ECMS_Fini(); return; } printf("NET_ECMS_StartPlayBack!\n"); //码流传输请求的输入参数 NET_EHOME_PUSHPLAYBACK_IN struPushPlayBackIn = {0}; struPushPlayBackIn.dwSize = sizeof(struPushPlayBackIn); struPushPlayBackIn.lSessionID = struPlayBackOut.lSessionID; //回放请求的会话ID //码流传输请求的输出参数 NET_EHOME_PUSHPLAYBACK_OUT struPushPlayBackOut = {0}; //发送请求给设备并开始传输码流 if(!NET_ECMS_StartPushPlayBack(lLoginID, &struPushPlayBackIn, &struPushPlayBackOut)) { printf("NET_ECMS_StartPushPlayBack failed, error code: %d\n", NET_ECMS_GetLastError()); NET_ECMS_Fini(); return; } printf("NET_ECMS_StartPushPlayBack!\n"); Sleep(50000); //登出 //CMS停止监听服务 if(!NET_ECMS_StopListen(lListen)) { printf("NET_ECMS_StopListen failed, error code: %d\n", NET_ECMS_GetLastError()); } //释放被CMS占用的资源 NET_ECMS_Fini(); // //SMS停止转发码流 if(lPlayHandle >= 0) { if (!NET_ESTREAM_StopPlayBack(lPlayHandle)) { printf("NET_ESTREAM_StopPlayBack failed, error code: %d\n", NET_ECMS_GetLastError()); } } //SMS停止监听服务 if(lLinkHandle >= 0) { if (!NET_ESTREAM_StopListenPlayBack(lLinkHandle)) { printf("NET_ESTREAM_StopListenPlayBack failed, error code: %d\n", NET_ECMS_GetLastError()); } } //释放被SMS占用的资源 NET_ESTREAM_Fini(); //释放文件资源 if(Videofile != NULL) { fclose(Videofile); Videofile = NULL; } printf("Exit!\n"); }
更多关于EasyCVR:
EasyCVR是一个集视频联网共享、存储、流媒体转发、视频转码、视频上云、智能分析统一等多种功能为一体的流媒体视频服务融合性平台。
1、支持各种类型存储,包括DAS、NAS、SAN、OBS等;
2、支持各种摄像机、NVR、DVR接入,包括RTSP、RTMP、GB/T28181、Onvif、SDK、ehome协议;
3、以经济高效的方式存储视频,支持扩展、备份、归档;
4、视频分析数据与多源数据融合,通过智能分析算法挖掘价值数据;
5、支持RTSP/RTMP等方式转发视频图像。
视频相关解决方案均可访问TSINGSEE青犀视频,可以联系我们获取演示方案,直观感受,也可自行进行下载及测试。