goodman

goodman

4个粉丝

30

问答

18

专栏

17

资料

goodman  发布于  2014-12-31 21:32:49
采纳率 0%
30个问答
wooshang@126.com
33704

ONVIF协议实现1:Server端Discovery的实现详解

   

本帖最后由 goodman 于 2014-12-31 21:37 编辑

最近在做摄像机ONVIF的协议,看了几天文档调了点代码和大家分享下,下步准备实现RTSP的流地址的获取。 附件里面是我的完整代码工程,使用的是arm-linux-gcc,代码也可以在X86的Linux上跑,只要将Makefile里面额CC=arm-linux-gcc换成gcc即可

工作平台及工具: Ubuntu:12.04 + arm-linux-gcc/gcc + OnvifTestTool12.12 gsoap下载:http://www.cs.fsu.edu/~engelen/soap.html 目前的最新版本为:gsoap2.8.21

1.搞定工具: 首先需要做的是提取工具一共有3样: soapcpp2 wsdl2h typemap.dat 我下载的的gsoap里面的typemap.dat已经包含了WS-Discovery的支持因此不需要再像网上那样去添加ONVIF支持了 下载好的源码解压出来,到gsoap-2.8/gsoap/bin目录里面一看,没有我们需要的soapcpp2 wsdl2h: [attach]2065[/attach] 没有我们只好自己编译一个了,看了下他的README.txt里面有这么一句话(PS:我比较喜欢看项目里面的README能帮助我们解决很多问题). For other platforms: see installation instructions INSTALL.txt in the root dir. 到根目录里面看下INSTALL.txt知道了怎么编译了 cd gsoap/src make -f MakefileManual cd gsoap/wsdl make -f MakefileManual

  1. Remotediscovery.wsdl产生onvif.h头文件 对于这里我们只要实现设备发现的功能,所以我们只需要Remotediscovery.wsdl这一个wsdl就可以了 ./wsdl2h -o onvif.h -c -s -k -t ./typemap.dat http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl 生成的时候会报SOAP_ENVFault 重定义的错误,将gsoap-2.8/gsoap/import/wsa5.h里面的第277行的SOAP_ENV__Fault改为SOAP_ENVFault_ex就可以了

3.生成ONVIF的框架代码 ./soapcpp2 -c onvif.h -x -d ./ -I ${HOME}/workspace/source/gsoap-2.8/gsoap/import -I ${HOME}/workspace/source/gsoap-2.8/gsoap/ 这里的${HOME}/workspace/source/gsoap-2.8/gsoap/import 和${HOME}/workspace/source/gsoap-2.8/gsoap/注意修成自己的。 这里会报

4.拷贝相关代码 建立一个onvif_test的目录将${HOME}/workspace/source/gsoap-2.8如下文件拷贝过来过来 gsoap/dom.c gsoap/stdsoap2.c gsoap/stdsoap2.h gsoap/custom/duration.c gsoap/plugin/mecevp.c gsoap/plugin/mecevp.h gsoap/plugin/smdevp.c gsoap/plugin/smdevp.h gsoap/plugin/threads.c gsoap/plugin/threads.h gsoap/plugin/wsaapi.c gsoap/plugin/wsaapi.h gsoap/plugin/wsseapi.c gsoap/plugin/wsseapi.h gsoap/plugin/wsddapi.c gsoap/plugin/ wsddapi.h 这些代码会帮我很多工作的,下面就知道了

5.实现关键代码 [code]soap_wsdd_mode wsdd_event_Probe(struct soap soap, const char MessageID, const char ReplyTo, const char Types, const char Scopes, const char MatchBy, struct wsdd__ProbeMatchesType *matches) {

if 0

printf("%s,%d\n",FUNCTION, LINE); printf("MessageID:%s\n", MessageID); printf("ReplyTo:%s\n", ReplyTo); printf("Types:%s\n", Types); printf("Scopes:%s\n", Scopes); printf("MatchBy:%s\n", MatchBy);

endif

soap_wsdd_init_ProbeMatches(soap, matches); soap_wsdd_add_ProbeMatch(soap, matches, "urn:uuid:464A4854-4656-5242-4530-313035394100", "tdn:NetworkVideoTransmitter", "onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/type/audio_encoder onvif://www.onvif.org/type/ptz onvif://www.onvif.org/type/video_analytics onvif://www.onvif.org/hardware/HD-IPCAM onvif://www.onvif.org/location/country/china onvif://www.onvif.org/name/IPCAM", NULL, "http://192.168.1.22/onvif/device_service",10); return SOAP_WSDD_MANAGED;

}[/code] 这个就是回应设备发现工具的主要代码,是不是很简单如果不适用wsddapi.c 里面的代码将要写一大推的填充代码具体,具体可以看最后面的参考链接。 6.实现的main函数 [code]

include "soapH.h"

include "wsdd.nsmap"

include "wsddapi.h"

include

include <sys/types.h> / See NOTES /

include <sys/socket.h>

include

include

