忙了一个多月,onvif总算告一段落了。这几个星期忙着其他的项目,也没有好好整理一下onvif的东西。接下来得好好整理一下自己的项目思路和项目经验,同时将自己的一些心得写出来,希望对人有所帮助。

相信大多数兄弟和我一样,onvif开发,最开始做的就是发现功能。这两天登录onvif的官网看才发现,onvif版本在八月份有更新,已经更新到V2.4了,于是下载最新的版本来进行。代码的生成可以详见我的前一篇文章。V2.4版本新增了一个wsdl文件,现在用于生成源码的文件一共有18个。为了保证全功能,最好一次性生成包含所有功能的源码。然后根据最新生成的源码来实现onvif客户端和服务端的发现功能。

1. 创建onvif_test目录。以下这些源码由最新的gsoap(2.8.16)和最新的onvif的wsdl文件(2.4)生成。(截止2013.09.16)

onvif.h

soapClientLib.c

soapServerLib.c

soapC.c

soapClient.c

soapH.h

soapServer.c

soapStub.h

2.以下文件来自gsoap_2.8.16\gsoap-2.8\gsoap

stdsoap2.c

stdsoap2.h

3.以下文件来自gsoap_2.8.16\gsoap-2.8\gsoap\custom

duration.c

4.生成的soapClientLib.c和soapServerLib.c无实际作用,可直接删除。

5.增加自定义文件:

onvif_server.c   onvif服务端实现代码

onvif_client.c   onvif客户端实现代码

onvif_server_interface.c   onvif服务端接口实现

onvif_function.c  onvif实现函数,公用

onvif_function.h  onvif实现函数,公用

onvif_server.c为服务端的实现代码,主要是定义main函数,服务端主要是监听,并处理和应答消息。

