ONVIF开发经验
ONVIF开发经验总结....................................................................................................... 1一、 利用gsoap2.8.14生成Onvif相关源代码................................................................ 21. 生成onvif.h头文件的方法................................................................................ 21) wsdl2h相关命令参数................................................................................. 22) 链接网络生成............................................................................................ 23) 下载到本地生成......................................................................................... 24) 备注说明.................................................................................................... 32. 生成onvif源代码.............................................................................................. 31) 整理相关的文件......................................................................................... 32) 通过以下命令生成相关源文件.................................................................. 33) Soapcpp2相关命令参数............................................................................. 34) 备注说明.................................................................................................... 33. 利用gsoap2.8.8生成源代码和gsoap2.8.14生成的差异.................................... 41) typemap.dat文件中需要添加相关信息...................................................... 42) wsa5.h中无SOAP_ENV__Fault函数........................................................... 5二、新建工程,调试代码................................................................................................. 5三、设备发现main函数说明.......................................................................................... 5四、遇到的问题和注意事项........................................................................................... 9五、经验总结................................................................................................................ 16一、 利用gsoap2.8.14生成Onvif相关源代码1. 生成onvif.h头文件的方法产生头文件有两种方法:链接网络生成和本地生成。1) wsdl2h相关命令参数 -c 产生c语言的代码,否则产生C++ -s 不使用STL代码 -t 指定typemap.dat文件 -o 指定生成的头文件名2) 链接网络生成l 将wsdl2.exe和typemap.dat文件放入同一个文件夹l 利用cmd或批处理执行以下dos命令:wsdl2h.exe -c -s -t typemap.dat -o onvif.hhttp://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdlhttp://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdlhttp://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdlhttp://www.onvif.org/onvif/ver10/analyticsdevice.wsdlhttp://www.onvif.org/onvif/ver10/media/wsdl/media.wsdlhttp://www.onvif.org/onvif/ver10/deviceio.wsdlhttp://www.onvif.org/onvif/ver10/display.wsdlhttp://www.onvif.org/onvif/ver10/event/wsdl/event.wsdlhttp://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdlhttp://www.onvif.org/onvif/ver10/recording.wsdlhttp://www.onvif.org/onvif/ver10/replay.wsdlhttp://www.onvif.org/onvif/ver10/search.wsdlhttp://www.onvif.org/onvif/ver10/receiver.wsdlhttp://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl3) 下载到本地生成l 从ONVIF官网上把相关的WSDL文档下载到本地,下载地址(详细参见备注说明),此外还需下载样式表,下载地址见WSDL文档中的schemaLocation。l 将wsdl2.exe、typemap.dath、WSDL文档和样式表放入同一文件夹中。l 将相关WSDL文档中的样式表引入路径(schemaLocation)修改为本地实际地址,如:event.wsdl中schemaLocation="http://www.w3.org/2005/08/addressing/ws-addr.xsd修改为schemaLocation=ws-addr.xsdl 利用cmd或批处理执行以下命令wsdl2h.exe -c -s -t typemap.dat -o onvif.hremotediscovery.wsdldevicemgmt.wsdlanalytics.wsdlanalyticsdevice.wsdlmedia.wsdldeviceio.wsdldisplay.wsdlevent.wsdlimaging.wsdlecording.wsdlreplay.wsdlsearch.wsdlreceiver.wsdlptz.wsdl4) 备注说明l wsdl2.exe位于gsoap_2.8.14\gsoap-2.8\gsoap\binl typemap.dat位于gsoap_2.8.14\gsoap-2.8\gsoapl wsdl下载地址:http://www.onvif.org/Documents/Specifications.aspxl 各url之间用空格隔开l typemap.dat不需要修改l 链接网络生成方法的优点是不用考虑以上文件对其它文件的依赖关系,不用修改引入路径。该方法的缺点跟网速有关,因此中途可能会中断,如果超过5分钟未生成,可重新执行命令,通过代理上网则无法生成,不推荐用此方法。l 下载本地生成方法的优缺点和链接网络方法生成相反,代理网推荐使用此方法。2. 生成onvif源代码1) 整理相关的文件把刚生成的onvif.h与soapcpp2.exe、import和custom放入同一文件夹,其中:soapcpp2.exe位于gsoap_2.8.14\gsoap-2.8\gsoap\binimport位于gsoap_2.8.14\gsoap-2.8\gsoap custom位于gsoap_2.8.14\gsoap-2.8\gsoap 2) 通过以下命令生成相关源文件soapcpp2.exe-2–c onvif.h -Iimport3) Soapcpp2相关命令参数 -2 采用SOAP1.2, -x 不产生xml文件(不推荐使用此命令,因为xml文档很有用) -I 为引入路径 -C 只产生客户端代码(注意:C是大写)4) 备注说明l 需要在onvif.h中加入#import"wsse.h,用来做安全验证l 需要将import目录下的wsa5.h以下部分注释掉,否则编译时会报soap_xxxx_SOAP_ENV__Fault()函数重复定义。int SOAP_ENV__Fault(_QName faultcode, //SOAP1.1 char *faultstring, //SOAP1.1 char *faultactor, //SOAP1.1 structSOAP_ENV__Detail *detail, //SOAP1.1 structSOAP_ENV__Code *SOAP_ENV__Code, //SOAP1.2 structSOAP_ENV__Reason *SOAP_ENV__Reason, //SOAP1.2 char *SOAP_ENV__Node, //SOAP1.2 char *SOAP_ENV__Role, //SOAP1.2 structSOAP_ENV__Detail *SOAP_ENV__Detail, //SOAP1.2 void); 3. 利用gsoap2.8.8生成源代码和gsoap2.8.14生成的差异利用gsoap2.8.8生成源代码方法跟gsoap2.8.14基本一致,但需注意以下区别:1) typemap.dat文件中需要添加相关信息tds ="http://www.onvif.org/ver10/device/wsdl"tev ="http://www.onvif.org/ver10/events/wsdl"tls ="http://www.onvif.org/ver10/display/wsdl"tmd ="http://www.onvif.org/ver10/deviceIO/wsdl"timg ="http://www.onvif.org/ver20/imaging/wsdl"trt ="http://www.onvif.org/ver10/media/wsdl"tptz ="http://www.onvif.org/ver20/ptz/wsdl"trv ="http://www.onvif.org/ver10/receiver/wsdl"trc ="http://www.onvif.org/ver10/recording/wsdl"tse ="http://www.onvif.org/ver10/search/wsdl"trp ="http://www.onvif.org/ver10/replay/wsdl"tan ="http://www.onvif.org/ver20/analytics/wsdl"tad ="http://www.onvif.org/ver10/analyticsdevice/wsdl"tdn ="http://www.onvif.org/ver10/network/wsdl"tt="http://www.onvif.org/ver10/schema" # OASISrecommendedprefixeswsnt ="http://docs.oasis-open.org/wsn/b-2"wsntw ="http://docs.oasis-open.org/wsn/bw-2"wsrfbf="http://docs.oasis-open.org/wsrf/bf-2"wsrfr ="http://docs.oasis-open.org/wsrf/r-2"wsrfrw ="http://docs.oasis-open.org/wsrf/rw-2"wstop ="http://docs.oasis-open.org/wsn/t-1" # WS-Discovery1.0remapping wsdd10__HelloType =|wsdd__HelloType wsdd10__ByeType =|wsdd__ByeType wsdd10__ProbeType =|wsdd__ProbeType wsdd10__ProbeMatchesType =|wsdd__ProbeMatchesType wsdd10__ProbeMatchType =|wsdd__ProbeMatchType wsdd10__ResolveType =|wsdd__ResolveType wsdd10__ResolveMatchesType =|wsdd__ResolveMatchesType wsdd10__ResolveMatchType =|wsdd__ResolveMatchType # SOAP-ENVmapping SOAP_ENV__Envelope =structSOAP_ENV__Envelope{structSOAP_ENV__Header*SOAP_ENV__Header;_XMLSOAP_ENV__Body;};|structSOAP_ENV__Envelope SOAP_ENV__Header =|structSOAP_ENV__Header SOAP_ENV__Fault =|structSOAP_ENV__Fault SOAP_ENV__Detail =|structSOAP_ENV__Detail SOAP_ENV__Code =|structSOAP_ENV__Code SOAP_ENV__Subcode =|structSOAP_ENV__Subcode SOAP_ENV__Reason =|structSOAP_ENV__Reason 2) wsa5.h中无SOAP_ENV__Fault函数由于wsa5.h中没有SOAP_ENV__Fault因此不会产生代码重复,因此不用注释。 二、新建工程,调试代码1. 新建一个项目将上面生成的soapH.h、soapStub.h、wsdd.nsmap、soapC.c、soapClient.c,还有位于gsoap-2.8\gsoap的:stdsoap2.c、stdsoap2.h和位于\custom中的:duration.c放入工程中,然后编写main函数,调试代码。2. 文件主要功能说明wsdd.nsmap 名空间定义,服务器端与客户端都要包含它,里面有很多,都是 相同的,只需导入一个进入工程就行stdsoap2.h Header_leofstdsoap2.cppruntimelibrarystdsoap2.c RuntimeClibrarywithXMLparserandrun-timesupportroutinessoapStub.h soapH.h //MainheaderfiletobeincludedbyallclientandservicesourcessoapC.c //SerializersanddeserializersforthespecfieddatastructuressoapClient.c //Clientstubroutinesforremoteoperations soapStub.h Amodi_edandannotatedheaderfileproducedfromtheinputheaderfile 三、设备发现main函数说明#include<iostream>#include"wsdd.nsmap"#include"soapH.h"usingnamespacestd;int main(){ /*****声明变量***********/ structsoap*soap; //soap环境变量 structwsdd__ProbeTypereq; //客户端发送的Probe struct__wsdd__ProbeMatchesresp; //服务端回的Probematchs structwsdd__ScopesTypesScope; //Probe里面的范围 structSOAP_ENV__Headerheader; //SOAP的头 intresult=0; //返回值 int count=0; //获得的设信息备个数 /**获取guid(windows下叫guid,linux下叫uuid),
为urn:uuid:8-4-4-4-12,由系统随机产生**/ staticcharbuf[64]={0}; //用来保存guid号 GUIDguid; /*声明guid为GUID结构体变量,包含4个变量,分别是 unsignedlongData1; unsignedshortData2; unsignedshortData3; unsignedchar Data4[8]; */if (S_OK==CoCreateGuid(&guid)) //如果guid生成成功,则将其转为字符串,保存在buf中{ _snprintf(buf,sizeof(buf) ,"urn:uuid:%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X" ,guid.Data1 ,guid.Data2 ,guid.Data3 ,guid.Data4[0],guid.Data4[1] ,guid.Data4[2],guid.Data4[3],guid.Data4[4],guid.Data4[5] ,guid.Data4[6],guid.Data4[7] ); }soap=soap_new(); //初始化soap if(soap==NULL) { return -1; } soap_set_namespaces(soap,namespaces); //设置命名空间 soap->recv_timeout=5; //设置接收Probematchs时间,超过5秒钟没有数据就退出soap_default_SOAP_ENV__Header(soap,&header); //将header设置为soap消息的头属性/*****给头赋值******/ header.wsa__MessageID=buf; 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; /*设置所需寻找设备的类型和范围,二者至少设定一个,否则可能收到非ONVIF设备,出现异常*/ soap_default_wsdd__ScopesType(soap,&sScope); sScope.__item="onvif://www.onvif.org"; //设置所需设备的sScope soap_default_wsdd__ProbeType(soap,&req); req.Scopes=&sScope; req.Types="tdn:NetworkVideoTransmitter"; /*设置所需设备的类型,tdn为命名空间前缀,为wsdd.nsmap文件中{"tdn","http://www.onvif.org/ver10/network/wsdl"}的tdn,如过不是tdn,而是其它,如ns1这里也要随之改为ns1*/ //通过组播发送Probe探针,发送成功返回0,否则-1result=soap_send___wsdd__Probe(soap,"soap.udp://239.255.255.250:3702",NULL,&req); if(result==-1) { cout<<"soaperror:"<<soap->error<<soap_faultcode(soap)<<"---"<<soap_faultstring(soap)<<endl; }else { do{ result=soap_recv___wsdd__ProbeMatches(soap,&resp);//接收ProbeMatches,成功返回0,否则-1 if (result==-1) { cout<<"共发现"<<count<<"个设备"<<endl;cout<<"soaperror:"<<soap->error<<soap_faultcode(soap)<<"---"<<soap_faultstring(soap)<<endl; break; }else { count++; cout<<"========================================="<<endl; cout<<"UUID:"<<""<<resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address<<endl; cout<<"Type:"<<""<<resp.wsdd__ProbeMatches->ProbeMatch->Types<<endl; cout<<"Scopes:"<<""<<resp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item<<endl; cout<<"DeviceServiceAddress:"<<""<<resp.wsdd__ProbeMatches->ProbeMatch->XAddrs<<endl; cout<<"MetadataVersion:"<<""<<resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion<<endl; } }while(1); } /********清除变量************/ soap_destroy(soap);//removedeserializedclassinstances(C++only) soap_end(soap); //cleanupandremovedeserializeddata soap_done(soap); returnresult;}四、调试过程遇到的问题和注意事项1. 出现如下语法错误:errorC2143:语法错误:缺少“{”(在“:”的前面)errorC2059:语法错误:“:”errorC2143:语法错误:缺少“{”(在“:”的前面)需要将工程中的.c文件改成.cpp文件即可。2. 无法解析的外部命令错误soap_check_faultsubcode在stdsoap2.h中声明的soap_check_faultsubcode(structsoap*soap)函数在soapC.cpp中未实现,可在soapC.cpp中添加如下实现:SOAP_FMAC3constchar*SOAP_FMAC4soap_check_faultsubcode(structsoap*soap){ soap_fault(soap); if(soap->version==2) { if(soap->fault->SOAP_ENV__Code&&soap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode&&soap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode)returnsoap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode->SOAP_ENV__Value; returnNULL; } returnsoap->fault->faultcode;}3. &