int main(int argc, char argv[]) { int m, s; struct ip_mreq mcast; struct soap soap; soap_init2(&soap, SOAP_IO_UDP | SOAP_IO_FLUSH, SOAP_IO_UDP|SOAP_IO_FLUSH);
soap_set_namespaces(&soap, namespaces); soap_set_mode(&soap, SOAP_C_UTFSTRING); soap.bind_flags = SO_REUSEADDR; soap.connect_timeout = 0; soap.recv_timeout = 0; soap.send_timeout = 0; soap_register_plugin(&soap, soap_wsa); //这个很重要,我分析了很久才得出的 // 打开调试信息 soap_set_recv_logfile(&soap, "./log/recv.xml"); soap_set_sent_logfile(&soap, "./log/send.xml"); soap_set_test_logfile(&soap, "./log/test.log"); if(!soap_valid_socket(soap_bind(&soap, NULL, 3702, 16))) { soap_print_fault(&soap, stderr); exit(1); } mcast.imr_multiaddr.s_addr = inet_addr("239.255.255.250"); mcast.imr_interface.s_addr = inet_addr("0.0.0.0"); if(setsockopt(soap.master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char
)&mcast, sizeof(mcast)) < 0) { printf("setsockopt error!\n"); return 0; }
//成功绑定之后,便开始监听 for (;;) { //监听直到有连接请求 soap_wsdd_listen(&soap, 0); soap_destroy(&soap); soap_end(&soap); fprintf(stderr, "Socket connection successful: slave socket = %d\n", s); } soap_done(&soap); return 0; } [/code] 整体的主函数就是这样,需要注意的一点是需要在wsdd.nsmap里多添加一个命名空间 {"tds", "http://www.onvif.org/ver10/device/wsdl", NULL, NULL},

7.测试结果 [attach]2066[/attach] 消息格式: [code] <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" x mlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsdd="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:tdn="http://www.onvif.org/ver10/network/wsdl" xmlns:tds="http://www.onvif.org/ver10/device/wsdl">

urn:uuid:54a3c06c-96c8-47ca-b4b0-dc5119495cff uuid:5e054455-4d8e-4060-8ef8-e1cb9bfd7940 http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches urn:uuid:464A4854-4656-5242-4530-313035394100 tdn:NetworkVideoTransmitter onvif://www.onvif.org/type/video_encoder onvif://www.onvif.org/type/audio_encoder onvif://www.onvif.org/type/ptz onvif://www.onvif.org/type/video_analytics onvif://www.onvif.org/hardware/HD-IPCAM .. onvif://www.onvif.org/location/country/china onvif://www.onvif.org/name/IPCAM http://192.168.1.230/onvif/device_service 10 [/code] 8.过程总结 ONVIF这个设备发现的实现耗费了我好几天近去调试和阅读相关文档,虽然网上有很多的资料可供参考,但是真正去理解所有的东西还是要花上一些功夫的 如xml的命名空间,gsoap的消息格式和wsdl等,这些东西还是很耗费时间的,尤其是调试出问题后怎么去解决问题。 PC端抓包收到了,但是还是发现不了设备? 可能出现的问题1: "tdn:NetworkVideoTransmitter"填的不对他的前缀不是随便填的是和命名空间相关的 可能出现的问题2: wsa:RelatesTo这个字段没有,这个没有的原因是因为我们使用到了 int soap_wsa_reply(struct soap *soap, const char *id, const char *action) 函数 而这个函数里面里面有这些代码 struct soap_wsa_data *data = (struct soap_wsa_data*)soap_lookup_plugin(soap, soap_wsa_id); struct SOAP_ENV__Header *oldheader, *newheader; DBGFUN1("soap_wsa_reply", "action=%s", action?action:"(null)"); if (!data) // 这里总是返回0 return soap->error = SOAP_PLUGIN_ERROR; 网上收到了一些做法是将 if (!data) return soap->error = SOAP_PLUGIN_ERROR; 向后移一移解决的,填充了wsa:RelatesTo再判断,我觉得问题不是这么来的,最终我调试和血毒代码后,加上了 soap_register_plugin(&soap, soap_wsa); 完美解决,同时知道了为什么这么做,这很重要。见gsoap-2.8/gsoap/doc/wsa里面的文档 参考链接: http://blog.csdn.net/ghostyu/article/details/8182516 http://www.360doc.com/content/14/0828/15/9075092_405360193.shtml [attach]2067[/attach]
易百纳技术社区文件: onvif_test.tar.gz
下载
我来回答
回答43个
时间排序
认可量排序

zk922

0个粉丝

4

问答

0

专栏

0

资料

zk922 2015-01-01 10:50:21
认可0
good 大赞 。 2014年 最后一天还干到这么晚。

dondeng

0个粉丝

3

问答

0

专栏

1

资料

dondeng 2015-01-04 09:18:26
认可0
很详细。这个要赞。

ebaina_

0个粉丝

82

问答

40

专栏

0

资料

ebaina_ 2015-01-04 15:18:25
认可0
这个必须有奖品 ,奖励goodman 100元 话费,请站内你的手机号,希望更多精品。

一直未离开

0个粉丝

0

问答

0

