zoukankan      html  css  js  c++  java
  • 视频融合协议安防监控系统EasyCVR开发支持大华SDK接入设备录像回放流程说明

    很多咨询者或者老客户都知道TSINGSEE青犀视频开发的EasyCVR平台是支持私有协议的,最开始支持HIKSDK,随后又开发了Ehome协议的接入,到现在,我们已经完成了大华SDK的接入支持。本文讲一下EasyCVR平台接入大华SDK设备进行录像回放的流程。

    录像回放是指客户端远程播放设备中指定时间段内的录像文件,寻找所需要的视频信息。 回放功能支持多种回放操作,如正常播放、暂停、快放、慢放、拖动播放等。

    1. 完成SDK初始化流程。
    2. 初始化成功后,调用 CLIENT_LoginEx2 登录设备。
    3. 登录成功后,两次调用 CLIENT_SetDeviceMode,分别设置回放时的码流类型和回放时的录像文件类型。
    4. 登录成功后,调用 CLIENT_PlayBackByTimeEx 启动回放,hWnd 参数为 NULL,fDownLoadDataCallBack 参数为有效回调函数指针。
    5. SDK 收到回放数据后,通过设置的fDownLoadDataCallBack回调函数回调回放数据给用户,用户在回调函数中保存回放数据,离开回调函数后,再通过第三方库解码回放录像数据。
    6. 回放过程中 ,根据用户需求调用 CLIENT_SlowPlayBack 实现慢放,CLIENT_FasePlayBack 实现快放, CLIENT_NormalPlayBack 实现正常播放速
      度,CLIENT_PausePlayBack 实现暂停/恢复,CLIENT_SeekPlayBack 实现拖
      动播放,同时需调用第三方库相应的接口。
    7. 回放使用完毕后,调用 CLIENT_StopPlayBack 停止回放。
    8. 业务使用完后,调用 CLIENT_Logout 注销用户。
    9. SDK功能使用完后,调用 CLIENT_Cleanup 释放SDK资源。

    大华SDK解码回放流程,如下图所示:

    #include <stdio.h> 
    #include "dhnetsdk.h" 
    #pragma comment(lib , "dhnetsdk.lib") 
    static BOOL g_bNetSDKInitFlag = FALSE; 
    static LLONG g_lLoginHandle = 0L; 
    static LLONG g_lPlayHandle = 0L; 
    static char g_szDevIp[32] = "172.11.1.6"; 
    static WORD g_nPort = 37777; // tcp 连接端口,需与期望登录设备页面 tcp 端口配置一 
    致 
    static char g_szUserName[64] = "admin"; 
    static char g_szPasswd[64] = "admin"; 
    //************************************************************************* 
    ******** 
    // 常用回调集合声明 
    // 设备断线回调函数 
    // 不建议在该回调函数中调用SDK接口 
    // 通过 CLIENT_Init 设置该回调函数,当设备出现断线时,SDK 会调用该函数。 
    void CALLBACK DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, 
    DWORD dwUser); 
    // 断线重连成功回调函数 
    // 不建议在该回调函数中调用 SDK 接口 
    // 通过 CLIENT_SetAutoReconnect 设置该回调函数,当已断线的设备重连成功时,SDK 会 
    调用该函数。 
    void CALLBACK HaveReConnect(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, 
    LDWORD dwUser); 
    // 回放进度回调函数 
    // 不建议在该回调函数中调用SDK接口 
    // 通过 CLIENT_PlayBackByTimeEx 设置该回调函数,当接收到设备端的回放数据时,SDK会调用该函数 
    void CALLBACK DownLoadPosCallBack(LLONG lPlayHandle, DWORD dwTotalSize, DWORD 
    dwDownLoadSize, LDWORD dwUser); 
    // 回放数据回调函数 
    // 不建议在该回调函数中调用SDK接口 
    // 当设置该回调函数时,若对应的hWnd参数为 NULL,参数返回,0:表示本次回调失败,下次回调会返回相同的数据,1:表示本次回调成功,下次回调会返回后续的数据 
    // 当设置该回调函数时,若对应的 hWnd 参数不为 NULL,则不管回调函数返回值为多少都认为 
    回调成功,下次回调会返回后续的数据 
    // 通过CLIENT_PlayBackByTimeEx设置该回调函数,当接收到设备端的回放数据时,SDK 
    40 41 
    会调用该函数。 
    int CALLBACK DataCallBack(LLONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, 
    DWORD dwBufSize, LDWORD dwUser); 
    //************************************************************** *********** 
    ************ 
    void InitTest() 
    { 
    // 初始化 SDK 
    g_bNetSDKInitFlag = CLIENT_Init(DisConnectFunc, 0); 
    if (FALSE == g_bNetSDKInitFlag) 
    { 
    printf("Initialize client SDK fail; 
    "); 
    return; 
    } 
    else 
    { 
    printf("Initialize client SDK done; 
    "); 
    } 
    // 获取 SDK 版本信息 
    // 此操作为可选操作 
    DWORD dwNetSdkVersion = CLIENT_GetSDKVersion(); 
    printf("NetSDK version is [%d]
    ", dwNetSdkVersion); 
    // 设置断线重连回调接口,设置过断线重连成功回调函数后,当设备出现断线情况,SDK内部会自动进行重连操作
    // 此操作为可选操作,但建议用户进行设置 
    CLIENT_SetAutoReconnect(&HaveReConnect, 0); 
    // 设置登录超时时间和尝试次数 
    // 此操作为可选操作 
    int nWaitTime = 5000; // 登录请求响应超时时间设置为5s 
    int nTryTimes = 3; // 登录时尝试建立链接3次 
    CLIENT_SetConnectTime(nWaitTime, nTryTimes); 
    // 设置更多网络参数,NET_PARAM 的 nWaittime,nConnectTryNum 成员与 
    CLIENT_SetConnectTime 接口设置的登录设备超时时间和尝试次数意义相同 
    // 此操作为可选操作 
    NET_PARAM stuNetParm = {0}; 42 
    stuNetParm.nConnectTime = 3000; // 登录时尝试建立链接的超时时间 
    CLIENT_SetNetworkParam(&stuNetParm); 
    NET_DEVICEINFO_Ex stDevInfoEx = {0}; 
    int nError = 0; 
    while(0 == g_lLoginHandle) 
    { 
    // 登录设备 
    g_lLoginHandle = CLIENT_LoginEx2(g_szDevIp, g_nPort, g_szUserName, 
    g_szPasswd, EM_LOGIN_SPEC_CAP_TCP, NULL, &stDevInfoEx, &nError); 
    if(0 == g_lLoginHandle) 
    { 
    // 根据错误码,可以在 dhnetsdk.h 中找到相应的解释,此处打印的是 16 进制,头文件中是十进制,其中的转换需注意 
    // 例如: 
    // #define NET_NOT_SUPPORTED_EC(23) // 当前 SDK 未支持该功能,对应的错误码为 0x80000017, 23 对应的 16 进制为 0x17 
    printf("CLIENT_LoginEx2 %s[%d]Failed!Last Error[%x]
    " , g_szDevIp , 
    g_nPort , CLIENT_GetLastError()); 
    } 
    else 
    { 
    printf("CLIENT_LoginEx2 %s[%d] Success
    " , g_szDevIp , g_nPort); 
    } 
    // 用户初次登录设备,可能要初始化一些数据才能正常实现业务功能,所以建议登录后等待一小段时间,具体等待时间因设备而异 
    Sleep(1000); 
    printf("
    "); 
    } 
    } 
    void RunTest() 
    { 
    if (FALSE == g_bNetSDKInitFlag) 
    { 
    return; 
    } 
    if (0 == g_lLoginHandle) 
    { 
    return; 
    } 43 
    // 录像回放功能 
    // 设置回放时的码流类型 
    int nStreamType = 0; // 0-主辅码流,1-主码流,2-辅码流 
    CLIENT_SetDeviceMode(g_lLoginHandle, DH_RECORD_STREAM_TYPE, 
    &nStreamType); 
    // 设置回放时的录像文件类型 
    NET_RECORD_TYPE emFileType = NET_RECORD_TYPE_ALL; // 所有录像 
    CLIENT_SetDeviceMode(g_lLoginHandle, DH_RECORD_TYPE, &emFileType); 
    //开启录像回放 
    int nChannelID = 0; // 通道号 
    NET_TIME stuStartTime = {0}; 
    stuStartTime.dwYear = 2015; 
    stuStartTime.dwMonth = 11; 
    stuStartTime.dwDay = 20; 
    NET_TIME stuStopTime = {0}; 
    stuStopTime.dwYear = 2015; 
    stuStopTime.dwMonth = 11; 
    stuStopTime.dwDay = 21; 
    // 函数形参 hWnd 需为 NULL 
    // 函数形参 fDownLoadDataCallBack 需为 有效回调函数指针 
    g_lPlayHandle = CLIENT_PlayBackByTimeEx(g_lLoginHandle, nChannelID, 
    &stuStartTime, &stuStopTime, NULL, &DownLoadPosCallBack, NULL, &DataCallBack, 
    NULL); 
    if (g_lPlayHandle == 0) 
    { 
    printf("CLIENT_PlayBackByTimeEx: failed! Error code: %x.
    ", 
    CLIENT_GetLastError()); 
    } 
    // 用户可根据需求实现回放控制 
    // 由于是第三方库解码,用户在调用 SDK 的回放控制接口的同时,还需要调用第三方库相应的控制接口 
    // 由于这个是控制台 demo,无法将录像回放和回放控制同时展现给用户,这里提供示例 
    代码用于参考 
    // CLIENT_SlowPlayBack 实现慢放 
    /* 示例代码 
    if (FALSE == CLIENT_SlowPlayBack (g_lPlayHandle)) 
    { 44 
    printf("CLIENT_SlowPlayBack Failed, g_lPlayHandle[%x]!Last 
    Error[%x]
    " , g_lPlayHandle, CLIENT_GetLastError()); 
    } 
    // 第三方库相应接口调用 
    */ 
    // CLIENT_FastPlayBack 实现快放 
    /* 示例代码 
    if (FALSE == CLIENT_FastPlayBack (g_lPlayHandle)) 
    { 
    printf("CLIENT_FastPlayBack Failed, g_lPlayHandle[%x]!Last 
    Error[%x]
    " , g_lPlayHandle, CLIENT_GetLastError()); 
    } 
    // 第三方库相应接口调用 
    */ 
    // CLIENT_NormalPlayBack 实现正常播放速度 
    /* 示例代码 
    if (FALSE == CLIENT_NormalPlayBack (g_lPlayHandle)) 
    { 
    printf("CLIENT_NormalPlayBack Failed, g_lPlayHandle[%x]!Last 
    Error[%x]
    " , g_lPlayHandle, CLIENT_GetLastError()); 
    } 
    // 第三方库相应接口调用 
    */ 
    // CLIENT_PausePlayBack 实现暂停/恢复 
    /* 示例代码 
    if (FALSE == CLIENT_PausePlayBack (g_lPlayHandle, TRUE)) 
    { 
    printf("CLIENT_PausePlayBack Failed, g_lPlayHandle[%x]!Last 
    Error[%x]
    " , g_lPlayHandle, CLIENT_GetLastError()); 
    } 
    // 第三方库相应接口调用 
    */ 
    // CLIENT_SeekPlayBack 实现拖动播放 
    /* 示例代码 
    int nOffsetSeconds = 2 * 60 * 60; // 拖动至 stuStartTime 后 2*60*60 秒的位 
    置开始回放 if (FALSE == CLIENT_SeekPlayBack (g_lPlayHandle, nOffsetSeconds, 0)) 
    { 
    printf("CLIENT_SeekPlayBack Failed, g_lPlayHandle[%x]!Last 
    Error[%x]
    " , g_lPlayHandle, CLIENT_GetLastError()); 
    } 
    // 第三方库相应接口调用 
    */ 
    } 
    void EndTest() 
    { 
    printf("input any key to quit!
    "); 
    getchar(); 
    // 关闭回放 
    if (0 != g_lPlayHandle) 
    { 
    if (FALSE == CLIENT_StopPlayBack(g_lPlayHandle)) 
    { 
    printf("CLIENT_StopPlayBack Failed, g_lRealHandle[%x]!Last 
    Error[%x]
    " , g_lPlayHandle, CLIENT_GetLastError()); 
    } 
    else 
    { 
    g_lPlayHandle = 0; 
    } 
    } 
    // 退出设备 
    if (0 != g_lLoginHandle) 
    { 
    if(FALSE == CLIENT_Logout(g_lLoginHandle)) 
    { 
    printf("CLIENT_Logout Failed!Last Error[%x]
    ", 
    CLIENT_GetLastError()); 
    } 
    else 
    { 
    g_lLoginHandle = 0; 
    } 
    } 
    // 清理初始化资源 
    if (TRUE == g_bNetSDKInitFlag) 
    { 
    CLIENT_Cleanup(); 
    45 46 
    g_bNetSDKInitFlag = FALSE; 
    } 
    return; 
    } 
    int main() 
    { 
    InitTest(); 
    RunTest(); 
    EndTest(); 
    return 0; 
    } 
    //************************************************************************* 
    ******** 
    // 常用回调集合定义 
    void CALLBACK DisConnectFunc(LLONG lLoginID, char *pchDVRIP, LONG nDVRPort, 
    DWORD dwUser) 
    { 
    printf("Call DisConnectFunc
    "); 
    printf("lLoginID[0x%x]", lLoginID); 
    if (NULL != pchDVRIP) 
    { 
    printf("pchDVRIP[%s]
    ", pchDVRIP); 
    } 
    printf("nDVRPort[%d]
    ", nDVRPort); 
    printf("dwUser[%p]
    ", dwUser); 
    printf("
    "); 
    } 
    void CALLBACK HaveReConnect(LLONG lLoginID, char *pchDVRIP, LONG nD VRPort, 
    LDWORD dwUser) 
    { 
    printf("Call HaveReConnect
    "); 
    printf("lLoginID[0x%x]", lLoginID); 
    if (NULL != pchDVRIP) 
    { 
    printf("pchDVRIP[%s]
    ", pchDVRIP); 
    } 
    printf("nDVRPort[%d]
    ", nDVRPort); 47 
    printf("dwUser[%p]
    ", dwUser); 
    printf("
    "); 
    } 
    void CALLBACK DownLoadPosCallBack(LLONG lPlayHandle, DWORD dwTotalSize, DWORD 
    dwDownLoadSize, LDWORD dwUser) 
    { 
    // 若多个回放/下载使用相同的进度回调函数,则用户可通过 lPlayHandle 进行一一对应 
    if (lPlayHandle == g_lPlayHandle) 
    { 
    printf("lPlayHandle[%p]
    ", lPlayHandle); 
    printf("dwTotalSize[%d]
    ", dwTotalSize); 
    printf("dwDownLoadSize[%d]
    ", dwDownLoadSize); 
    printf("dwUser[%p]
    ", dwUser); 
    printf("
    "); 
    } 
    } 
    int CALLBACK DataCallBack(LLONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, 
    DWORD dwBufSize, LDWORD dwUser) 
    { 
    int nRet = 0; 
    printf("call DataCallBack
    "); 
    // 若多个回放/下载使用相同的数据回调函数,则用户可通过 lRealHandle 进行一一对应 
    if(lRealHandle == g_lPlayHandle) 
    { 
    BOOL bSuccess = TRUE; 
    // 以下打印在回放/下载时会造成刷屏现象,请注意 
    printf("lPlayHandle[%p]
    ", lRealHandle); 
    printf("dwDataType[%d]
    ", dwDataType); 
    printf("pBuffer[%p]
    ", pBuffer); 
    printf("dwBufSize[%d]
    ", dwBufSize); 
    printf("dwUser[%p]
    ", dwUser); 
    printf("
    "); 
    switch(dwDataType) 
    { 
    case 0: 
    //Original data 
    // 用户在此处保存码流数据,离开回调函数后再进行解码或转发等一系列处理 
    nRet = 1;// 
    break; 48 
    case 1: 
    //Standard video data 
    break; 
    case 2: 
    //yuv data 
    break; 
    case 3: 
    //pcm audio data 
    break; 
    case 4: 
    //Original audio data 
    break; 
    default: 
    break; 
    } 
    } 
    return nRet; 
    }
    

     

  • 相关阅读:
    WCF实现上传图片功能
    C#中String.Empty、NULL与""三者的区别
    C#中equal与==的区别
    static 关键字的使用,静态和非静态类的区别
    C#索引器
    C# 接口的隐式与显示实现说明
    Python文件处理
    Python3.X与urllib
    python中if __name__ == '__main__'
    Python中的random模块
  • 原文地址:https://www.cnblogs.com/TSINGSEE/p/14326428.html
Copyright © 2011-2022 走看看