接触Onvif协议快要两个月了,之前由于种种原因不得不用到这个在安防领域很热门的协议,学习之路十分的坎坷,几度怀疑人生。现在也算是有点小成果了,就准备写出来跟大家分享一下,总结一些自己走过的弯路。
我的开发环境:Ubuntu 14.04/16.04;Linux C/C++;为了方便开发,用了Qt5.6.2
一、资源导航
首先,良好的习惯,学习Onvif先从 官网 (https://www.onvif.org/)看起,说起来也搞笑,我装了360,打开的时候浏览器居然提示这个网站有危险……
但是官网不太友好,尤其在之后学习生成开发框架的时候。虽然是英文网页,但是有些东西还是不能忽略的,比如说有个开发者文档还是有一丝帮助的:https://www.onvif.org/profiles/whitepapers/ 页面中的Onvif Application Programmers Guide
还有一个后期开发帮助很大的:Onvif API(https://www.onvif.org/onvif/ver20/util/operationIndex.html)
当然,对初学者来说,各位大神们的精品博文是不可或缺的。这里我找到了几个对我帮助比较大的博客。
【1】onvif - 随笔分类 - DoubleLi - 博客园(http://www.cnblogs.com/lidabo/category/952965.html)
【2】快活林高老大:Onvif专栏(http://blog.youkuaiyun.com/u012084827)
【3】许振坪的专栏:ONVIF协议网络摄像机(IPC)客户端程序开发(1):专栏开篇 (http://blog.youkuaiyun.com/benkaoya/article/details/72424335)
以上内容基本上可以说是挺全面的了,一些详细的内容可以在后面学习的时候边找边看。
二、gSOAP
SOAP是一种简单的基于XML的协议,通过http来交换信息。Onvif其实就是用SOAP协议来通信的,而SOAP协议又是基于XML的,上面提到的Onvif API网站,点开任意一条API详细页查看源代码,一目了然。
所以从我自己的理解来看,包括实际开发的上,都是在填充消息内容。后面生成的框架其实就是把每个通信需要发送的内容和获取结果用结构体的形式做了封装,隐藏了SOAP协议的组包内容。所以到后来你会发现,Onvif开发的一大特点就是,你在这个框架里基本能获得的参数只有一个url链接:想要看相机的实时视频?给你一个rtsp地址。想要抓图片?给你一个图片的网页地址……
(这里是我这么多天的开发心得,讲的不对欢迎指正)
开始讲gSOAP。
gSOAP是SOAP协议的C/C++语言实现,为什么用到这个工具,因为我们需要把官方的协议文档转换成可供开发的C/C++代码。对!是代码,不是什么动态链接库!最大的好处就是平台无关,但是编译的时候真的蛋疼,整整二三十万行的代码需要跟着程序一起编译。
gSOAP安装很简单,从官网(http://www.cs.fsu.edu/~engelen/soap.html)获取源码编译安装,源码地址:https://sourceforge.net/projects/gsoap2/files/
./configure
make
make install
三、在线生成 onvif.h
参考博客:http://blog.youkuaiyun.com/max_min_go/article/details/17562045(Onvif开发之代码框架生成篇)
gsoap还是选择稍微高点的版本,上面的博客说明了在gsoap2.8.8版本下(可能包括更低),需要在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"
# OASIS recommended prefixes
wsnt = "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-Discovery 1.0 remapping
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-ENV mapping
SOAP_ENV__Envelope = struct SOAP_ENV__Envelope { struct SOAP_ENV__Header *SOAP_ENV__Header; _XML SOAP_ENV__Body; }; | struct SOAP_ENV__Envelope
SOAP_ENV__Header = | struct SOAP_ENV__Header
SOAP_ENV__Fault = | struct SOAP_ENV__Fault
SOAP_ENV__Detail = | struct SOAP_ENV__Detail
SOAP_ENV__Code = | struct SOAP_ENV__Code
SOAP_ENV__Subcode = | struct SOAP_ENV__Subcode
SOAP_ENV__Reason = | struct SOAP_ENV__Reason
四、生成Onvif源码
好多博主都说有离线生成的wsdl文档,但是我在官网真的没有找到,现在我觉得可能说的就是上面我提到的那些API网页吧。
反正没关系的,我们可以在线生成嘛,毕竟有的博主也说离线的不稳定。
wsdl2h -c -s -t typemap.dat -o onvif.h \
http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl \
http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl \
http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl \
http://www.onvif.org/onvif/ver10/analyticsdevice.wsdl \
http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl \
http://www.onvif.org/onvif/ver10/deviceio.wsdl \
http://www.onvif.org/onvif/ver10/display.wsdl \
http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl \
http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl \
http://www.onvif.org/onvif/ver10/recording.wsdl \
http://www.onvif.org/onvif/ver10/replay.wsdl \
http://www.onvif.org/onvif/ver10/search.wsdl \
http://www.onvif.org/onvif/ver10/receiver.wsdl \
http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl
这里可要注意了,以上的代码输在命令行里,是不带回车的一行!一开始我也是崩溃的,然后复制粘贴写了一个shell脚本……
此时生成的onvif.h中不含鉴权的功能,所以需要在onvif.h中大约在 95~100行的位置添加代码:
import "wsse.h"
这时候可以用命令愉快的生成Onvif源代码了,输入命令:
soapcpp2 -2 -c onvif.h -x -I ./gsoap-2.8.14/gsoap-2.8/gsoap/import -I ./gsoap-2.8.14/gsoap-2.8/gsoap/
//soapcpp2命令的相关命令参数如下:(可以根据自己的实际需要添加不同参数)
-2 //采用SOAP1.2,和SOAP1.0版本不同,会导致搜索工具搜索不到
-x //不产生xml文件(可用可不用,xml有一定帮助,但是太多)
-I //为引入路径
-C //只产生客户端代码(注意:C是大写,不推荐此命令)
接下来会在“
-I ”指定的目录下生成文件,包含大量的 .nsmap文件,没有用;以及10个左右真正有用的文件。
用于开发的有效文件:
duration.c //可能在plugin文件夹下
onvif.h
soapC.c
soapClient.c //用于Onvif客户端开发
soapServer.c //用于Onvif服务端开发
soapH.h
soapStub.h
stdsoap2.c
stdsoap2.h
wsdd.h //将wsdd.nsmap更改后缀名而来
五、关于生成的Onvif框架
因为我的项目需要用C++来写,当时我在找了无数的资料后发现几乎只有讲生成C语言框架的,整得我很郁闷,直到后来我才在以上源码里发现有这么一句:
#ifdef __cplusplus
extern "C" {
#endif
原来人家早就帮你想好了……
这里我还要说一句,虽然是框架是C的,但是已经做到了兼容,没必要刻意去追求C++的框架。有是有,但是我觉得不好用,并且资料也难找,编译起来更是蛋疼。
其实上面说了怎么生成,我自己根本就没有成功。看上去文件都是对的,但是别人生成的文件有成千上万行代码,我的只有几百行,显然是有问题的。
所以,还是要经常关注GitHub,用别人做好的框架吧。