打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【原创】Linux设备上的Onvif实现18: ONVIF视频监视功能开发问题总结

我从去年8月份开始学习ONVIF,经历了各种困难,有时简直要暴走发狂,终于能够达成计划目标,实现了预订功能。痛苦已经过去,现在是写个问题总结的时候了,希望能记录遇到的问题,以便将来遗忘时参考。

测试的摄像头有2种品牌3种型号。分别是海康的2款枪机,DS-2CD3312D-I

台湾升泰科技(AVTECH)的一款家用IPCAVM311

 

1 自己编写的服务端收到Probe命令,应答的报文不能被 ONVIFTest识别。

该问题比较奇怪,经过比较正常的应答包和错误包,发现是Header段缺少<wsadis:RelatesTo>内容。OnvifTest发出的probe命令带有MessageID,设备的应答报文必须带有该MessageID,只有一致才认为是正确的匹配。缺少<wsadis:RelatesTo>就导致OnvifTest工具软件无法识别应答命令。

跟踪服务端soap_serve()函数流程,发现问题出在soap_wsa_reply函数。

main()

soap_serve()

soap_serve_request()

soap_serve___wsdd__Probe()

__wsdd__Probe() wsddapi.c

soap_wsa_reply() wsddapi.c

该函数调用了插件函数soap_lookup_plugin()导致返回值无效,引起提前结束函数。这就引起没有填充Header段的RelatesTo结构体。

现在不清楚soap_lookup_plugin()为什么返回NULL,但是可以把对data的操作搬移到newheader->SOAP_WSA(RelatesTo)之后执行。这样回答的报文中就包含RelatesTo内容了。修改后的soap_wsa_reply()函数请看博客原文:

linux设备上的Onvif 实现5:实现Probe命令检测设备:

http://gaohtao.blog.163.com/blog/static/58241823201362343648345/

 

2 客户端发出Probe命令,摄像头应答多次,造成记录的设备列表中重复。

我使用的Probe命令设定的等待时间是5s,在此期间等待摄像头应答,如果没有收到应答包就自动结束。收到应答包后解析出设备名和IP地址添加到设备列表中。实际上发现海康的摄像头只应答一次,升泰科技的摄像头摄像头应答3次。3次应答的MessageID完全相同。

发送的probe MessageID

<wsa:MessageID>41772060-76e5-11e1-ad77-85ac2d7785ac</wsa:MessageID>

 

收到的3次应答MessageID

1  <wsa:MessageID>41772060-76e5-11e1-ad77-85ac2d7785ac</wsa:MessageID>

       <wsa:RelatesTo>41772060-76e5-11e1-ad77-85ac2d7785ac</wsa:RelatesTo>

2  <wsa:MessageID>41772060-76e5-11e1-ad77-85ac2d7785ac</wsa:MessageID>

       <wsa:RelatesTo>41772060-76e5-11e1-ad77-85ac2d7785ac</wsa:RelatesTo>

3  <wsa:MessageID>41772060-76e5-11e1-ad77-85ac2d7785ac</wsa:MessageID>

       <wsa:RelatesTo>41772060-76e5-11e1-ad77-85ac2d7785ac</wsa:RelatesTo>

解决方法是在设备列表中增加UUID字段,添加设备时检查列表中是否存在UUID的设备,不存在就添加,存在就表示已经添加过了,丢弃此次应答包。具体实现时注意字符串比较函数最好使用strstr(),不要使用strcmp(),原因是输入参数可能分别是

urn:uuid:AA9DFBE7-4359-49D4-000E5324BB77

AA9DFBE7-4359-49D4-000E5324BB77

这样的话strcmp就会出现错误。

 

3  GetCapabilities()函数返回401失败,要求鉴权。

我测试的2种牌子表现不同。海康摄像头直接调用该函数返回正确应答报文。升泰科技的摄像头则返回401错误,必须添加鉴权信息,然后再次调用GetCapabilities()才能正确返回应答报文。

添加鉴权过程研究了一段时间,终于弄明白了使用方法,请看博客原文:

Linux设备上的Onvif实现16:实现Onvif鉴权

http://gaohtao.blog.163.com/blog/static/58241823201383042530402/

 

4 GetProfiles()函数应答多个profile

使用GetProfiles()函数获取媒体信息,结果发现海康摄像头返回2profile,升泰摄像头返回3profile。这样在解析数据时出现遗漏错误。经过测试,发现升泰摄像头支持3个通道,这3profile都是实际可用的,必须予以支持。

