ONVIF协议网络摄像机(IPC)客户端程序开发使用gSOAP生成ONVIF框架代码(C++,并支持h264、h265)01-->CentOS

其它的不多说,直接开始步骤。
我的版本是2.8.109,目前最新版本。

1 gsoap工具下载地址

1)下载
因为linux的wget下载很慢,所以我是在windows下载后再拉进去linux的。

https://sourceforge.net/projects/gsoap2//最新版本,点击Files,然后右击复制链接,wget(windows下载快)

2 )解压

unzip gsoap_2.8.109.zip					//解压
cd gsoap-2.8/

3 )执行配置

./configure  --prefix /home/tyy/mycode/OnvifGetInfo/gsoap/gsoap-2.8	//执行配置

出现错误:

../../ylwrap: line 176: yacc: command not found

解决: 安装bison。(yacc是一个生成语法分析器的工具,CentOS下是用flex和bison来分别代替lex和yacc的,安装bison:sudo yum install bison)

4) 解决上面的问题

yum install bison	//这是Centos的方法,并且需要root权限

5) 重新配置

./configure  --prefix /home/tyy/mycode/OnvifGetInfo/gsoap/gsoap-2.8	//重新配置
make

同样出现问题,

/home/tyy/mycode/OnvifGetInfo/gsoap/gsoap-2.8/missing: line 81: flex: command not found

6) 解决上面的问题

yum install flex	//解决,安装flex

7) 再次重新配置

./configure  --prefix /home/tyy/mycode/OnvifGetInfo/gsoap/gsoap-2.8	//再次重新配置
make

8)最后

make install

可以简单分析生成的目录
在这里插入图片描述
我们接下来主要是使用到bin,gsoap,share这三个目录。其中bin下面的是我们两个可执行文件soapcpp2 ,wsdl2h。,gsoap/bin下面也有,但主要是windows时使用,因为我的是linux,所以直接用bin的即可。而share主要是用它里面的一些导入配置。
这是linux的bin的图。
在这里插入图片描述
这是windows用的bin的图。
在这里插入图片描述

上面我们已经成功的下载完gsoap,接下来是利用它生成框架了。

2 使用gSOAP生成ONVIF框架代码

1.1 准备原材料
1)随便建一个目录,我在gsoap2.8创建了一个dev_onvif目录。并且创建bin,gsoap两个空目录。
2)将两个工具wsdl2h , soapcpp2拷贝到刚刚创建的bin目录。
3)将 share/gsoap内的所有目录和gsoap的dom.cpp,stdsoap2.h,stdsoap2.cpp(.c文件不需要处理)源代码文件拷贝到gsoap。
所以目前的目录架构是这样的。
在这里插入图片描述

1.2 防止出现LONG64的错误
为了不让编译时出现LONG64的错误,我们需要在typemap.dat(在刚刚创建的gsoap/WS)中去掉一个注释,注意,只需要删除一个#即可。大概218行。

# xsd__duration = #import "custom/duration.h" | xsd__duration
改成
xsd__duration = #import "custom/duration.h" | xsd__duration

1.3 生成onvif.h头文件
为了方便,在dev_onvif目录下编写脚本onvif_head.sh,生成头文件。注意脚本可能需要权限执行。编写完直接执行即可。

#!/bin/bash
#wsdl2h -help查看选项帮助

if [ ! -d "onvif_head" ]; then 
	mkdir onvif_head
