onvifonvif2.0中文协议原版怎么开发

博客访问: 2752561
博文数量: 824
博客积分: 13014
博客等级: 上将
技术积分: 10319
注册时间:
认证徽章:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
onvif实现功能和经验
1) 设备匹配probe消息
SOAP_FMAC5 int SOAP_FMAC6
soap_serve___dndl__Probe(struct soap *soap)
把soap_put_d__ProbeMatchesType(soap,
&dn__ProbeResponse, "dn:ProbeResponse", NULL) 改成soap_put_d__ProbeMatchesType(soap,
&dn__ProbeResponse, "d:ProbeMatches", NULL)
2) 由analytics.wsdl ptz.wsdl devicemgmt.wsdl media.wsdl event.wsdl 生成头文件,在头文件中要加#import "import/wsse.h" ,为了实现安全接口
3) 安全验证用户
SOAP_FMAC3 int SOAP_FMAC4
soap_out_SOAP_ENV__Header(struct soap *soap, const char *tag, int id, const
struct SOAP_ENV__Header *a, const char *type)
soap-&mustUnderstand = 1;
(soap_out_PointerTo_wsse__Security(soap, "wsse:Security", -1,
&a-&wsse__Security, ""))
&&&&&&&&&&&&& return
改为soap-&mustUnderstand
(soap_out_PointerTo_wsse__Security(soap, "wsse:Security", -1,
&a-&wsse__Security, ""))
&&&&&&&&&&&&& return
4) 生成.c文件
D:\onvif&soapcpp2 -2 -c -x -L -pws -I
D:\gsoap-2.8\d:\gsoap-2.8/gsoap/import/ ws.h
其中-2参数是选择onvif 1.2 版本, 如果选择-1消息通知就无法被onvif测试工具识别
5) 生成.c后缀名的文件全部改成.cpp文件
6) onvif要生成客户和服务端, 客户端主要是用来发送hello消息和消息通知接口
7) 生成头文件
D:\onvif&wsdl2h.exe –c -o ws.h -t typemap.dat -s
analytics.wsdl ptz.wsdl devicemgmt.wsdl media.wsdl event.wsdl
remotediscovery.wsdl imaging.wsdl
要在ws.h文件中增加 #import
"import/wsse.h" 这表明是安全接口
8) soapcpp2生成数个.nsmp命名空间文件,只需要用其中一个就可以(我们使用的EventBinding.nsmap)
9) 开发人员只需关注wsClient.c, wsServer.c这两个文件,可对他进行修改
10) 通过wsdl2h.exe –c -o ws.h -t typemap.dat -s analytics.wsdl ptz.wsdl devicemgmt.wsdl
media.wsdl event.wsdl remotediscovery.wsdl imaging.wsdl 会报错误,不影响开发.
&11) 设备发现的soap初试化必为 下列代码
& &soap_init1(&m_soap_entry,
SOAP_IO_UDP | SOAP_XML_IGNORENS);
struct ip_
imreq.imr_multiaddr.s_addr =inet_addr(MULTI_GROUPID);
imreq.imr_address.s_addr = htonl(INADDR_ANY);
imreq.imr_ifindex= 2;
m_soap_entry.version = 2;
m_soap_entry.send_timeout = 3; // 1s timeout
m_soap_entry.recv_timeout = 3; // 1s timeout
if (!soap_valid_socket(soap_bind(&m_soap_entry, NULL, )))
DEBUG_OUTPUT4("CDiscovery::Init soap_valid_socket error");
DEBUG_OUTPUT4("CDiscovery::Init soap_valid_socket success");
if (setsockopt(m_soap_entry.master, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&imreq, sizeof(imreq))&0)
DEBUG_OUTPUT4("CDiscovery::Init setsockopt IP_ADD_MEMBERSHIP
12) hello 消息发送必须为
& & & & struct soap *
tsoap = soap_copy(&m_soap_entry);
Hello(tsoap, endpointReference);
if (soap_connect(soap, soap_endpoint,
soap_action)
&&&&&& &|| soap_envelope_begin_out(soap)
&&&&&& &|| soap_putheader(soap)
&&&&&& &|| soap_body_begin_out(soap)
&&&&&& &|| soap_put___dnrd__Hello(soap,
&soap_tmp___dnrd__Hello, "-dnrd:Hello", NULL)
&&&&&& &|| soap_body_end_out(soap)
&&&&&& &|| soap_envelope_end_out(soap)
&&&&&& &|| soap_end_send(soap))
&&&&&&&&&&&&& return
soap_closesock(soap);
(soap_connect(soap, NULL, soap_action))
&&&&&&&&&&&
return soap_closesock(soap);
}&&&&&&&&&&&&&&&&&&
soap_set_endpoint(soap, soap_endpoint);
soap-&error = SOAP_OK;
struct sockaddr_
peer.sin_family=AF_INET;
peer.sin_port=htons(soap-&port);
&&peer.sin_addr.s_addr=inet_addr(soap-&host);
memcpy(&soap-&peer, &peer, sizeof(sockaddr_in));
soap-&peerlen = sizeof(peer);
if(soap_envelope_begin_out(soap)
&&&&&&&&&&&&&&& || soap_putheader(soap)
&&&&&&&&&&&&&&& || soap_body_begin_out(soap)
&&&&&&&&&&&&&&& || soap_put___dnrd__Hello(soap,
&soap_tmp___dnrd__Hello, "-dnrd:Hello", NULL)
&&&&&&&&&&&&&&& || soap_body_end_out(soap)
&&&&&&&&&&&&&&& || soap_envelope_end_out(soap)
&&&&&&&&&&&&&&& || soap_end_send(soap))
&&&&&&&&&&&
return soap_closesock(soap);
13) 开发人员要实现服务端所有接口,下面是部分接口(请参考wsClient.cpp 文件
SOAP_FMAC5 int SOAP_FMAC6
__dndl__Probe(struct soap*, struct d__ProbeType *dn__Probe, struct d__ProbeMatchesType
*dn__ProbeResponse);
SOAP_FMAC5 int SOAP_FMAC6
__dnrd__Hello(struct soap*, struct d__HelloType *dn__Hello, struct
d__ResolveType *dn__HelloResponse);
SOAP_FMAC5 int SOAP_FMAC6
__dnrd__Bye(struct soap*, struct d__ByeType *dn__Bye, struct d__ResolveType
*dn__ByeResponse);
14) 安全用户名和密码是采用openssl库和gsoap的自带的控件, 采用下列接口
soap_wsse_verify_Password
soap_wsse_verify_Timestamp
soap_wsse_get_Username
15) openssl 编译
tar zxvf openssl-0.9.8.tar.gz
cd openssl-0.9.8
./config no-asm --prefix=/opt/openssl os/compiler: /ToolChain/bin/
arm-none-linux-gnueabi-g++
make install
之后进入到/opt/openssl 拷贝头文件和库
16) 通过80端口发送流
首先要判断消息是onvif消息还是请求流消息, 通过MSG_PEEK来区分
如果是onvif消息就走onvif信令,否则走播流通道
&Onvif已经实现功能
设备发送hello消息
设备接收hello消息
设备发现匹配相应
获取设备信息
设置系统时间
获取系统时间
软件出厂默认值恢复
系统重新启动
获取wsdlurl
获取所有能力集
获取设备能力集
获取事件能力集
获取图象能力集
获取媒体能力集
获取主机名字
设置主机名
获取网络接口信息
设置网络接口信息
获取网络协议
阅读(17934) | 评论(1) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
hello消息的修改不明白,不是UDP报文吗?为什么改成这个样子?另外想问下,我现在hello包可以发出,但是test工具测试的时候总是报收包失败,我抓包看过了3702端口的组播包发出来了,请问楼主有遇到这种情况吗?谢谢
请登录后评论。工具类服务
编辑部专用服务
作者专用服务
基于ONVIF协议的网络视频监控系统的开发与实现
随着智慧城市的建设和不断发展,社会环境变得日益复杂,视频监控系统将更广泛的应用到更多的场所,接入的视频监控设备也变得多种多样。然而由于大多数安防厂商都采用自己的私有协议,造成网络视频产品之间无法实现互联互通。同时传统的方法在管理和维护大量多样的终端设备上变得越发困难。  本文开发与实现的视频监控系统在基于ONVIF协议的基础上实现对终端视频监控设备的管理,使得不同厂商所生产的网络视频产品完全互通。本文在创新点上主要有以下三点:  (1)实现ONVIF协议重要功能,完成对终端视频设备的管理,解决了传统方法对网络视频产品管理不便的问题,并对相应功能封装成动态库的形式,使得用户无需了解ONVIF协议也可以完成相关工作。  (2)针对业界普遍采用特定的专业硬件来实现视频监控多画面显示和OSD叠加功能显示的情况,本文研究并提出了一种自定义的ActiveX视频播放控件,该控件支持多画面显示,具有自适应调整分辨率的功能,同时还支持全屏状态切换、窗口拖拽移动以及移动侦测区域绘制等功能。与依赖硬件实现的方案相比,该视频播放ActiveX控件在操作便捷性及低成本控制上都有很大的提升,并且在画面显示效果上也有不错的表现,适用于家庭用户使用。  (3)提出采用注册回调函数的方式进行媒体流数据的分发,完成视频截图录像等功能,通过在ActiveX控件上自定义绘制移动侦测区域并将视频监控与移动侦测算法相结合进行移动侦测告警测试,向智能视频监控研究工作迈出了一小步。  本文的主要研究工作如下:  1、本文首先对视频监控相关技术进行了简单的叙述,在完成系统需求分析的前提下给出了系统的整体设计方案。随后进行系统模块的具体开发,在基于gSOAP的基础上开发出WebService通信框架,实现了设备发现和设备管理两大功能。  2、通过构建RTSP会话过程完成媒体流数据的传输,并使用FFmpeg编解码解决方案完成对媒体流数据的解码及相应处理,继而完成视频预览、截图和录像等功能的开发。  3、通过定制基于MFC的ActiveX视频播放控件来实现视频流数据的画面显示,该ActiveX控件支持多画面显示,可以实现对多个视频监控设备的视频预览。同时该控件支持移动侦测区域的绘制,与移动侦测检测算法相结合可以实现移动侦测告警。  4、使用WINGDI+绘图技术完成视频预览画面中OSD字幕的设置和显示,通过MFC编程完成视频监控系统客户端GUI的设计开发工作。  5、对视频监控系统的几个重要模块进行了功能测试。最后,对本文的研究工作进行概括与总结,指出该课题中有待完善的地方,并展望下一步研究方向。
学科专业:
授予学位:
学位授予单位:
导师姓名:
学位年度:
在线出版日期:
本文读者也读过
相关检索词
万方数据知识服务平台--国家科技支撑计划资助项目(编号:2006BAH03B01)(C)北京万方数据股份有限公司
万方数据电子出版社【原创】Linux设备上的Onvif实现18: ONVIF视频监视功能开发问题总结
我的图书馆
【原创】Linux设备上的Onvif实现18: ONVIF视频监视功能开发问题总结
我从去年8月份开始学习ONVIF,经历了各种困难,有时简直要暴走发狂,终于能够达成计划目标,实现了预订功能。痛苦已经过去,现在是写个问题总结的时候了,希望能记录遇到的问题,以便将来遗忘时参考。
测试的摄像头有2种品牌3种型号。分别是海康的2款枪机,DS-2CD3312D-I
台湾升泰科技(AVTECH)的一款家用IPC,AVM311
1 自己编写的服务端收到Probe命令,应答的报文不能被 ONVIFTest识别。
该问题比较奇怪,经过比较正常的应答包和错误包,发现是Header段缺少&wsadis:RelatesTo&内容。OnvifTest发出的probe命令带有MessageID,设备的应答报文必须带有该MessageID,只有一致才认为是正确的匹配。缺少&wsadis:RelatesTo&就导致OnvifTest工具软件无法识别应答命令。
跟踪服务端soap_serve()函数流程,发现问题出在soap_wsa_reply函数。
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/static//
2 客户端发出Probe命令,摄像头应答多次,造成记录的设备列表中重复。
我使用的Probe命令设定的等待时间是5s,在此期间等待摄像头应答,如果没有收到应答包就自动结束。收到应答包后解析出设备名和IP地址添加到设备列表中。实际上发现海康的摄像头只应答一次,升泰科技的摄像头摄像头应答3次。3次应答的MessageID完全相同。
发送的probe MessageID
&wsa:MessageID&e5-11e1-ad77-85ac2d7785ac&/wsa:MessageID&
收到的3次应答MessageID
(1)& &wsa:MessageID&e5-11e1-ad77-85ac2d7785ac&/wsa:MessageID&
&&&&&& &wsa:RelatesTo&e5-11e1-ad77-85ac2d7785ac&/wsa:RelatesTo&
(2)& &wsa:MessageID&e5-11e1-ad77-85ac2d7785ac&/wsa:MessageID&
&&&&&& &wsa:RelatesTo&e5-11e1-ad77-85ac2d7785ac&/wsa:RelatesTo&
(3)& &wsa:MessageID&e5-11e1-ad77-85ac2d7785ac&/wsa:MessageID&
&&&&&& &wsa:RelatesTo&e5-11e1-ad77-85ac2d7785ac&/wsa:RelatesTo&
解决方法是在设备列表中增加UUID字段,添加设备时检查列表中是否存在UUID的设备,不存在就添加,存在就表示已经添加过了,丢弃此次应答包。具体实现时注意字符串比较函数最好使用strstr(),不要使用strcmp(),原因是输入参数可能分别是
urn:uuid:AA9DFBE7--000E5324BB77,
AA9DFBE7--000E5324BB77
这样的话strcmp就会出现错误。
3 &GetCapabilities()函数返回401失败,要求鉴权。
我测试的2种牌子表现不同。海康摄像头直接调用该函数返回正确应答报文。升泰科技的摄像头则返回401错误,必须添加鉴权信息,然后再次调用GetCapabilities()才能正确返回应答报文。
添加鉴权过程研究了一段时间,终于弄明白了使用方法,请看博客原文:
Linux设备上的Onvif实现16:实现Onvif鉴权
http://gaohtao./blog/static//
4 GetProfiles()函数应答多个profile
使用GetProfiles()函数获取媒体信息,结果发现海康摄像头返回2份profile,升泰摄像头返回3份profile。这样在解析数据时出现遗漏错误。经过测试,发现升泰摄像头支持3个通道,这3份profile都是实际可用的,必须予以支持。
解决方法:扩展设备媒体信息数据结构,最多支持3个profile,对于超过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
Accept: application/sdp
User-Agent: ABB Genway E-3000 RTSP 1.0
RTSP/1.0 401 Unauthorized
WWW-Authenticate: Basic realm="Server"
WWW-Authenticate: Digest realm="Server", nonce="50e5d8bff60b6f5b5a85e7a5b613e85e
19512c53defbdfb69d9dd"
有的如下:
RTSP/1.0 401 Unauthorized
WWW-Authenticate: Digest realm="8ce748eafc54", nonce="db83db519a1f658af4a47", stale="FALSE"
WWW-Authenticate: Basic realm="8ce748eafc54"
Date:& Tue, Dec 31 :39 GMT
就是这两种鉴权顺序是反的。不知道是否第一个代表了默认鉴权方式。以前实现了基本认证,后来努力了很久实现了摘要认证,请看博客原文:
Linux设备上的Onvif实现17:实现RTSP摘要认证
&& 有的摄像头Web页面上可以设置鉴权方式(开关、基本、摘要),对应的在自己的RTSP代码中也要使用响应的方式,实例如下:
typedef struct _WWW_Authenticate
& int bA&&&&&&&&&& //认证标记,0=none, 1=basic, 2=digest
&&&&&&&&&&&&&&&&&&&& &&//请求计数
& 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];& //存储完整的认证信息
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;
&&&&&&&& 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
Accept: application/sdp
Authorization: Basic YWRtaW46YWRtaW4=
User-Agent: ABB Genway E-3000 RTSP 1.0
RTSP/1.0 200 OK
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
o=- 1 1 IN IP4 127.0.0.1
s=RTSP server
c=IN IP4 0.0.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 37:Sequence Number
01 5f f7 5c: Timestamp
97 48 1d 18: SSRC ― 同步源标识
78:& 表示STAP-A单一时间组合包,其后实际上包括sps、pps两帧
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单一时间组合包,就是sps、pps两帧数据组合在一个数据包,以前没有实现过这种包的解析,所以无法显示。而海康的摄像头发出的SPS和PPS分别是单独的两个数据包,就能正常解析显示。
解决方法:增加解析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&
&&&&&&&&&&&&&&& */
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&& for(i=13;i&P)
&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&& //内部一帧长度
&&&&&&&&&&&&&&&&&&& 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+
&&&&&&&&&&&&&&&&&&& free(frameBuf);
&&&&&&&&&&&&&&& }&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&&&&&&
&&&&&&&&&&& case 25:& //STAP-B 单一时间的组合包, 没有实现解析
&&&&&&&&&&& case 26:& //MTAP16 多个时间的组合包
&&&&&&&&&&& case 27:& //MTAP24 多个时间的组合包
&&&&&&&&&&& default:
&&&&&&&&&&&&&&& SliceReady=-1;&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&& goto NALU_
9 分机设备打开摄像头,经常收不到摄像头的视频流,这时所有的RTSP命令都返回454错误。
升泰摄像头遇到了这种情况,好好的在自己的设备上监视摄像头成功,停止,再一次监视就无法收到数据流。这时RTSP命令都返回错误。
5& ==================================
PLAY rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0
Authorization: Basic YWRtaW46YWRtaW4=
Session: C3ED883FFE905FEC98DC5B
User-Agent: ABB Genway E-3000 RTSP 1.0
RTSP/1.0 200 OK
Session: C3ED883FFE905FEC98DC5B
6 ==================================
TEARDOWN rtsp://192.168.0.112:540/live/h264_ulaw/VGA RTSP/1.0
Authorization: Basic YWRtaW46YWRtaW4=
Session: 2D50C2A8C72EC5ABFCD26
User-Agent: ABB Genway E-3000 RTSP 1.0
RTSP/1.0 454 Session Not Found
complete recv response, buffer state: offset=43 len=0
rtsp respond code(454) != 200
遇到的问题:停止命令失败,提示会话不存在。
发现真正原因:
接收流程:分机设备向摄像头发送PLAY命令,收到成功应答(200 OK)后才开始建立rtp、rtcp socket连接,接收H264数据流。
分析故障时的网络抓包序列:
Package 26:分机向摄像头发送PLAY命令
Package 28:摄像头应答200 OK
Package 30: 摄像头发出第一个数据包,实际内容就是SPS、PPS的组合包。
Package 32:摄像头发出第二个数据包,内容是I帧。
Package 33:分机应答 Port unreachable,之后摄像头就停止了发送数据。
原因分析:
通过网络上对“Port unreachable”的解释,发现如果摄像头向分机端口发送UDP数据包时,分机端还未能建立RTP/RTCP,就可能出现分机的RTP端口无法接收数据,分机linux系统自动应答ICMP数据包Port unreachable, 该摄像头连续收到2个ICMP包就会中断连接。由于之前SETUP建立的连接被中断,之后分机发送TEARDOWN提示“Session Not Found”。
奇怪的是海康摄像头就不会停止发送数据,也不会中断连接,这样当分机端RTP连接建立成功后就能收到数据包了。
解决方法:
&1 修改流程:分机收到摄像头SETUP成功应答后就要建立UDP接收线程,然后才能发送PLAY请求。
&2 为了确保UDP接收线程中的socket初始化完成后才能发送PlayReq,在IPC_CreateEngineThread线程中使用信号量wait,在RTP_ReciveThread线程中发出post。
这样处理之后分机监视正常,反复操作100次全部成功显示。
TA的最新馆藏[转]&[转]&
喜欢该文的人也喜欢

我要回帖

更多关于 onvif协议 的文章

 

随机推荐