专栏

0

资料

一直未离开 2015-01-09 15:49:55
认可0
这个必须保存啊 ,赞一个。

fujunxu

0个粉丝

0

问答

0

专栏

0

资料

fujunxu 2015-01-16 11:04:28
认可0
非常感谢大神

沧浪一钓舟

0个粉丝

0

问答

0

专栏

0

资料

沧浪一钓舟 2015-01-24 09:20:54
认可0
这个很有意义

Singcol

0个粉丝

4

问答

0

专栏

1

资料

Singcol 2015-01-28 08:54:37
认可0
好帖子,感谢大神

peterlink

0个粉丝

2

问答

0

专栏

0

资料

peterlink 2015-02-01 14:29:46
认可0
这个厉害的,赞一个!

地狱的猪

1个粉丝

15

问答

0

专栏

0

资料

地狱的猪 2015-02-02 12:29:16
认可0
用海思的arm-hisiv100-linux-gcc下编译报错
stdsoap2.c:(.text+0x20758):对‘__isnan’未定义的引用
是什么原因呢?

goodman

4个粉丝

30

问答

18

专栏

17

资料

goodman 2015-02-02 14:17:58
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=12143&ptid=4929]地狱的猪 发表于 2015-2-2 12:29[/url]
用海思的arm-hisiv100-linux-gcc下编译报错
stdsoap2.c.text+0x20758):对‘__isnan’未定义的引用
是 ...[/quote]

arm-hisiv100-linux-gcc 用uclib的在链接库的时候加上-lm就能解决了:lol

liucuqi

0个粉丝

0

问答

0

专栏

0

资料

liucuqi 2015-05-20 15:36:32
认可0
非常棒,可以好好借鉴下!

goodplayer

0个粉丝

1

问答

0

专栏

0

资料

goodplayer 2015-06-15 13:29:28
认可0
问下楼主,设备端(服务端)加入鉴权怎么加啊?有没有相关资料啊?

mediastream

0个粉丝

0

问答

0

专栏

0

资料

mediastream 2015-07-30 17:16:24
认可0
很不错,最近正在弄 ONVIF 的东西!!谢谢!

myearth

0个粉丝

3

问答

0

专栏

3

资料

myearth 2015-08-09 10:07:50
认可0
楼主和我搞得东西好像。版主是先行者,学习了。一并感谢!

sxsong

0个粉丝

12

问答

0

专栏

1

资料

sxsong 2015-09-28 10:22:36
认可0
好东西啊,谢谢

jimvyli

0个粉丝

2

问答

0

专栏

0

资料

jimvyli 2015-10-27 14:52:08
认可0
谢谢楼主,先看一看

climberking

0个粉丝

1

问答

0

专栏

0

资料

climberking 2015-12-15 20:55:42
认可0
进行到第二步骤。有点疑惑求指教:      我网上下了一些wsdl,   找到了Remotediscovery.wsdl, 是不是把Remotediscovery.wsdl 和 typemap.dat  拷贝到  gsoap\bin\ 目录下 ,经过第一步,gsoap\bin 目录下已经有soapcpp2和wsdl2h 文件了, 然后再执行./wsdl2h -o onvif.h -c -s -k -t ./typemap.dat http://www.onvif.org/onvif/ver10 ... emotediscovery.wsdl   ? 我看了下,上面的命令网址显示不全,我自己补全了一下:./wsdl2h -o onvif.h -c -s -k -t ./typemap.dat http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl         。
综上所述,当前的 gsoap\bin\   有以下几个文件:

然后再执行命令???


貌似网址没反应,是不是网址不正确了。求指教了。

climberking

0个粉丝

1

问答

0

专栏

0

资料

climberking 2015-12-15 20:57:35
认可0
本帖最后由 climberking 于 2015-12-15 21:01 编辑

不知道是不是我的步骤有问题,我是小白,完全不懂的。。

几分钟后提示出错了:

goodman

4个粉丝

30

问答

18

专栏

17

资料

goodman 2015-12-15 21:00:01
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=23413&ptid=4929]climberking 发表于 2015-12-15 20:57[/url]
不知道是不是我的步骤有问题,我是小白,完全不懂的。。[/quote]

这个不怪你,怪天朝的网络!有条件的话,挂个VPN吧

climberking

0个粉丝

1

问答

0

专栏

0

资料

climberking 2015-12-15 21:02:02
认可0
[quote][url=forum.php?mod=redirect&goto=findpost&pid=23414&ptid=4929]goodman 发表于 2015-12-15 21:00[/url]
这个不怪你,怪天朝的网络!有条件的话,挂个VPN吧[/quote]

我的步骤对吗?
加载中···
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
+ 添加网盘链接/附件

Markdown 语法

  • 加粗**内容**
  • 斜体*内容*
  • 删除线~~内容~~
  • 引用> 引用内容
  • 代码`代码`
  • 代码块```编程语言↵代码```
  • 链接[链接标题](url)
  • 无序列表- 内容
  • 有序列表1. 内容
  • 缩进内容
  • 图片![alt](url)
举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

易百纳技术社区