解决方法:扩展设备媒体信息数据结构,最多支持3profile,对于超过3个的profile丢弃不处理。

<tt:VideoSourceConfiguration token="VS1token">

        <tt:Name>VS1</tt:Name>

        <tt:UseCount>3</tt:UseCount>

        <tt:SourceToken>VS1srctoken</tt:SourceToken>

        <tt:Bounds height="240" width="352" y="0" x="0"></tt:Bounds>

       

主通道:PROFILE-1

  分辨率  Width=1280, Height=720

  帧率    FrameRateLimit=30

  码率    BitrateLimit=5000        

  编码    Encoding=H264

 

子通道 PROFILE-2

  分辨率  Width=640, Height=480      设置正确的参数: 640x480

  帧率    FrameRateLimit=30                       25

  码率    BitrateLimit=5000                       1536

  编码    Encoding=MPEG4                          H264

 

子通道 PROFILE-3

  分辨率  Width=320, Height=240

  帧率    FrameRateLimit=30

  码率    BitrateLimit=5000

  编码    Encoding=H264

5 修改摄像头的视频配置参数,命令应答成功,实际无效。

ONVIF协议的一个突出优点是可以使用命令修改摄像头的配置参数SetVideoEncoderConfiguration(),我就使用这个功能,把摄像头的视频流修改成我方设备支持的类型,结果海康摄像头工作正确,升泰摄像头命令应答成功,但是实际上摄像头参数根本没有修改。

解决方法: 与台湾升泰公司的工程师联系,对方测试了这种情况,提供了摄像头的升级固件,更新后该问题解决。

6 RTSP鉴权的2种方式

RTSP协议中规定了2种鉴权方式,分别是基本认证(basic authentication)、摘要认证(digest authentication)。测试摄像头发现,有的摄像头应答DESCRIBE命令如下:

DESCRIBE rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0

CSeq: 2

Accept: application/sdp

User-Agent: ABB Genway E-3000 RTSP 1.0

 

RTSP/1.0 401 Unauthorized

CSeq: 2

WWW-Authenticate: Basic realm="Server"

WWW-Authenticate: Digest realm="Server", nonce="50e5d8bff60b6f5b5a85e7a5b613e85e

19512c53defbdfb69d9dd2739877cc82"

 

有的如下:

RTSP/1.0 401 Unauthorized

CSeq: 5

WWW-Authenticate: Digest realm="8ce748eafc54", nonce="db83d3233626b950b519a1f658af4a47", stale="FALSE"

WWW-Authenticate: Basic realm="8ce748eafc54"

Date:  Tue, Dec 31 2013 11:55:39 GMT

 

就是这两种鉴权顺序是反的。不知道是否第一个代表了默认鉴权方式。以前实现了基本认证,后来努力了很久实现了摘要认证,请看博客原文:

Linux设备上的Onvif实现17:实现RTSP摘要认证

http://gaohtao.blog.163.com/blog/static/58241823201422711841555/

 

   有的摄像头Web页面上可以设置鉴权方式(开关、基本、摘要),对应的在自己的RTSP代码中也要使用响应的方式,实例如下:

typedef struct _WWW_Authenticate

{   

  int bAuthenticate;           //认证标记,0=none, 1=basic, 2=digest

  int nc;                      //请求计数

  char realm[MAXPATH];         //认证的领域

  char nonce[MAXPATH];         //服务器密码随机数

  char cnonce[MAXPATH];        //客户端密码随机数

  char qop[MAXPATH];           //保护质量 

  char username[MAXPATH];      //用户名

  char password[MAXPATH];      //密码

  char uri[MAXPATH];           //uri

  char method[MAXPATH];        //method

  char response[MAXPATH];      //摘要 

  char opaque[MAXPATH];        // ??  ,用于客户端对服务端认证 

 

  char Authenticate[2*MAXPATH];  //存储完整的认证信息

}WWW_Authenticate;

 

if(ret == 401)

{

     ret =simple_parse_www_authenticate(resp.www_authenticate1,resp.www_authenticate2);

     if(count<=0)

     {

         if(ret==0) //WWW-Authenticate: Basic

         {

             rtsp_client->wwwAuthenticate.bAuthenticate = 1;                           

         }               

         else if(ret==1)  //WWW-Authenticate: Digest

         {                   

             rtsp_client->wwwAuthenticate.bAuthenticate = 2;

             ParseDigestAuthenticateInfo(rtsp_client, resp.www_authenticate1, resp.www_authenticate2);

         }

         clear_response(&resp);

         count++;

         goto AUTHENTICATE;

    }

    else

    {

         RTSP_ALERT("--ERROR: not support www_authenticate! \n");

    }

}

 

