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交互过程中,出错了

对接宇视网络摄像机SDK_宇视 SDK 对接

 设备返回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版本已经修复该问题