ONVIFclient搜索设备获取rtsp解决开发笔记(精华文章)
总结:
文章仅仅讲述了比較重要或其它博文没有讲述的开发点,具体能够參考文末參考文章。最后,能获得rtsp地址之后。然后去做其它功能比方录像,ptz这些就很得心应手了。本文出自CSDN-固本培元 ,转载注明出自:leolupy@gmail.com。
前言及鸣谢:
感谢guog先生,快活林高先生,onvif全国交流群的的酷夏先生在开发过程中给予的巨大支持,没有你们的帮助开发过程将异常艰难啊。谢谢了。
ONVIF介绍:
流程总览:
搜索:Probe: 发现网络摄像头,获取webserver地址
http://192.168.15.240/onvif/device_service
能力获取:GetCapabilities:获取设备能力文件,从中识别出媒体信息地址URI: http://192.168.15.240/onvif/Media
媒体信息获取:GetProfiles: 获取媒体信息文件,识别主通道、子通道的视频编码分辨率
RTSP地址获取:GetStreamUri:获取指定通道的流媒体地址 rtsp://192.168.15.240:554/Streaming/Channels/2?transportmode=unicast
Gsoap及开发框架生成:
命令:
wsdl2h -o onvif.h -c -s -t ./typemap.dat devicemgmt.wsdl media.wsdl event.wsdl display.wsdl deviceio.wsdl imaging.wsdl ptz.wsdl receiver.wsdl recording.wsdl search.wsdl remotediscovery.wsdl replay.wsdl analytics.wsdl analyticsdevice.wsdl actionengine.wsdl accesscontrol.wsdl doorcontrol.wsdl
离线文件在:
wsdl2h -o onvif.h -c -s -t ./typemap.dat http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl http://www.onvif.org/onvif/ver10/display.wsdl http://www.onvif.org/onvif/ver10/deviceio.wsdl http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl http://www.onvif.org/onvif/ver10/receiver.wsdl http://www.onvif.org/onvif/ver10/recording.wsdl http://www.onvif.org/onvif/ver10/search.wsdl http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl http://www.onvif.org/onvif/ver10/replay.wsdl http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl http://www.onvif.org/onvif/ver10/analyticsdevice.wsdl http://www.onvif.org/ver10/actionengine.wsdl http://www.onvif.org/ver10/pacs/accesscontrol.wsdl http://www.onvif.org/ver10/pacs/doorcontrol.wsdl
(记得拷贝gsoap的typemap文件至生成文件夹下,wsdl2h命令须要这个。)
wsdl2h -o onvif.h -c -s -t ./typemap.dat devicemgmt.wsdl media.wsdl event.wsdl display.wsdl deviceio.wsdl imaging.wsdl ptz.wsdl receiver.wsdl recording.wsdl search.wsdl remotediscovery.wsdl replay.wsdl analytics.wsdl analyticsdevice.wsdl actionengine.wsdl accesscontrol.wsdl doorcontrol.wsdl
如今能够開始生成了:例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3ViZW5wZWl5dWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
假设直接生成相应C的库文件会发生反复定义错误,能够改动该文件。
wsa5.h(288): **ERROR**: remote method name clash: struct/class 'SOAP_ENV__Fault' already declared at line 274
打开文件gsoap_2.8.16/gsoap-2.8/gsoap/import/ wsa5.h
将277行int SOAP_ENV__Fault改动为int SOAP_ENV__Fault_alex
笔者没有使用这样的方法,是将这个结构体直接凝视的方式,最后的结果是,都能够使用。
同一时候上一步生成的onvif.h文件里没有打开wsse.h, 导致最后生成代码中SOAP_ENV__Header 结构体中缺少定义 wsse__Security数据段,无法进行鉴权命令。
即:加入对openssl的支持,在上一步生成的onvif.h中加入(可选)
- #import "wsse.h"
随后使用命令生成:
soapcpp2 -c onvif.h -x -I/root/Tools/Gsoap/gsoap-2.8/gsoap/import -I/root/Tools/Gsoap/gsoap-2.8/gsoap/ -I/root/Tools/Gsoap/gsoap-2.8/gsoap/custom -I/root/Tools/Gsoap/gsoap-2.8/gsoap/extras -I/root/Tools/Gsoap/gsoap-2.8/gsoap/plugin
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ3ViZW5wZWl5dWFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
到此为止,基于 C 的client和server的Onvif开发框架及已经搭建完毕。
设备搜索原理及编程技巧:
參考代码:
struct soap* NewSoap(struct SOAP_ENV__Header *header,struct soap* soap,
wsdd__ProbeType *req_,
wsdd__ScopesType *sScope_)
{
soap = soap_new();
if(NULL == soap )
{
printf("sopa new error\r\n");
return NULL;
} soap->recv_timeout = 5;
soap_set_namespaces(soap, namespaces); soap_default_SOAP_ENV__Header(soap, header); uuid_t uuid;
char guid_string[100];
uuid_generate(uuid);
uuid_unparse(uuid, guid_string); header->wsa__MessageID = guid_string;
header->wsa__To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
header->wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
soap->header = header; soap_default_wsdd__ScopesType(soap, sScope_);
sScope_->__item = "";
soap_default_wsdd__ProbeType(soap, req_);
req_->Scopes = sScope_;
req_->Types = ""; //"dn:NetworkVideoTransmitter"; return soap ;
}
int i = 0;
result = soap_send___wsdd__Probe(soap, MULTICAST_ADDRESS, NULL, &req); while(result == SOAP_OK)
{
result = soap_recv___wsdd__ProbeMatches(soap, &resp);
if(result == SOAP_OK)
{
if(soap->error)
{
printf("soap error 1: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error;
}
else
{
printf("Onvif Device detected *********************************************\r\n");
for(i = 0; i < resp.wsdd__ProbeMatches->__sizeProbeMatch; i++)
{
printf("__sizeProbeMatch : %d\r\n", resp.wsdd__ProbeMatches->__sizeProbeMatch);
printf("wsa__EndpointReference : %p\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference);
printf("Target EP Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address);
printf("Target Type : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Types);
printf("Target Service Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->XAddrs);
printf("Target Metadata Version : %d\r\n", resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion);
if(resp.wsdd__ProbeMatches->ProbeMatch->Scopes)
{
printf("Target Scopes Address : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item);
}
}
break;
}
}
else if (soap->error)
{
printf("[%d] soap error 2: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error;
}
}
设备鉴权:
soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);
原理也非常easy明确事实上,就是讲http的soap消息增加相应header中xml的元素而已。然后敏感消息digest MD5加密编码。
获取能力:
void UserGetCapabilities(struct soap *soap ,struct __wsdd__ProbeMatches *resp,
struct _tds__GetCapabilities *capa_req,struct _tds__GetCapabilitiesResponse *capa_resp)
{
capa_req->Category = (enum tt__CapabilityCategory *)soap_malloc(soap, sizeof(int));
capa_req->__sizeCategory = 1;
*(capa_req->Category) = (enum tt__CapabilityCategory)(tt__CapabilityCategory__Media); capa_resp->Capabilities = (struct tt__Capabilities*)soap_malloc(soap,sizeof(struct tt__Capabilities)) ; soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);
printf("\n--------------------Now Gettting Capabilities NOW --------------------\n\n"); int result = soap_call___tds__GetCapabilities(soap, resp->wsdd__ProbeMatches->ProbeMatch->XAddrs, NULL, capa_req, capa_resp); if (soap->error)
{
printf("[%s][%d]--->>> soap error: %d, %s, %s\n", __func__, __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
int retval = soap->error;
exit(-1) ;
}
else
{
printf(" \n--------------------GetCapabilities OK! result=%d--------------\n \n",result);
if(capa_resp->Capabilities==NULL)
{
printf(" GetCapabilities failed! result=%d \n",result);
}
else
{ printf(" Media->XAddr=%s \n", capa_resp->Capabilities->Media->XAddr);
}
}
}
获取媒体信息Profile:
void UserGetProfiles(struct soap *soap,struct _trt__GetProfiles *trt__GetProfiles,
struct _trt__GetProfilesResponse *trt__GetProfilesResponse ,struct _tds__GetCapabilitiesResponse *capa_resp)
{
int result=0 ; printf("\n-------------------Getting Onvif Devices Profiles--------------\n\n");
soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);
result = soap_call___trt__GetProfiles(soap, capa_resp->Capabilities->Media->XAddr, NULL, trt__GetProfiles, trt__GetProfilesResponse);
if (result==-1)
//NOTE: it may be regular if result isn't SOAP_OK.Because some attributes aren't supported by server.
//any question email leoluopy@gmail.com
{
printf("soap error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error;
exit(-1);
}
else{
printf("\n-------------------Profiles Get OK--------------\n\n");
if(trt__GetProfilesResponse->Profiles!=NULL)
{
if(trt__GetProfilesResponse->Profiles->Name!=NULL){
printf("Profiles Name:%s \n",trt__GetProfilesResponse->Profiles->Name); }
if(trt__GetProfilesResponse->Profiles->token!=NULL){
printf("Profiles Taken:%s\n",trt__GetProfilesResponse->Profiles->token);
}
}
else{
printf("Profiles Get inner Error\n"); }
}
printf("Profiles Get Procedure over\n"); }
获取RTSP的URI:
void UserGetUri(struct soap *soap,struct _trt__GetStreamUri *trt__GetStreamUri,struct _trt__GetStreamUriResponse *trt__GetStreamUriResponse,
struct _trt__GetProfilesResponse *trt__GetProfilesResponse,struct _tds__GetCapabilitiesResponse *capa_resp)
{
int result=0 ;
trt__GetStreamUri->StreamSetup = (struct tt__StreamSetup*)soap_malloc(soap,sizeof(struct tt__StreamSetup));//初始化,分配空间
trt__GetStreamUri->StreamSetup->Stream = 0;//stream type trt__GetStreamUri->StreamSetup->Transport = (struct tt__Transport *)soap_malloc(soap, sizeof(struct tt__Transport));//初始化,分配空间
trt__GetStreamUri->StreamSetup->Transport->Protocol = 0;
trt__GetStreamUri->StreamSetup->Transport->Tunnel = 0;
trt__GetStreamUri->StreamSetup->__size = 1;
trt__GetStreamUri->StreamSetup->__any = NULL;
trt__GetStreamUri->StreamSetup->__anyAttribute =NULL; trt__GetStreamUri->ProfileToken = trt__GetProfilesResponse->Profiles->token ; printf("\n\n---------------Getting Uri----------------\n\n"); soap_wsse_add_UsernameTokenDigest(soap,"user", ONVIF_USER, ONVIF_PASSWORD);
soap_call___trt__GetStreamUri(soap, capa_resp->Capabilities->Media->XAddr, NULL, trt__GetStreamUri, trt__GetStreamUriResponse); if (soap->error) {
printf("soap error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
result = soap->error; }
else{
printf("!!!!NOTE: RTSP Addr Get Done is :%s \n",trt__GetStreamUriResponse->MediaUri->Uri);
}
}
开发注意事项:(必读)
soap通信的命名空间假设错误则不能检索到设备:编译好的wsdd.nsmap文件须要改动命名空间,例如以下:
假设要正常开发,被检索到。或者发现其它设备须要nsmap改动例如以下:1.1换1.2
下面命名空间表示SOAP1.1版本号: {"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL}, {"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL}, //1.1 下面命名空间表示SOAP1.2版本号: {"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL}, {"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL}, //1.2
另外存在的client搜索不到设备情况:
1.是否有vpn。存在的话。本机IP会产生变化导致不能搜到?抓包能够看到,3702port包的数据源地址改变。
2.uuid是否已经赋值。
3.有时,windows宿主机装有虚拟机。也可能造成onvifclient的ip获取错误。
故搜索不到。
这些问题,在交换机或者路由支持本地局域网跨网段数据UDP交互时,均不会产生。
调试技巧:
fsend/ frecv 打印出发送和接收到的报文。
使用xml编辑器分析。当然也能够直接用浏览器看。
1、打开onvif调试开关,以便让onvif打印一些可用的调试信息。
在Makefile中加入调试宏定义如: CC = gcc -DDEBUG
2、打开调试宏后,默认在程序执行的文件夹产生三个文件:
RECV.log
SENT.log
TEST.log
RECV.log是onvif接收到的SOAP数据,没接收一条。都会在RECV.log中记录
SENT.log是onvif发送出去的SOAP数据,没发送一套,也会在SENT.log中生成记录
最后是TEST.log,假设说RECV和SENT能够用wireshark工具抓包取代。那么TEST.log是谁也替代不了的。TEST.log记录了onvif的实时的工作状态。
尤其当出现segmentation fault错误,TEST.log就成了唯一一个可以定位到详细内存出错的地方了。
SOAP_TYPE返回soap->error=4的错误说明
关于数据正确(抓包可收到数据)。但soap返回错误,为4 及 SOAP_TYPE 的问题:
GetCapabilities的过程错误时。
多次调试后得出结论,是tt__CapabilityCategory 的设置问题,有的设备不具备所有功能,而请求所有或请求没有的功能就可能造成这样的问题。推荐写5(tt__CapabilityCategory__Media) 这是大多数设置有的能力,并且最经常使用。
GetProfile时错误:
事实上数据在抓包过程中也能全然抓到,多次调试后,发现结构体须要的Name以及tokenkeyword被赋值。其它的没有,说明本点返回与server的支持性有非常大关系。
及,开发过程中须要相应自己的需求,依据实际的须要和返回错误。读取返回结构体数据。
资源:
ONVIFDEVICEMANAGER下载地址:
http://pan.baidu.com/share/link?shareid=1967805400&uk=70662920&fid=3981296515
ONVIFTESTTOOL下载地址:
http://www.cr173.com/soft/66448.html
官网开发人员向导资料下载地址:
http://www.onvif.org/Resources/WhitePapers.aspx
參考文章:
http://blog.csdn.net/ghostyu/article/details/8162280
http://blog.csdn.net/max_min_go/article/details/17964643
linux设备上的Onvif 实现10:获取支持通道的RTSP地址
http://gaohtao.blog.163.com/blog/static/58241823201381113214599/
http://blog.csdn.net/max_min_go/article/details/17617057
ONVIF协议开发资源
http://www.csdn.net/tag/onvif%252520%2525E5%25258D%25258F%2525E8%2525AE%2525AE
http://blog.csdn.net/love_xjhu/article/details/11821037
http://blog.csdn.net/u012084827/article/details/19031969
http://blog.csdn.net/love_xjhu/article/details/9772361
http://blog.csdn.net/zsl461975543/article/details/8971143
代码框架生成之Onvif开发
http://www.yc-edu.org/C__peixun/6655.html
linux设备上的Onvif 实现4:成功编译gsoap 2.8.15
http://blog.csdn.net/u012084827/article/details/12202133
onvif规范的实现:onvif开发经常使用调试方法 和常见的segmentation
fault错误
http://blog.csdn.net/ghostyu/article/details/8432760
linux设备上的Onvif 实现6:获取摄像头的流媒体地址完整流程
http://blog.csdn.net/u012084827/article/details/12201997
SOAP 错误代码表
http://blog.csdn.net/u012084827/article/details/12201897
ONVIFclient搜索设备获取rtsp解决开发笔记(精华文章)的更多相关文章
- ONVIFclient搜索设备获取rtsp地址开发笔记(精华篇)
概要: 眼下ONVIF协议家族设备已占领数字监控行业半壁江山以上.亲,作为开发人员的你还在犹豫是否了解下吗?本文介绍了ONVIFclient从设备搜索,鉴权,能力获取,媒体信息获取 ...
- ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)
原文 http://blog.csdn.net/gubenpeiyuan/article/details/25618177 概要: 目前ONVIF协议家族设备已占据数字监控行业半壁江山以上,亲, ...
- 【视频开发】ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)
转载地址:http://blog.csdn.net/gubenpeiyuan/article/details/25618177 概要: 目前ONVIF协议家族设备已占据数字监控行业 ...
- [Openwrt 项目开发笔记]:Samba服务&vsFTP服务(四)
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 在上一节中,我们讲述了如何在路由器上挂载U盘,以 ...
- [Openwrt 项目开发笔记]:USB挂载& U盘启动(三)
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 在上一篇中,我结合Netgear Wndr370 ...
- [Openwrt 项目开发笔记]:Openwrt必要设置(二)
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 前面的两篇blog中,我将如何搭建Openwrt ...
- [Openwrt 项目开发笔记]:Openwrt平台搭建(一)补遗
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 昨晚上熬夜写了[Openwrt项目开发笔记]:O ...
- [Openwrt 项目开发笔记]:Openwrt平台搭建(一)
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 最近开始着手进行Openwrt平台的物联网网关设 ...
- [Openwrt 项目开发笔记]:PHP+Nginx安装(七)
[Openwrt项目开发笔记]系列文章传送门:http://www.cnblogs.com/double-win/p/3888399.html 正文: 在上一节中,我们已经搭建了MySQL数据库了,因 ...
随机推荐
- PHP - 自定义函数
第7章 自定义函数 学习要点: 1.标准函数 2.自定义函数 3.文件包含 4.魔法常量 一般来讲,冗余的代码都是不好的.一而再,再而三地重写代码不仅浪费时间,从布局结构角度看也显得粗制滥造.与所有优 ...
- 在Qt中如何使用QtDesigner创建的UI文件
使用Qt有一些时间了,一直在IDE环境(qtcreator和VS2003+集成器)中使用,自然少了很多麻烦的步骤.但是在享受这种便利的同 时,我们也失去了理解更多知识背后的点滴.在IDE中,如果我们要 ...
- HTTP 错误 500.19 – Internal Server Error web.config 文件的 system.webServer/httpErrors 节中不允许绝对物理路径“C:\inetpub\custerr”[转]
给ASP或者ASP.NET等需要配置IIS服务器的过程中,很可能会遇到以下两种错误.尤其是用Win7系统的,配置IIS7.0版本比用XP系统配置IIS5.1版本而言要复杂复杂一些.当同时需要配置ASP ...
- 自定义navigationBar的高度
原来看过一些解决办法,都不太好,最近解决自定义 tab bar的高度的问题,从中受到启发,找到下面的解决办法. 个人觉得和网上找到的其它方法比还是很简洁的. 关键是要调整navBarTransitio ...
- S3C3440看门狗驱动程序
S3C3440看门狗驱动程序 http://www.cnblogs.com/lfsblack/archive/2012/09/13/2684079.html 看门狗是当CPU进入错误状态后,无法恢复的 ...
- C# - 数据库存取图片
1.创建数据表 CREATE TABLE Tb_pic ( ID int primary key identity(1, 1) not null, PictureBox varchar(max) ) ...
- 基于visual Studio2013解决面试题之0804复杂链表
题目
- Apple iOS MDM开发流程
一年前曾参与过中石油的一个移动平台项目,实现了通过MDM对iOS设备进行管理.由于苹果对于mdm这块的接口及开发流程只向几个合作伙伴进行了分享,并没有对具体实现的文档进行公开,所以这方面的资料非常少. ...
- boost在windows下的编译(vs2010)
首先说下环境,win7,vs2010. 先在http://www.boost.org/users/download/上下载boost安装包,我下的是1.52.0版. 按照说明,直接运行“bootstr ...
- uva 129
暴力求解 大致题意 如果一个字符串含有相邻的重复字串称为容易的串,反之为非容易 求字典序第n困难的串…… 大致思路,暴力如果是容易的串停过,然后困难的串继续求解tot++ 总之先记着吧…… 最后输出格 ...