if(rtsp_client->wwwAuthenticate.bAuthenticate)

    {

        if(rtsp_client->wwwAuthenticate.bAuthenticate==2)

        {

            memset(rtsp_client->wwwAuthenticate.method, 0, MAXPATH);

            strcpy(rtsp_client->wwwAuthenticate.method, "DESCRIBE");

 

            memset(rtsp_client->wwwAuthenticate.uri, 0, MAXPATH);

            strcpy(rtsp_client->wwwAuthenticate.uri, rtsp_client->url);

            CreateDigestAuthenticate(rtsp_client,(u_char*)username,strlen(username));

        }

        else if(rtsp_client->wwwAuthenticate.bAuthenticate==1)

        {

            CreateBasicAuthenticate(rtsp_client,(u_char*)username,strlen(username));

        }

       

        cmd.authorization = malloc(2*MAXPATH);

        memset(cmd.authorization, 0, 2*MAXPATH);

        strncpy(cmd.authorization, rtsp_client->wwwAuthenticate.Authenticate, 2*MAXPATH);

}

 

7 DESCRIBE命令应答解析

DESCRIBE rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0

CSeq: 3

Accept: application/sdp

Authorization: Basic YWRtaW46YWRtaW4=

User-Agent: ABB Genway E-3000 RTSP 1.0

 

RTSP/1.0 200 OK

CSeq: 3

Content-Base: rtsp://192.168.0.112:540/live/h264_ulaw/VGA/

Content-Type: application/sdp

Cache-Control: must-revalidate

x-Accept-Dynamic-Rate: 1

x-Accept-Dynamic-Rasave exit: isCheckpointed 1

te: 1 [not processing]

Content-Length: 305

response body length=305, current buffer size=305, offset=198

v=0

o=- 1 1 IN IP4 127.0.0.1

s=RTSP server

c=IN IP4 0.0.0.0

t=0 0

a=control:*

a=range:npt=now-

m=video 0 RTP/AVP 97

a=rtpmap:97 H264/90000

a=fmtp:97 packetization-mode=1;profile-level-id=420028;sprop-parameter-sets=Z0IAKOkBQHsg,aM4xUg==;

a=control:track1

m=audio 0 RTP/AVP 0

a=control:track3

v-media = video

 

问题: 其中a=control:track1 升泰摄像头数据与海康摄像头不一致,引起通道参数错误。

 海康的应答结果有2种:

   a=control:trackID=1   相对路径

   a=control:rtsp://...    绝对路径

  

解决方法:由于a=control:字段内容不规范,为了通用考虑,不能检查control是否含有track/trackID,直接判断是否含有”rtsp://…”

 

8 RTSP 发送的H264数据流无法解析显示。

调试升泰摄像头遇到接收到的H264数据流无法解码显示,对H264的数据包进行了深入分析:

接收到的第一个数据包:

--len=43    80 e1 49 37 01 5f f7 5c 97 48 1d 18 78 00 16 67 42 00 1e e9 01 40 7b 5c 48 00 6d dd 00 0c df e6 00 d8 81 09 40 00 04 68 ce 31 52 

解析如下:

80 cc(b4~b7)=0指示后面的CSRC个数=0,就是无CSRC

e1 Marker(b0)=1,  payload type(b1~b7)=0x61

49 37Sequence Number

01 5f f7 5c: Timestamp

97 48 1d 18: SSRC 同步源标识

78表示STAP-A单一时间组合包,其后实际上包括spspps两帧

00 16 67 42 00 1e e9 01 40 7b 5c 48 00 6d dd 00 0c df e6 00 d8 81 09 40  sps 长度=0x0016

00 04 68 ce 31 52    pps 长度=0x0004

 

这里新遇到了STAP-A单一时间组合包,就是spspps两帧数据组合在一个数据包,以前没有实现过这种包的解析,所以无法显示。而海康的摄像头发出的SPSPPS分别是单独的两个数据包,就能正常解析显示。

解决方法:增加解析STAP-A

