1 SDK交互说明
1)通过抓包分析SDK跟服务器之间的交互,采用的是ONVIF协议
2)连接采用的是短链接,一般查询结束,下一次查询采用的端口是不一样的
3)SDK没有主动关闭短链接,如果频繁查询连接,会产生大量的TIME_WAIT,耗尽系统的端口资源,可以通过设置TIME_WAIT的存活时间优化一下,但是不能根本解决问题
4)取流端口是554,非常类似于通过ONVIF进行设备信息交互,RTSP取流方式
2 NETDEV_Login解析
/**
* 用户登录 User login
* @param [IN] pszDevIP 设备IP Device IP
* @param [IN] wDevPort 设备服务器端口 Device server port
* @param [IN] pszUserName 用户名 Username
* @param [IN] pszPassword 密码 Password
* @param [OUT] pstDevInfo 设备信息结构体指针 Pointer to device information structure
* @return 返回的用户登录句柄,返回 0 表示失败,其他值表示返回的用户登录句柄值. Returned user login ID. 0 indicates failure, and other values indicate the user ID.
* @note
*/
NETDEV_API NEWINTERFACE LPVOID STDCALL NETDEV_Login(IN char *pszDevIP,
IN INT16 wDevPort,
IN char *pszUserName,
IN char *pszPassword,
OUT LPNETDEV_DEVICE_INFO_S pstDevInfo);
1)设备服务器端口一般情况下是80,也有81的情况,因此最好不要硬编码
2)登陆的接口耗时比较久,大概1秒,这个过程中会进行用户名和密码校验,然后进行设备信息查询
3)登陆离线状态的摄像机,耗时30秒才能返回,因此流媒体对接过程中,需要针对这个函数进行异步处理,避免阻塞下一个点播请求
4)调用登陆接口,提示出错65543,原因升级SDK,DLL只是替换了部分,导致加载DLL出错
3 NETDEV_SetExceptionCallBack
可以设置NETDEV_SetExceptionCallBack的回调函数,该接口在设备断线的情况下,会进行函数的回调,测试结果表明,断线之后,可以不需要调用NETDEV_Login重新登陆
void STDCALL myNETDEV_ExceptionCallBack_PF(IN LPVOID lpUserID,
IN INT32 dwType,
IN LPVOID lpExpHandle,
IN LPVOID lpUserData,
OUT LPNETDEV_EXCEPTION_OUTPUT_INFO_S pstExceptionOutputInfo)
{
std::cout << "异常错误信息" << std::endl;
std::cout << std::hex << (unsigned int) dwType << std::endl;
}
NETDEV_SetExceptionCallBack(myNETDEV_ExceptionCallBack_PF, NULL);
4 NETDEV_QueryVideoChlDetailList
迭代NVR的视频通道
NETDEV_VIDEO_CHL_DETAIL_INFO_S pstVideoChlList[256] = { 0 };
INT32 dwCount = 256;
bool bRet = NETDEV_QueryVideoChlDetailList(m_pUserHandle, &dwCount, pstVideoChlList);
if (bRet)
{
//实际上测试的结果都会返回128个通道,跟网页上的不一致,多余的通道名称都是摄像机[空格]+通道号
for (int i = 0; i < dwCount; i++)
{
//pstVideoChlList[i].dwChannelID;
//pstVideoChlList[i].szChnName;
}
std::cout << "查询通道列表成功";
}
else
{
std::cout<< "查询通道列表失败,错误码:" << NETDEV_GetLastError();
}
5 NETDEV_PICTURE_REAL
通过SDK,获取到码流数据进行转发,设置图像播放流畅性优先类型参数为NETDEV_PICTURE_REAL,获取到码流(从点播到接收到第一个I帧)需要300毫秒,设置NETDEV_PICTURE_FLUENCY,大概是390毫秒,测试次数不够多,意义不大
6 NETDEV_RealPlay预览
1回调数据设置
NETDEV_RealPlay函数可以设置回调函数获取到RTP格式的码流数据
NETDEV_SetPlayParseCB函数可以设置回调函数获取到(H264或者H265)的裸流数据
2 预览失败问题分析
2.5版本SDK ,该函数返回空句柄,错误码
NETDEV_E_LIVE_NET_FAILED 2005 会话网络错误
2.6版本SDK,该函数返回空句柄,错误码
NETDEV_E_LIVE_INPUT_NOT_READY 2001 媒体流未准备就绪
通过抓包分析到在进行RTSP交互过程中,出错了
设备返回RST ACK ,说明不响应该请求,直接断开
解决方案
网页修改RTSP端口为553,解决问题(暂时不清楚设备为何会中断连接,宇视DEMO,在客户端访问预览正常,在服务器登陆设备成功,预览异常)
6 NETDEV_GetFrameRate获取窗口帧率
目前调用接口返回成功,但是帧率字段为0,无法获取真实的帧率
std::int32_t nFrameRate = 0;
bRet = NETDEV_GetFrameRate(pPlayHandle, &nFrameRate);
6回放相关设置问题
6.1回放时间戳
NETDEV_PARSE_VIDEO_DATA_S *pstParseVideoData
INT64 tTimeStamp; /* 时间戳(毫秒) Time stamp (ms) */
保存了PTS信息,可以用来计算当前回放时间
由于获取不到真实的帧率,目前都是采用25fps
6.2回放设置速度问题
tagNETDEVVodPlayStatus tagStatus = NETDEV_PLAY_STATUS_1_FORWARD;
bool bRet = NETDEV_PlayBackControl((LPVOID)id->handle, NETDEV_PLAY_CTRL_SETPLAYSPEED, &tagStatus);
回放开始以后,立刻调用速度设置会导致播放画面从0点开始,因此需要延时1秒,然后才开始调用该接口
7 NETDEV_PTZ_STATUS_S
11)NETDEVSDK_Win32_V1.8.0.1和NETDEVSDK_Win32_V2.5.0.0,两个版本的云台状态查询接口不同,但是参数中传递云台状态结构体不变,通过在SDK文档中查看调用NETDEV_PTZ_STATUS_S结构体的函数,确定好相应的接口
1.8.0.1版本接口:NETDEV_GetDevConfig
2.5.0.0版本接口:NETDEV_PTZGetStatus
8 SDK取流失败排查
相同的产品型号:HIC5641,通过2.1和2.5版本的SDK demo都是同样的效果,登陆设备成功,点击异常摄像机的时候,没有任何打印
正常播放软件版本:QIPC-B6301.7.2.201010 异常播放软件版本:QIPC-B6301.6.11.200810
解决方案
1)通过其他方式取流,例如IMOS或者RTSP取流
2)联系厂商升级摄像机软件版本
9 RTSP URL字符串
rtsp://admin:admin@192.168.8.8:554/video1 //主码流
rtsp://admin:admin@192.168.8.8:554/video2 //子码流
rtsp://admin:admin@192.168.8.8:554/video3 //第三码流
10 RTSP 中SDP描述
v=0
o=- 1001 1 IN IP4 192.168.18.100
s=VCP IPC Realtime stream
m=video 0 RTP/AVP 105
c=IN IP4 192.168.18.100
a=control:rtsp://192.168.18.100/media/video1/video
a=rtpmap:105 H264/90000
a=fmtp:105 profile-level-id=64002a; packetization-mode=1; sprop-parameter-sets=Z2QAKq2EAQwgCGEAQwgCGEAQwgCEO1A8ARPyzcBAQFAAAD6AAAw1CEA=,aO4xshs=
a=recvonly
m=application 0 RTP/AVP 107
c=IN IP4 192.168.18.100
a=control:rtsp://192.168.18.100/media/video1/metadata
a=rtpmap:107 vnd.onvif.metadata/90000
a=fmtp:107 DecoderTag=h3c-v3 RTCP=0
a=recvonly
SETUP rtsp://192.168.18.100/media/video1/video RTSP/1.0
CSeq: 5
Authorization: Digest username="admin", realm="48ea63829fd0", nnotallow="1566412173821714612613117617111186614948", uri="rtsp://192.168.18.100:554/media/video1", respnotallow="b8465758d21b5643afb215c245211349"
User-Agent: LibVLC/2.2.4 (LIVE555 Streaming Media v2016.02.22)
Transport: RTP/AVP;unicast;client_port=52026-52027
11 海康宇视SDK头文件冲突
error C2059: 语法错误:“常量”解决方案
场景
添加海康,宇视SDK对接的头文件和库文件,编译出错提示error C2059: 语法错误:“常量”。显示宇视SDK头文件NetDEVSDK.h中宏定义异常
typedef enum tagNETDEV_PASSIVEDECODE_CMD
{
PASSIVE_DEC_PAUSE = 1, /* 被动解码暂停(仅文件流有效) */
PASSIVE_DEC_RESUME = 2, /* 恢复被动解码(仅文件流有效) */
PASSIVE_DEC_FAST = 3, /* 快速被动解码(仅文件流有效) */
PASSIVE_DEC_SLOW = 4, /* 慢速被动解码(仅文件流有效) */
PASSIVE_DEC_NORMAL = 5, /* 正常被动解码(仅文件流有效) */
PASSIVE_DEC_ONEBYONE = 6, /* 被动解码单帧播放(保留) */
PASSIVE_DEC_AUDIO_ON = 7, /* 音频开启 */
PASSIVE_DEC_AUDIO_OFF = 8, /* 音频关闭 */
PASSIVE_DEC_RESETBUFFER = 9 /* 清空缓冲区 */
}NETDEV_PASSIVEDECODE_CMD_E;
NetDEVSDK.h(5082): error C2059: 语法错误:“常量”
NetDEVSDK.h(5091): error C2143: 语法错误: 缺少“;”(在“}”的前面)
鼠标放在PASSIVE_DEC_PAUSE,看到错误提示:#define PASSIVE_DEC_PAUSE 1
排查过程
在Notepad++对整个工程目录进行宏定义搜索PASSIVE_DEC_PAUSE,发现在海康的头文件中已有定义HCNetSDK.h
#define PASSIVE_DEC_PAUSE 1 /*被动解码暂停(仅文件流有效)*/
#define PASSIVE_DEC_RESUME 2 /*恢复被动解码(仅文件流有效)*/
#define PASSIVE_DEC_FAST 3 /*快速被动解码(仅文件流有效)*/
#define PASSIVE_DEC_SLOW 4 /*慢速被动解码(仅文件流有效)*/
#define PASSIVE_DEC_NORMAL 5 /*正常被动解码(仅文件流有效)*/
#define PASSIVE_DEC_ONEBYONE 6 /*被动解码单帧播放(保留)*/
#define PASSIVE_DEC_AUDIO_ON 7 /*音频开启*/
#define PASSIVE_DEC_AUDIO_OFF 8 /*音频关闭*/
#define PASSIVE_DEC_RESETBUFFER 9 /*清空缓冲区*/
所以才会出现上面的提示错误
解决方案
在宇视SDK头文件中没有搜索到NETDEV_PASSIVEDECODE_CMD_E宏定义的使用,因此,直接注释掉整个宏定义解决问题
12 CentOS x86架构对接
SDK版本
NETDEVSDK_Linux64_V2.6.0.0
操作系统
[root@localhost NETDEVSDK_Linux64_V2.6.0.0]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[root@localhost NETDEVSDK_Linux64_V2.6.0.0]# uname -a
Linux localhost.localdomain 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
编译文件排布
[root@localhost NETDEVSDK_Linux64_V2.6.0.0]# ls
demo doc include lib test.cpp
代码
#include <iostream>
#include <string>
#include <stdlib.h>
#include "NetDEVSDK.h"
int main()
{
bool bRet = NETDEV_Init();
if (bRet)
{
std::cout << "load sdk success" << std::endl;
}
else
{
std::cout << "load sdk failed" << std::endl;
return -1;
}
tagNETDEVDeviceInfo devInfo = { 0 };
LPVOID pUserHandle = NETDEV_Login((char *)"192.168.11.200", 80, (char *)"admin", (char *)"admin12345", &devInfo);
if (NULL == pUserHandle)
{
std::cout << "login failed,error:" << NETDEV_GetLastError() << std::endl;
return -1;
}
NETDEV_PTZ_STATUS_S ptzStatus = { 0 };
bRet = NETDEV_PTZGetStatus(pUserHandle, 1, &ptzStatus);
if (!bRet)
{
std::cout << "query gis failed,error:" << NETDEV_GetLastError() << std::endl;
return -1;
}
else
{
std::cout << "P:" << ptzStatus.fPanTiltX << std::endl;
std::cout << "T:" << ptzStatus.fPanTiltY << std::endl;
std::cout << "Z:" << ptzStatus.fZoomX << std::endl;
}
return 0;
}
编译脚本
g++ test.cpp -I ./include -L ./ -L ./lib -lNetDEVSDK -lmxml -Wl,-rpath=./
问题
1)libmxml.so.1: cannot open shared object file
mv libmxml.so libmxml.so.1
2)libNetDiscovery.so: cannot open shared object file
将lib文件中的所有文件拷贝到跟执行文件a.out同一级目录
13 宇视DEMO预览版本
2.0版本在没有GPU服务器上预览花屏
2.6版本已经修复该问题