Linux下onvif的编译

这大概是我迄今为止碰到过最难编译的库了,其中遇到各种各样的问题,最终我是在windows下编译出了源文件,然后回到linux进行开发的。

最先要申明的一点:onvif开发并不需要编译安装gsoap,gsoap只是用来获取onvif源代码的工具!

一、准备"onvif"源码

需要gsoap来帮助我们将.wdsl生成为.h,最后再生成.c文件。因为wdsl互相之间有相关性,离线安装会出现更多的麻烦(修改更多的配置信息),所以整个过程都在联网状态

完成,虽然比较耗时,但是强烈建议

gsoap项目地址(需要下载)

http://www.cs.fsu.edu/~engelen/soap.html

onvif项目的wdsl地址(不需要下载)

http://www.onvif.org/Documents/Specifications.aspx中的ONVIF WSDL and XML Schemas Specifications

二、生成源文件

1、准备生成环境(2.8.10以上版本应该不需要这个步骤,2.8.17r并不需要修改typemap.dat!)

解压gsoap到任意文件夹,修改gsoap目录下的typemap.dat文件,gsoap官网对onvif编译的说明如下:

How do I use gSOAP for the ONVIF specifications?

Use gSOAP 2.8.10 and up. In the typemap.dat file used by wsdl2h, add:

#	ONVIF recommended prefixes
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

typemap.dat文件添加如上代码段,并复制到编译目录gsoap\bin\win32(win32对应windows,linux386对应linux,macosx对应macosx)。

2、生成.h文件

进入编译目录gsoap\bin\win32,这时目录下会有3个文件wsdl2h.exesoapcpp2.exe以及typemap.dat

运行命令行

wsdl2h -P -x -c -s -t typemap.dat -o onvif.h   ...

其中为http://www.onvif.org/Documents/Specifications.aspx中的ONVIF WSDL and XML Schemas Specifications列表下各个wsdl文件网络位置,用空格分隔

举例

 http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl
 http://www.onvif.org/onvif/ver10/events/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/ver10/media/wsdl/media.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
 http://www.onvif.org/ver10/advancedsecurity/wsdl/advancedsecurity.wsdl
 http://www.onvif.org/onvif/ver10/schema/onvif.xsd

等待完毕,会生成onvif.h文件在编译目录,大小在3~4m左右,失败的话大小为0k。

如果需要身份验证,修改生成的onvif.h,增加

#import "wsse.h"

3、生成.c文件

进入编译目录gsoap\bin\win32,运行命令行

soapcpp2 -c -x -L -I ../../import -I ../../../gsoap/ onvif.h

使用gsoap版本gSOAP 2.8.17r stable (update) (20.7 MB)出现如下错误(这错误太低级了,完全没有宏保护)

wsa5.h(288): **ERROR**: remote method name clash: struct/class 'SOAP_ENV__Fault'

already declared at line 274

回到gsoap\import目录下修改wsa5.h,将重复申明的部分注释如下。

/*int SOAP_ENV__Fault
(       _QName			 faultcode,		// SOAP 1.1
        char			*faultstring,		// SOAP 1.1
        char			*faultactor,		// SOAP 1.1
        struct SOAP_ENV__Detail	*detail,		// SOAP 1.1
        struct SOAP_ENV__Code	*SOAP_ENV__Code,	// SOAP 1.2
        struct SOAP_ENV__Reason	*SOAP_ENV__Reason,	// SOAP 1.2
        char			*SOAP_ENV__Node,	// SOAP 1.2
        char			*SOAP_ENV__Role,	// SOAP 1.2
        struct SOAP_ENV__Detail	*SOAP_ENV__Detail,	// SOAP 1.2
	void
);*/
重新运行上面的生成命令,生成成功。在目录下会生成很多文件,有用的文件如下:

soapC.c

soapClient.c

soapServer.c(与soapClient.c根据需要选择其一)

onvif.h

soapH.h

soapStub.h

wsdd.nsmap

除此之外,还需要gsoap-2.8\gsoap目录下的两个文件:

stdsoap2.c

stdsoap2.h

这些文件放在自己的代码目录下即可

四、onvif源码的使用

1、注释soapServer.c中SOAP_ENV__Fault部分代码

编译发生以下错误:

soapServer.c:259: undefined reference to `SOAP_ENV__Fault'

这里有两个解决办法,①如下注释soapServer.c中与这函数有关的代码,②自己实现这个函数。

SOAP_FMAC5 int SOAP_FMAC6 soap_serve_request(struct soap *soap)
{
soap_peek_element(soap);
/*if (!soap_match_tag(soap, soap->tag, "SOAP-ENV:Fault"))
return soap_serve_SOAP_ENV__Fault(soap);*/
if (!soap_match_tag(soap, soap->tag, "wsdd:Hello"))
return soap_serve___wsdd__Hello(soap);
if (!soap_match_tag(soap, soap->tag, "wsdd:Bye"))
return soap_serve___wsdd__Bye(soap);
if (!soap_match_tag(soap, soap->tag, "wsdd:Probe"))
return soap_serve___wsdd__Probe(soap);
if (!soap_match_tag(soap, soap->tag, "wsdd:ProbeMatches"))
return soap_serve___wsdd__ProbeMatches(soap);
if (!soap_match_tag(soap, soap->tag, "wsdd:Resolve"))
return soap_serve___wsdd__Resolve(soap);
if (!soap_match_tag(soap, soap->tag, "wsdd:ResolveMatches"))
return soap_serve___wsdd__ResolveMatches(soap);
return soap->error = SOAP_NO_METHOD;
}

/*SOAP_FMAC5 int SOAP_FMAC6 soap_serve_SOAP_ENV__Fault(struct soap *soap)
{	struct SOAP_ENV__Fault soap_tmp_SOAP_ENV__Fault;
	soap_default_SOAP_ENV__Fault(soap, &soap_tmp_SOAP_ENV__Fault);
	if (!soap_get_SOAP_ENV__Fault(soap, &soap_tmp_SOAP_ENV__Fault, "SOAP-ENV:Fault", NULL))
		return soap->error;
	if (soap_body_end_in(soap)
	 || soap_envelope_end_in(soap)
	 || soap_end_recv(soap))
		return soap->error;
	soap->error = SOAP_ENV__Fault(soap, soap_tmp_SOAP_ENV__Fault.faultcode, soap_tmp_SOAP_ENV__Fault.faultstring, soap_tmp_SOAP_ENV__Fault.faultactor, soap_tmp_SOAP_ENV__Fault.detail, soap_tmp_SOAP_ENV__Fault.SOAP_ENV__Code, soap_tmp_SOAP_ENV__Fault.SOAP_ENV__Reason, soap_tmp_SOAP_ENV__Fault.SOAP_ENV__Node, soap_tmp_SOAP_ENV__Fault.SOAP_ENV__Role, soap_tmp_SOAP_ENV__Fault.SOAP_ENV__Detail);
	if (soap->error)
		return soap->error;
	return soap_closesock(soap);
}*/

2、重定义soapH.h中soap_default_xsd_duration、soap_out_xsd__duration、soap_in_xsd__duration申明

编译发生很多类似以下的 错误:
soapC.c:197: undefined reference to `soap_in_xsd__duration'

这里有两个解决办法,①如下修改soapH.h头文件,②项目包含gsoap/custom/duration.c文件(实现在此文件中)

//SOAP_FMAC1 void SOAP_FMAC2 soap_default_xsd__duration(struct soap*, LONG64 *);
#define soap_default_xsd__duration(soap, a) soap_default_unsignedLONG64(soap, (ULONG64 *)a)
//SOAP_FMAC1 int SOAP_FMAC2 soap_out_xsd__duration(struct soap*, const char*, int, const LONG64 *, const char*);
#define soap_out_xsd__duration(soap,a,b,c,d) soap_out_unsignedLONG64(soap, a, b, (ULONG64 *)c, d)
//SOAP_FMAC1 LONG64 * SOAP_FMAC2 soap_in_xsd__duration(struct soap*, const char*, LONG64 *, const char*);
#define soap_in_xsd__duration(soap, a, b, c) (LONG64*)soap_in_unsignedLONG64(soap,a,(ULONG64 *)b,c)


3、实现功能函数

这时候编译我们的代码后会发生如下的错误(错误会有很多,做好思想准备,这里只列出一小部分)