/* -----------------  处理一包是多帧------------------  */

    if(24<=NALU_parload && NALU_parload<=27)

    {

        switch(NALU_parload)

        {

            case 24:  //STAP-A 单一时间的组合包

            {

                /* 带有rtp包头的数据内容示例 :     只包含sps/pps两帧

                   80 e1 49 37 01 5f f7 5c 97 48 1d 18    78 00 16 67 42 00 1e e9 01 40 7b 5c 48 00 6d dd 00 0c df e6 

                */

                int i;               

                for(i=13;i<Packlength;)

                {

                    int len;   //内部一帧长度

                    len = (RtpPackage[i]<<8)+RtpPackage[i+1];

                    char * frameBuf= (char *)malloc(len);

                    memset(frameBuf,0, len);

                    memcpy(frameBuf,RtpPackage+i+2,len);

                    OSA_DBG_MSG(" ReciveRTPPackage()  STAP-A: frame len=%d  \n",len);

                   

                    DoH264SinglePackage(frameBuf,len);

                    i= i+2+len;

                    free(frameBuf);

                }              

            }

            break;

 

            case 25:  //STAP-B 单一时间的组合包, 没有实现解析

            case 26:  //MTAP16 多个时间的组合包

            case 27:  //MTAP24 多个时间的组合包

            default:

                SliceReady=-1;                    

                break;           

        }

        goto NALU_end;

    }

 

9 分机设备打开摄像头,经常收不到摄像头的视频流,这时所有的RTSP命令都返回454错误。

升泰摄像头遇到了这种情况,好好的在自己的设备上监视摄像头成功,停止,再一次监视就无法收到数据流。这时RTSP命令都返回错误。

 

5  ==================================

PLAY rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0

CSeq: 5

Authorization: Basic YWRtaW46YWRtaW4=

Session: C3ED883FFE905F1816A2D1EC98DC5B

User-Agent: ABB Genway E-3000 RTSP 1.0

 

RTSP/1.0 200 OK

CSeq: 5

Session: C3ED883FFE905F1816A2D1EC98DC5B

 

6 ==================================

TEARDOWN rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0

CSeq: 6

Authorization: Basic YWRtaW46YWRtaW4=

Session: 2D50C2A8C72EC5AB5605D6906FCD26

User-Agent: ABB Genway E-3000 RTSP 1.0

 

RTSP/1.0 454 Session Not Found

CSeq: 6

complete recv response, buffer state: offset=43 len=0

rtsp respond code(454) != 200

 

遇到的问题:停止命令失败,提示会话不存在。

 

2014-3-11 发现真正原因:

接收流程:分机设备向摄像头发送PLAY命令,收到成功应答(200 OK)才开始建立rtprtcp socket连接,接收H264数据流。

分析故障时的网络抓包序列:

Package 26:分机向摄像头发送PLAY命令

Package 28:摄像头应答200 OK

Package 30: 摄像头发出第一个数据包,实际内容就是SPSPPS的组合包。

Package 32:摄像头发出第二个数据包,内容是I帧。

Package 33:分机应答 Port unreachable,之后摄像头就停止了发送数据。

 

原因分析:

通过网络上对“Port unreachable”的解释,发现如果摄像头向分机端口发送UDP数据包时,分机端还未能建立RTP/RTCP,就可能出现分机的RTP端口无法接收数据,分机linux系统自动应答ICMP数据包Port unreachable, 该摄像头连续收到2ICMP包就会中断连接。由于之前SETUP建立的连接被中断,之后分机发送TEARDOWN提示“Session Not Found”。

奇怪的是海康摄像头就不会停止发送数据,也不会中断连接,这样当分机端RTP连接建立成功后就能收到数据包了。

 

解决方法:

 1 修改流程:分机收到摄像头SETUP成功应答后就要建立UDP接收线程,然后才能发送PLAY请求。

 2 为了确保UDP接收线程中的socket初始化完成后才能发送PlayReq,在IPC_CreateEngineThread线程中使用信号量wait,在RTP_ReciveThread线程中发出post

这样处理之后分机监视正常,反复操作100次全部成功显示。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
ONVIF协议网络摄像机(IPC)客户端程序开发(5):门外汉理解ONVIF协议
大华网络摄像头ip搜索工具
安防再升级 华创4K监控 西数紫盘安装全过程
家庭安防监控系统搭建全流程攻略
onvif是啥?海康录像机如何通过Onvif协议添加其他品牌的摄像头?
RTSP的www-Authenticate认证
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服