else
   rm -rf onvif_head/*
fi

# 注意,这里是进入了onvif_head/目录的,所以下面是../bin/wsdl2。
cd onvif_head/

# ../bin/wsdl2h -x -t ../gsoap/WS/typemap.dat -o onvif.h \
# https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl \
# https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl \
# https://www.onvif.org/ver10/media/wsdl/media.wsdl \
# http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl \
# http://www.onvif.org/onvif/ver10/search.wsdl \
# http://www.onvif.org/onvif/ver10/display.wsdl \
# http://www.onvif.org/onvif/ver10/deviceio.wsdl \
# http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl \
# http://www.onvif.org/onvif/ver10/receiver.wsdl \
# http://www.onvif.org/onvif/ver10/recording.wsdl \

#有些地址缺少onvif节点是因为加上onvif可能会打不开。例如第三个media,但是有时又行,我试过晚上可能比较慢。甚至突然无法下载。我试过有些是因为不支持https协议导致的,可以试试换成http。
#并且注意:想要开发光圈,对比度,饱和度设置的,需要添加imaging.wsdl,这是我后面加上的.不过不是嵌入式的,建议还是全部下载吧,我后面也是全部下载

#下面是所有的wsdl和xsd(下面只有2个xsd),根据需求添加。在线下载时,xsd可以不管,xsd一般是下载到本地后好像才有用的,具体忘记了。反正在线下载就不会错。

../bin/wsdl2h -x -t ../gsoap/WS/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/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/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/replay.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/schema/onvif.xsd 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/ver10/accessrules/wsdl/accessrules.wsdl \
http://www.onvif.org/ver10/credential/wsdl/credential.wsdl http://www.onvif.org/ver10/schedule/wsdl/schedule.wsdl \
http://www.onvif.org/ver10/pacs/types.xsd

一些比较重要的wsdl:

http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl          // 只能获取264的视频流地址
http://www.onvif.org/onvif/ver20/media/wsdl/media.wsdl          // 用于获取h265视频流地址
https://www.onvif.org/ver20/media/wsdl/media.wsdl               // 用于获取h265视频流地址,打开网页比对后,和上面的265是一样的,区别在于一个是http,一个是https.并且https可能下载比较慢,所以上面选择了http方式,就没有选择https

http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl				// 云台控制
http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl		// 光圈,对比度,饱和度

特别说明:

  • 1)按照我这样的下载是支持视频编码为h265的云台控制、imaging等操作的,这得益于该模块http://www.onvif.org/onvif/ver20/media/wsdl/media.wsdl。若不下载该模块,当遇到视频编码为h265的设备时,调用soap_call___trt__GetProfiles获取token时,会报soap->error = 4。
  • 2)当下载了支持h265的wsdl模块后,因为有些球机是共用一个h264、h265媒体流地址,而有些球机则h264、h265分开使用。
    不管是否共用媒体流地址,通过能力集接口soap_call___tds__GetCapabilities获取的媒体流地址可以看到只有http://xxx/Media,而当不共用时,soap_call___tds__GetServices是可以拿到两个媒体流地址,即h264、h265的媒体流地址。
    本来单独调用soap_call___tds__GetServices代替soap_call___tds__GetCapabilities获取能力集即可,但是在考虑到soap_call___tds__GetServices返回的是vector数组,只能通过查找子串去区分不同的能力集地址,而有些球机能力集地址是大写、有些是小写,字符串到底是怎么样的我无法区分,所以我首先调用soap_call___tds__GetCapabilities去获取能力集,再调用soap_call___tds__GetServices单独获取265的媒体流地址。
    这样不管是否共用媒体流地址,我都获取了h264、h265的地址,例如调用soap_call___tds__GetCapabilities后,当h265地址是空,表示是共用,不是空,表示不共用。
soap_call___tds__GetCapabilities	// 只能拿到一个媒体流地址
soap_call___tds__GetServices		// 能拿到264、265的媒体流地址
  • 3)上面拿到h264、h265的媒体流地址后,便可往下获取token了。获取token应该优先使用soap_call___trt__GetProfiles优先获取,因为当共用时,调用soap_call___trt__GetProfiles不会报错,而调用soap_call___ns1__GetProfiles是可能报错的。
    当soap_call___trt__GetProfiles报错,说明此时视频编码可能是h265,所以我们应该调用soap_call___ns1__GetProfiles再次尝试,如果成功,说明此时设备视频编码为265,否则就是账号密码或者其它错误了。
soap_call___trt__GetProfiles	// 支持264以及当264、265媒体流地址共用时获取token
soap_call___ns1__GetProfiles	// 支持不共用媒体流地址时,获取265的token。好像共用媒体流地址时,调用该接口可能会失败。

例如上面的调用顺序:

// 1. 获取支持h264,h265的媒体流地址
if((ret = onvif.ONVIF_GetCapabilities(det.onvif_url, userInfo)) != 0){
	// 错误
}else{
	// 成功
}
if((ret = onvif.ONVIF_GetServices(det.onvif_url, userInfo)) != 0){
    // 错误
}else{
	// 成功
}

if(soap_call___trt__GetProfiles(xxx) == error){
	// 错误,则尝试h265
	if(soap_call___ns1__GetProfiles(xxx) == error){
		// 说明是其它错误
	}else{
		// 说明此时视频编码是h265,往下处理即可
	}
}else{
	// 264成功,往下处理即可
}
  • 4)当视频编码为h265时,是无法得到设备的帧率、码率、分辨率、协议格式等信息的,这个与我们无关,与Onvif目前不太支持265的问题有关,如果想要得到这些信息,只能将设备设置成h264去获取。
    但是我们能获取到token,只要拿到这个token,我们就能够去操作云台,例如上下左右,变暗变亮,清晰度等等。

关于onvif常见错误分析可以参考:Onvif工作整理总结(二)问题及解决汇总

1.4 因鉴权需要,修改onvif.h头文件
在脚本生成的onvif_head目录将onvif.h头文件添加下面内容。

#import "wsse.h"

1.5 根据onvif.h生成onvif框架的代码
在dev_onvif目录下继续添加onvif_code.sh。

#!/bin/bash
#DIR=soap
#mkdir $DIR
#cd $DIR
# ../bin/soapcpp2 -2 -x -C ../onvif_head/onvif.h  -L -I ../gsoap/import -I ../gsoap/
#-2表示获取1.2资源代码,-x表示不获取XML信息文件,-C表示只生成客户端代码
#-L表示不生成客户端或者服务端的库,-I表示import导入路径

if [ ! -d "soap" ]; then 
	mkdir soap
else
   rm -rf soap/*
fi

cd soap/
../bin/soapcpp2 -2 -x -C ../onvif_head/onvif.h  -L -I ../gsoap/import -I ../gsoap/

添加权限后执行脚本。

报错,这是因为这两个文件重定义了。

#import "wsdd10.h" // wsdd10.h中又#import "wsa.h"
#import "wsa5.h"   // wsa.h和wsa5.h两个文件重复定义了int SOAP_ENV__Fault

在这里插入图片描述
解决: 将gsoap源码的wsa5.h(位于刚刚创建的gsoap/import目录)的SOAP_ENV__Fault函数改成其他名字或者直接注释掉。
我是改成其它名字。

int SOAP_ENV__Fault修改为int SOAP_ENV__Fault_alex

重新执行脚本即可。

1.6 结果
可以看到,成功生成了onvif.h和相应的客户端代码。
在这里插入图片描述

  • 1)各种nsmap文件:命名空间,除了名字不一样,内容是一样的,里面的内容竟然是每一个xml文件里的Envelope字段内容。我们只需要留下一个就可以了,并将之改名为wsdd.nsmap。
  • 2)soapC.c:指定数据结构的序列化和反序列化。
  • 3)soapClient.c:客户端代码。
  • 4)soapH.h:主头文件,所有客户机和服务器源代码都要包括它。
  • 5)soapStub.h:从输入头文件(onvif.h)生成的经过修改且带命名空间前缀的头文件。

上面的命名空间都是这样的内容,所以只需要留一个即可。
在这里插入图片描述

3 整理代码

1)在soap的同级目录中创建一个ONVIFAPI文件夹,用于存项目开发时使用。

2)拷贝刚刚生成soap目录内的相关源文件到ONVIFAPI。

cp ../soap/soapH.h ../soap/soapStub.h ../soap/soapC.cpp ../soap/soapClient.cpp ../soap/wsdd.nsmap .

3)拷贝plugin里面的源码到ONVIFAPI。

cp ../gsoap/plugin/wsseapi.* ../gsoap/plugin/wsaapi.* ../gsoap/plugin/threads.* ../gsoap/plugin/smdevp.* ../gsoap/plugin/mecevp.* ../gsoap/plugin/md5evp.* .

4)拷贝custom里面的源码到ONVIFAPI。

cp ../gsoap/custom/struct_timeval.* ../gsoap/custom/duration.* .

5)拷贝dom.cpp,stdsoap2.h,stdsoap2.cpp到ONVIFAPI。

cp ../gsoap/dom.cpp ../gsoap/stdsoap2.* .

6)修改.c后缀成.cpp,防止无法编译vector这些C++特有的容器。这里可能你会拷贝多一个wsseapi的.c文件,删除即可。并且同名的.c和.cpp文件是完全一样的,我使用工具对比过了。所以你可以方心的修改后缀即可。我的版本是2.8-109,共24个文件。
在这里插入图片描述

7)关联自己的命名空间,修改stdsoap2.cpp文件,在开头加入下面内容。实际上你也可以在其它地方添加,但是容易重定义命名空间,所以我们到最后编写Onvif的函数时,需要类似模板一样,不要将头文件和.cpp文件分离。

#include “wsdd.nsmap”

在这里插入图片描述

上面就已经完成了整个onvif框架的搭建。然后拷贝到你想要开发的项目即可。
在这里插入图片描述

4 编译测试

1)编写CMake,这一步是最重要的,因为onvif框架编译的成功和链接头文件和库的顺序有很大的关系。这里大家只是简单参考我的CMake即可,具体的大家按照我的顺序不太可能出现问题。
再次强调:编译onvif无论是源文件还是生成动态库,必须先把openssl的编译宏,头文件路径和库路径比源码先,否则非常容易出错,因为onvif需要依赖openssl才能成功编译。

 #1.cmake verson,指定cmake版本 
cmake_minimum_required(VERSION 2.8)

#2.project name,指定项目的名称,一般和项目的文件夹名称对应
PROJECT(OnvifGetInfo)


#3 打印相应变量信息
message(STATUS "PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")
message(STATUS "PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
#设置Cmake的调试类型为Debug,必须设置该行才能gdb调试

#4.工程需要的源文件,可以包含源文件目录下的所有源文件,或者set想要的源文件编译
AUX_SOURCE_DIRECTORY(./src/ SRC_LIST)

#5 这一步很重要,最好先set了openssl的库和添加DWITH_OPENSSL宏,否则如果库是利用TARGET_LINK_LIBRARIES这种方式链openssl的话,很有可能出错,我一开始就是这样导致出错的
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -g -ggdb -w -Wall -std=c++11 -fPIC -lssl -lcrypto -DWITH_OPENSSL -DWITH_NONAMESPACES ")

message(STATUS "CMAKE_CXX_FLAGS_DEBUG:${CMAKE_CXX_FLAGS_DEBUG}")

#6.包含头文件目录,链接库目录,多个以空格隔开,关键字不区分大小写
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/openssl/include)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/rapidjson ${PROJECT_SOURCE_DIR}/spdlogInclude ${PROJECT_SOURCE_DIR}/mysql/include)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/libevent-2.1.12-stable/include ${PROJECT_SOURCE_DIR}/libevent-2.1.12-stable/WIN32-Code/nmake)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/libevent-2.1.12-stable/WIN32-Code)
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/openssl/lib/)
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/mysql/lib ${PROJECT_SOURCE_DIR}/libevent-2.1.12-stable/lib) 

#7 添加Onvif的框架代码
AUX_SOURCE_DIRECTORY(./ONVIFAPI/ SRC_LIST)

#8.添加要编译生成的可执行文件
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_LIST})

#9.添加可执行文件所需要的链接库名,1为生成的可执行文件名

MESSAGE(STATUS "PROJECT_NAME is: ${PROJECT_NAME}")

#mysql
TARGET_LINK_LIBRARIES(${PROJECT_NAME} mysqlclient)

TARGET_LINK_LIBRARIES(${PROJECT_NAME} pthread)

#libevent
TARGET_LINK_LIBRARIES(${PROJECT_NAME} event_core)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} event_extra)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} event_openssl)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} event_pthreads)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} event)

MESSAGE(STATUS "PROJECT_NAME is: ${PROJECT_NAME}")

可以看到,成功编译。
在这里插入图片描述

5 总结

很多时候出现openssl库没链成功是因为上面CMake时链接的顺序问题,和库下载完全没问题,我也被他弄得好惨。最后才弄出来的。

6 创建onvif框架时容易出现的问题

1)LONG64的错误,原因是生成onvif头文件时没有修改xxx.dat文件。

2)vector找不到,原因是.c文件无法编译STL这种C++特有的容器。一般是由于问题1引起的。
错误如下:
在这里插入图片描述

3)最后编译时,明明CMake已经链接了头文件和库文件,但是仍然报undefined等与openssl相关的函数,原因就是CMake时链接的顺序问题。
这些问题的具体解决方法已经在上面了。

7 代码

下面给大家关于C++项目开发github上的ONVIF开源项目。只不过函数不一样,不过本版本的函数全部合并在soapClient或者soapC.cpp上,并且一般使用到获取网络,设备信息,设备能力,码率信息等等以soap_call___开头,不要找错了。

https://github.com/xris-hu/gsoap-onvif/blob/master/main.cpp
  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
ONVIF协议是一种开放的网络视频接口标准,旨在实现网络摄像机网络视频录像机和其他相关设备的互通互联。在开发ONVIF协议网络摄像机客户端程序时,我们需要遵循以下步骤: 首先,为了开发ONVIF协议网络摄像机客户端程序,我们需要对ONVIF协议进行深入了解。ONVIF协议定义了网络摄像机和客户端之间的通信规则和接口,包括设备发现、视频流传输、设备控制等。我们需要熟悉协议的各个方面,包括消息结构、命令和响应等。 其次,我们需要选择合适的开发平台和工具。ONVIF协议可以在不同平台上运行,如Windows、Linux等。我们可以选择适合我们的开发环境的编程语言和工具,并研究它们的ONVIF协议支持。 接下来,我们需要编写客户端程序代码。首先,我们需要实现设备发现功能,通过发送协议指定的消息,搜索网络中的ONVIF设备。一旦找到设备,我们就可以获取设备的信息,如设备地址、设备型号等。然后,我们可以向设备发送命令,如实时视频流请求、设备时间同步等。我们需要处理设备返回的响应消息,并根据协议规范处理各种结果。 最后,我们需要对开发客户端程序进行测试和调试。我们可以创建模拟的ONVIF设备,模拟设备的各种行为,并验证客户端程序的功能和性能。我们还可以使用一些专业的测试工具来检查客户端程序的兼容性和稳定性。 总而言之,在开发ONVIF协议网络摄像机客户端程序时,我们需要深入了解ONVIF协议,选择适合的开发平台和工具,编写代码实现协议的各种功能,并进行测试和调试。这个过程中需要耐心和细心,以确保开发出高质量的客户端程序
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值