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 <wsdl地址> <wsdl地址> ...

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

<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的实时的工作状态

### 回答1: 使用Linux编写ONVIF代码的流程图可以大致分为以下几个步骤: 1. 开发环境设置:首先需要在Linux系统上搭建开发环境,包括安装编译器(如GCC)、设置开发工具链和配置相关库文件等。 2. 理解ONVIF协议:学习理解ONVIF协议的各种功能和特性,了解其工作原理和实现方式。 3. 选择开发语言和网络库:选择适合的编程语言,如C++或Python,并选择在Linux实现ONVIF功能所需的网络库,如gSOAP或libonvif。 4. 创建项目文件:使用所选的编程语言创建一个新的项目文件夹,并设置项目目录结构。 5. 导入依赖库:将所需的ONVIF库文件导入到项目目录中,并在代码中引入这些库文件。 6. 编写代码:根据ONVIF协议的要求和功能,编写代码来实现相应的功能,如设备发现、视频流传输、图像抓取等。这些代码应该Follow ONVIF API的规范和使用ONVIF库提供的函数。 7. 编译和生可执行文件:使用编译器将代码编译可执行文件,确保代码没有错误并生可运行的二进制文件。 8. 运行代码:在Linux系统上运行生的可执行文件,并测试功能的正确性和性能。根据需要,可能需要配置设备参数和网络连接。 需要注意的是,这只是一个大致的流程图,实际上每个步骤都可能涉及到很多细节和具体的实现方式。此外,还需要深入学习和熟悉ONVIF协议的各种功能和细节,以及相关的网络和媒体传输知识。 ### 回答2: 在使用LinuxONVIF代码之前,首先需要确保已经安装了适当的开发环境以及相关的库和工具。下面是使用LinuxONVIF代码的基本流程图: 1. 导入所需的库和头文件。 2. 创建ONVIF设备对象,并设置连接参数,例如设备的IP地址、端口号、用户名和密码。 3. 连接到设备,并进行身份验证。 4. 获取设备的基本信息。可以通过调用相应的API函数获取设备的制造商、型号、固件版本等信息。 5. 获取设备的媒体服务的URL。可以通过调用相应的API函数获取设备上的媒体服务的URL,以便后续的媒体操作。 6. 创建媒体服务对象,连接到媒体服务,并进行身份验证。 7. 获取设备的媒体流配置。可以通过调用相应的API函数获取设备的媒体流配置,例如视频编码参数、分辨率、帧率等。 8. 开始媒体流传输。可以通过调用相应的API函数开启设备的媒体流,开始传输视频流或音频流。 9. 对于视频流,可以使用合适的方法解码和播放视频;对于音频流,可以使用合适的方法进行音频处理。 10. 完媒体操作后,关闭媒体流传输。 11. 断开与媒体服务的连接。 12. 断开与设备的连接。 以上是一个简单的使用LinuxONVIF代码的流程示意图,实际使用中可能还会涉及更多操作和逻辑。需要根据具体的需求和代码实现进行合适的调整。 ### 回答3: 使用Linux上的ONVIF代码的流程图如下: 1. 初始化程序:首先,需要在Linux系统上设置开发环境,包括安装必要的开发工具和库文件。 2. 创建连接:通过网络连接到ONVIF设备。首先,需要获取设备的IP地址和端口号。然后,使用Socket编程技术来建立与设备的TCP连接。 3. 发送请求:使用HTTP协议发送指定的ONVIF请求。根据需要的功能,构建相应的SOAP消息,并将其发送到设备。 4. 接收响应:等待设备发送响应消息。一旦收到响应,解析SOAP消息,提取需要的信息,并根据需要进行相应的处理。 5. 处理响应:根据接收到的响应消息的结果,进行相应的处理。可能的操作包括获取设备的信息,配置设备的参数,开始/停止实时流等。 6. 断开连接:在完与设备的通信后,需要断开TCP连接,释放资源。 总结:使用Linux上的ONVIF代码的流程包括初始化程序、创建连接、发送请求、接收响应、处理响应和断开连接。这些步骤一起完了与ONVIF设备的通信和操作。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值