/alex/discovery/soapServer.c:489: undefined reference to `__tds__GetServices'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetServiceCapabilities':
/alex/discovery/soapServer.c:530: undefined reference to `__tds__GetServiceCapabilities'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetDeviceInformation':
/alex/discovery/soapServer.c:571: undefined reference to `__tds__GetDeviceInformation'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetSystemDateAndTime':
/alex/discovery/soapServer.c:612: undefined reference to `__tds__SetSystemDateAndTime'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetSystemDateAndTime':
/alex/discovery/soapServer.c:653: undefined reference to `__tds__GetSystemDateAndTime'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetSystemFactoryDefault':
/alex/discovery/soapServer.c:694: undefined reference to `__tds__SetSystemFactoryDefault'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__UpgradeSystemFirmware':
/alex/discovery/soapServer.c:735: undefined reference to `__tds__UpgradeSystemFirmware'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SystemReboot':
/alex/discovery/soapServer.c:776: undefined reference to `__tds__SystemReboot'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__RestoreSystem':
/alex/discovery/soapServer.c:817: undefined reference to `__tds__RestoreSystem'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetSystemBackup':
/alex/discovery/soapServer.c:858: undefined reference to `__tds__GetSystemBackup'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetSystemLog':
/alex/discovery/soapServer.c:899: undefined reference to `__tds__GetSystemLog'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetSystemSupportInformation':
/alex/discovery/soapServer.c:940: undefined reference to `__tds__GetSystemSupportInformation'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetScopes':
/alex/discovery/soapServer.c:981: undefined reference to `__tds__GetScopes'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetScopes':
/alex/discovery/soapServer.c:1022: undefined reference to `__tds__SetScopes'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__AddScopes':
/alex/discovery/soapServer.c:1063: undefined reference to `__tds__AddScopes'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__RemoveScopes':
/alex/discovery/soapServer.c:1104: undefined reference to `__tds__RemoveScopes'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetDiscoveryMode':
/alex/discovery/soapServer.c:1145: undefined reference to `__tds__GetDiscoveryMode'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetDiscoveryMode':
/alex/discovery/soapServer.c:1186: undefined reference to `__tds__SetDiscoveryMode'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetRemoteDiscoveryMode':
/alex/discovery/soapServer.c:1227: undefined reference to `__tds__GetRemoteDiscoveryMode'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetRemoteDiscoveryMode':
/alex/discovery/soapServer.c:1268: undefined reference to `__tds__SetRemoteDiscoveryMode'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetDPAddresses':
/alex/discovery/soapServer.c:1309: undefined reference to `__tds__GetDPAddresses'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetEndpointReference':
/alex/discovery/soapServer.c:1350: undefined reference to `__tds__GetEndpointReference'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetRemoteUser':
/alex/discovery/soapServer.c:1391: undefined reference to `__tds__GetRemoteUser'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetRemoteUser':
/alex/discovery/soapServer.c:1432: undefined reference to `__tds__SetRemoteUser'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetUsers':
/alex/discovery/soapServer.c:1473: undefined reference to `__tds__GetUsers'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__CreateUsers':
/alex/discovery/soapServer.c:1514: undefined reference to `__tds__CreateUsers'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__DeleteUsers':
/alex/discovery/soapServer.c:1555: undefined reference to `__tds__DeleteUsers'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetUser':
/alex/discovery/soapServer.c:1596: undefined reference to `__tds__SetUser'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetWsdlUrl':
/alex/discovery/soapServer.c:1637: undefined reference to `__tds__GetWsdlUrl'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__GetCapabilities':
/alex/discovery/soapServer.c:1678: undefined reference to `__tds__GetCapabilities'
/tmp/cc9R4RNL.o: In function `soap_serve___tds__SetDPAddresses':
/alex/discovery/soapServer.c:1719: undefined reference to `__tds__SetDPAddresses'

这里便是我们会调用的功能函数,需要自己实现,每个函数都需要实现,但是对于我们不需要的功能函数,只做最简单的定义即可

int  __wsdd__ProbeMatches(struct soap* soap, struct wsdd__ProbeMatchesType *wsdd__ProbeMatches)
{
	fprintf(stderr,"__wsdd__ProbeMatches\n");
}
int  __wsdd__Resolve(struct soap* soap, struct wsdd__ResolveType *wsdd__Resolve)
{
	fprintf(stderr,"__wsdd__Resolve\n");
}
int  __wsdd__ResolveMatches(struct soap* soap, struct wsdd__ResolveMatchesType *wsdd__ResolveMatches)
{
	fprintf(stderr,"__wsdd__ResolveMatches\n");
}
int  __tdn__Hello(struct soap* soap, struct wsdd__HelloType tdn__Hello, struct wsdd__ResolveType *tdn__HelloResponse)
{
	fprintf(stderr,"__ns1__Hello\n");
}
int  __tdn__Bye(struct soap* soap, struct wsdd__ByeType tdn__Bye, struct wsdd__ResolveType *tdn__ByeResponse)
{
	fprintf(stderr,"__ns1__Bye\n");
}
int  __tdn__Probe(struct soap* soap, struct wsdd__ProbeType tdn__Probe, struct wsdd__ProbeMatchesType *tdn__ProbeResponse)
{
	fprintf(stderr,"__ns2__Probe\n");
}


三、onvif开发手册

onvif开发手册

四、调试

1、打开onvif调试开关,以便让onvif打印一些可用的调试信息

在Makefile中添加调试宏定义如

CC = gcc -DDEBUG

2、打开调试宏后,程序运行目录会产生三个文件:

RECV.log:记录了onvif接收到的SOAP数据

SENT.log:记录了onvif发送出去的SOAP数据

TEST.log:记录了onvif的实时的工作状态

你可能感兴趣的:(LINUX,ONVIF协议)