Main函数定义如下:

  1. int main(int argc,char ** argv)
  2. {
  3. printf("[%s][%d][%s][%s] start \n", __FILE__, __LINE__, __TIME__, __func__);
  4. int count = 0;
  5. struct soap ServerSoap;
  6. struct ip_mreq mcast;
  7. soap_init1(&ServerSoap, SOAP_IO_UDP | SOAP_XML_IGNORENS);
  8. soap_set_namespaces(&ServerSoap,  namespaces);
  9. printf("[%s][%d][%s][%s] ServerSoap.version = %d \n", __FILE__, __LINE__, __TIME__, __func__, ServerSoap.version);
  10. if(!soap_valid_socket(soap_bind(&ServerSoap, NULL, ONVIF_LISTEN_PORT, 10)))
  11. {
  12. soap_print_fault(&ServerSoap, stderr);
  13. exit(1);
  14. }
  15. mcast.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
  16. mcast.imr_interface.s_addr = htonl(INADDR_ANY);
  17. if(setsockopt(ServerSoap.master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)
  18. {
  19. printf("setsockopt error! error code = %d,err string = %s\n",errno,strerror(errno));
  20. return 0;
  21. }
  22. for(;;)
  23. {
  24. if(soap_serve(&ServerSoap))
  25. {
  26. soap_print_fault(&ServerSoap, stderr);
  27. }
  28. soap_destroy(&ServerSoap);
  29. soap_end(&ServerSoap);
  30. //客户端的IP地址
  31. printf("RECEIVE count %d, connection from IP = %lu.%lu.%lu.%lu socket = %d \r\n", count, ((ServerSoap.ip)>>24)&0xFF, ((ServerSoap.ip)>>16)&0xFF, ((ServerSoap.ip)>>8)&0xFF,(ServerSoap.ip)&0xFF, (ServerSoap.socket));
  32. count++;
  33. }
  34. //分离运行时的环境
  35. soap_done(&ServerSoap);
  36. return 0;
  37. }

onvif_server_interface.c   此文件用来定义所有服务端需要填充的接口。这里我们填充__wsdd__Probe接口即可,其他赞不支持的接口可以用宏统一处理。

__wsdd__Probe的填充如下:

  1. SOAP_FMAC5 int SOAP_FMAC6  __wsdd__Probe(struct soap* soap, struct wsdd__ProbeType *wsdd__Probe)
  2. {
  3. #define MACH_ADDR_LENGTH 6
  4. #define INFO_LENGTH 512
  5. #define LARGE_INFO_LENGTH 1024
  6. #define SMALL_INFO_LENGTH 512
  7. printf("[%d] __wsdd__Probe start !\n", __LINE__);
  8. unsigned char macaddr[6] = {0};
  9. char _IPAddr[INFO_LENGTH] = {0};
  10. char _HwId[1024] = {0};
  11. wsdd__ProbeMatchesType ProbeMatches;
  12. ProbeMatches.ProbeMatch = (struct wsdd__ProbeMatchType *)soap_malloc(soap, sizeof(struct wsdd__ProbeMatchType));
  13. ProbeMatches.ProbeMatch->XAddrs = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  14. ProbeMatches.ProbeMatch->Types = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  15. ProbeMatches.ProbeMatch->Scopes = (struct wsdd__ScopesType*)soap_malloc(soap,sizeof(struct wsdd__ScopesType));
  16. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties = (struct wsa__ReferencePropertiesType*)soap_malloc(soap,sizeof(struct wsa__ReferencePropertiesType));
  17. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters = (struct wsa__ReferenceParametersType*)soap_malloc(soap,sizeof(struct wsa__ReferenceParametersType));
  18. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName = (struct wsa__ServiceNameType*)soap_malloc(soap,sizeof(struct wsa__ServiceNameType));
  19. ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType = (char **)soap_malloc(soap, sizeof(char *) * SMALL_INFO_LENGTH);
  20. ProbeMatches.ProbeMatch->wsa__EndpointReference.__any = (char **)soap_malloc(soap, sizeof(char*) * SMALL_INFO_LENGTH);
  21. ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);
  22. ProbeMatches.ProbeMatch->wsa__EndpointReference.Address = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  23. netGetMac("eth4", macaddr); //eth0  根据实际情况填充
  24. macaddr[0]=0x01;macaddr[1]=0x01;macaddr[2]=0x01;macaddr[3]=0x01;macaddr[4]=0x01;macaddr[5]=0x01;
  25. sprintf(_HwId,"urn:uuid:2419d68a-2dd2-21b2-a205-%02X%02X%02X%02X%02X%02X",macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
  26. unsigned int localIp = 0;
  27. netGetIp("eth4", &localIp); //eth0 根据实际情况填充
  28. sprintf(_IPAddr, "http://%s/onvif/device_service", inet_ntoa(*((struct in_addr *)&localIp)));
  29. printf("[%d] _IPAddr ==== %s\n", __LINE__, _IPAddr);
  30. ProbeMatches.__sizeProbeMatch = 1;
  31. ProbeMatches.ProbeMatch->Scopes->__item =(char *)soap_malloc(soap, 1024);
  32. memset(ProbeMatches.ProbeMatch->Scopes->__item,0,sizeof(ProbeMatches.ProbeMatch->Scopes->__item));
  33. //Scopes MUST BE
  34. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/NetworkVideoTransmitter");
  35. ProbeMatches.ProbeMatch->Scopes->MatchBy = NULL;
  36. strcpy(ProbeMatches.ProbeMatch->XAddrs, _IPAddr);
  37. strcpy(ProbeMatches.ProbeMatch->Types, wsdd__Probe->Types);
  38. printf("wsdd__Probe->Types=%s\n",wsdd__Probe->Types);
  39. ProbeMatches.ProbeMatch->MetadataVersion = 1;
  40. //ws-discovery规定 为可选项
  41. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__size = 0;
  42. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__any = NULL;
  43. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__size = 0;
  44. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__any = NULL;
  45. ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);
  46. //ws-discovery规定 为可选项
  47. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0], "ttl");
  48. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__item = NULL;
  49. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->PortName = NULL;
  50. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__anyAttribute = NULL;
  51. ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);
  52. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0], "Any");
  53. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute, "Attribute");
  54. ProbeMatches.ProbeMatch->wsa__EndpointReference.__size = 0;
  55. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.Address, _HwId);
  56. soap->header->wsa__To = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
  57. soap->header->wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches";
  58. soap->header->wsa__RelatesTo = (struct wsa__Relationship*)soap_malloc(soap, sizeof(struct wsa__Relationship));
  59. soap->header->wsa__RelatesTo->__item = soap->header->wsa__MessageID;
  60. soap->header->wsa__RelatesTo->RelationshipType = NULL;
  61. soap->header->wsa__RelatesTo->__anyAttribute = NULL;
  62. soap->header->wsa__MessageID =(char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  63. strcpy(soap->header->wsa__MessageID,_HwId+4);
  64. if (SOAP_OK == soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &ProbeMatches))
  65. {
  66. printf("send ProbeMatches success !\n");
  67. return SOAP_OK;
  68. }
  69. printf("[%d] soap error: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  70. return soap->error;;
  71. }

onvif_client.c   onvif客户端实现代码,主要是定义客户端的main函数:

Main定义如下:

  1. int main()
  2. {
  3. printf("[%s][%d][%s][%s] start \n", __FILE__, __LINE__, __TIME__, __func__);
  4. int result = 0;
  5. wsdd__ProbeType req;
  6. struct __wsdd__ProbeMatches resp;
  7. wsdd__ScopesType sScope;
  8. struct SOAP_ENV__Header header;
  9. struct soap *soap;
  10. soap = soap_new();
  11. if(NULL == soap )
  12. {
  13. printf("sopa new error\r\n");
  14. return -1;
  15. }
  16. soap->recv_timeout = 10;
  17. soap_set_namespaces(soap, namespaces);
  18. soap_default_SOAP_ENV__Header(soap, &header);
  19. uuid_t uuid;
  20. char guid_string[100];
  21. uuid_generate(uuid);
  22. uuid_unparse(uuid, guid_string);
  23. header.wsa__MessageID = guid_string;
  24. header.wsa__To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
  25. header.wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
  26. soap->header = &header;
  27. soap_default_wsdd__ScopesType(soap, &sScope);
  28. sScope.__item = "";
  29. soap_default_wsdd__ProbeType(soap, &req);
  30. req.Scopes = &sScope;
  31. req.Types = ""; //"dn:NetworkVideoTransmitter";
  32. int i = 0;
  33. result = soap_send___wsdd__Probe(soap, MULTICAST_ADDRESS, NULL, &req);
  34. while(result == SOAP_OK)
  35. {
  36. result = soap_recv___wsdd__ProbeMatches(soap, &resp);
  37. if(result == SOAP_OK)
  38. {
  39. if(soap->error)
  40. {
  41. printf("soap error 1: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  42. result = soap->error;
  43. }
  44. else
  45. {
  46. printf("guog *********************************************\r\n");
  47. if(soap->header->wsa__MessageID)
  48. {
  49. printf("MessageID   : %s\r\n", soap->header->wsa__MessageID);
  50. }
  51. if(soap->header->wsa__RelatesTo && soap->header->wsa__RelatesTo->__item)
  52. {
  53. printf("RelatesTo   : %s\r\n", soap->header->wsa__RelatesTo->__item);
  54. }
  55. if(soap->header->wsa__To)
  56. {
  57. printf("To          : %s\r\n", soap->header->wsa__To);
  58. }
  59. if(soap->header->wsa__Action)
  60. {
  61. printf("Action      : %s\r\n", soap->header->wsa__Action);
  62. }
  63. for(i = 0; i < resp.wsdd__ProbeMatches->__sizeProbeMatch; i++)
  64. {
  65. printf("__sizeProbeMatch        : %d\r\n", resp.wsdd__ProbeMatches->__sizeProbeMatch);
  66. printf("wsa__EndpointReference       : %p\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference);
  67. printf("Target EP Address       : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address);
  68. printf("Target Type             : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Types);
  69. printf("Target Service Address  : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->XAddrs);
  70. printf("Target Metadata Version : %d\r\n", resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion);
  71. if(resp.wsdd__ProbeMatches->ProbeMatch->Scopes)
  72. {
  73. printf("Target Scopes Address   : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item);
  74. }
  75. }
  76. }
  77. }
  78. else if (soap->error)
  79. {
  80. printf("[%d] soap error 2: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  81. result = soap->error;
  82. }
  83. }
  84. soap_destroy(soap);
  85. soap_end(soap);
  86. soap_free(soap);
  87. printf("[%d] guog discover over !\n", __LINE__);
  88. return result;
  89. }

6.将wsdd.nsmap改为nsmap.h,并删除其余的*.nsmap(都一样)

7.编写makefile文件。注意在makefile中打开开关DEBUG,以便跟踪日志。

8.tcpdump为gcc环境的抓包工具,调试的时候用。

make编译通过,运行,客户端发现功能ok;

但是服务端的发现功能却不行;别急,这是由于SOAP的版本问题;soap的版本是根据命名空间来自动确定的;在soap结构体的version字段表示soap版本;

以下命名空间表示SOAP1.1版本:

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},

{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL}, //1.1

以下命名空间表示SOAP1.2版本:

{"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},

{"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},  //1.2

注意确定自己当前的命名空间。我们用SOAP1.2版本才能被测试工具发现(ONVIF Device Test Tool version 13.06)。

不清楚可以查看soap_set_namespaces接口和soap_set_local_namespaces接口;

于是将nsmap.h中的命名空间前两行改为:

{"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},

{"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},  //1.2

再编译运行,发现功能ok。

最后,将所用的工具和源码提供给大家,大家根据需要下载。

onvif测试工具V13.06:http://download.csdn.net/detail/u011597695/6288593

gsoap 2.8.16版本: http://download.csdn.net/detail/u011597695/6288615

onvif v2.4版本的wsdl文件:http://download.csdn.net/detail/u011597695/6288627

onvif v2.4版本的wsdl文件(适于离线生成源码):http://download.csdn.net/detail/u011597695/6288647

onvif源代码V2.4:http://download.csdn.net/detail/u011597695/6288663

from:http://blog.csdn.net/love_xjhu/article/details/11821037

onvif开发之设备发现功能的实现--转的更多相关文章

  1. EasyNVR网页摄像机无插件H5、谷歌Chrome直播方案-Onvif(一)使用Onvif协议进行设备发现以及指定设备信息探测

    背景分析 众所周知,EasyNVR不拘泥.不受限于摄像机的品牌厂商及其配套平台,只要是网络监控摄像机IPC.硬盘录像机NVR.且设备支持标准的RTSP/Onvif协议,都可以接入实时视频流进入Easy ...

  2. ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)

    原文  http://blog.csdn.net/gubenpeiyuan/article/details/25618177   概要: 目前ONVIF协议家族设备已占据数字监控行业半壁江山以上,亲, ...

  3. 【视频开发】ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)

    转载地址:http://blog.csdn.net/gubenpeiyuan/article/details/25618177 概要:           目前ONVIF协议家族设备已占据数字监控行业 ...

  4. Onvif开发之服务端成功对接Rtsp视频流篇

    前面篇介绍onvif服务端的发现功能,继续在之前的代码基础上完成一个RTSP流的工作,也就是客户端通过ONVIF协议来预览设备端在这个之前必须确定几个简单的条件1 设备端能被发现2 设备端支持RTSP ...

  5. EasyNVR网页摄像机无插件H5、谷歌Chrome直播方案-Onvif(二)使用Onvif协议进行设备RTSP地址获取

    背景介绍 EasyNVR最大的优势就是兼容性,通过RTSP协议接入传统网络摄像机.NVR.编码器等,使用RTSP协议接入能兼容市面上绝大多数网络摄像机等源设备,最大程度的提高整体方案的硬件设备的兼容性 ...

  6. Onvif开发之服务端发现篇

    服务端的开发相对来说比客户端稍微难一点,也就是给填充相关结构体的时候,需要一点一点的去查阅,验证各个结构中各个成员各自代表什么意思,以及对应的功能需要是那个接口实现,这是开发服务端最头疼的事情.(在开 ...

  7. Atitti  onvif 设备发现与原理

    Atitti  onvif 设备发现与原理 1.1. ,有以下几个步骤:1 1.2. 设备搜索原理及编程技巧:2 1.3. Ws disconvert 的组播地址和端口就是37022 1)发现ipca ...

  8. 深入学习:如何实现不同Android设备之间相同应用程序的网络服务发现功能

    在我们的app中添加网络服务发现功能(NSD)以方便在不同的设备上响应局域网中的请求.这种功能对于多设备之间点对点服务来说很有用,例如多人游戏,多人通话,文件共享等. 一,在网络中注册你的服务 注意: ...

  9. Onvif开发之基础介绍篇

    什么是Onvif协议,谁开启了Onvif时代? ONVIF:原意为 开放型网络视频接口论坛,即 Open Network Video Interface Forum ,是安讯士.博世.索尼等三家公司在 ...

随机推荐

  1. [Recompose] Refactor React Render Props to Streaming Props with RxJS and Recompose

    This lesson takes the concept of render props and migrates it over to streaming props by keeping the ...

  2. [Python] Boolean Or "Mask" Index Arrays filter with numpy

    NumPy Reference: Indexing Integer array indexing Boolean array indexing Note: The expression a < ...

  3. 【Hibernate步步为营】--多对多映射具体解释

    上篇文章具体讨论了一对多映射,在一对多映射中单向的关联映射会有非常多问题,所以不建议使用假设非要採用一对多的映射的话能够考虑使用双向关联来优化之间的关系,一对多的映射事实上质上是在一的一端使用< ...

  4. iOS 一个ViewController上显示2个tableView的方法

    1.在StoryBoard上创建2个tableView,并用autolayout约束. 2.在ViewController上拖进来. @property (weak, nonatomic) IBOut ...

  5. php如何截取出视频中的指定帧作为图片

    php如何截取出视频中的指定帧作为图片 一.总结 一句话总结:截取视频指定帧为图片,php ffmpeg扩展已经完美实现,并且php ffmpeg是开源的 二.php如何截取出视频中的指定帧作为图片 ...

  6. pandas 下的 one hot encoder 及 pd.get_dummies() 与 sklearn.preprocessing 下的 OneHotEncoder 的区别

    sklearn.preprocessing 下除了提供 OneHotEncoder 还提供 LabelEncoder(简单地将 categorical labels 转换为不同的数字): 1. 简单区 ...

  7. P3908 异或之和

    题目描述 求1 \bigoplus 2 \bigoplus\cdots\bigoplus N1⨁2⨁⋯⨁N 的值. A \bigoplus BA⨁B 即AA , BB 按位异或. 输入输出格式 输入格 ...

  8. SqlCommand的四大方法

    SqlCommand类的方法 ---->>>1.ExecuteNonQuery(); 它的返回值类型为int型.多用于执行增加,删除,修改数据,返回受影响的行数.当select操作时 ...

  9. noip 2018 day1 T2 货币系统 完全背包

    Code: #include<cstdio> #include<string> #include<cstring> #include<algorithm> ...

  10. window下搭建Vue.Js开发环境

    一.安装node.js.https://nodejs.org/en/download/ 最新包会自动安装npm 二.安装完node之后,npm包含的很多依赖包是部署在国外的,在天朝,大家都知道下载速度 ...