Onvif开发之服务端发现篇

服务端的开发相对来说比客户端稍微难一点,也就是给填充相关结构体的时候,需要一点一点的去查阅,验证各个结构中各个成员各自代表什么意思,以及对应的功能需要是那个接口实现,这是开发服务端最头疼的事情。(在开发过程中郁闷了好久,后面是通过搜索工具抓包海康设备来填充相关信息的)开始切入主题了,准备服务端的开发了。

同理需要前面生成的代码,这个时候较之客户端的开发,需要在代码生成的时候之前生成的soapServer.c文件了,当放在客户端测试目录下用makefile编译的时候,你可能会很惊讶,怎么这么多错误,这么多函数报错,而且都是没有定义呢?

别紧张,这些接口就是服务端开发需要实现的!即使开发不需要使用,但是根据onvif协议,也是需要给函数一个实现体的,具体的这些函数就需要看看soapServer.c文件里的soap_serve_request函数,这里我贴出来一部分如下:

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1.  ifndef WITH_NOSERVEREQUEST  
  2. SOAP_FMAC5 int SOAP_FMAC6 soap_serve_request(struct soap *soap)  
  3. {  
  4.     soap_peek_element(soap);  
  5.     if (!soap_match_tag(soap, soap->tag, "wsdd:Hello"))  
  6.         return soap_serve___wsdd__Hello(soap);  
  7.     if (!soap_match_tag(soap, soap->tag, "wsdd:Bye"))  
  8.         return soap_serve___wsdd__Bye(soap);  
  9.     if (!soap_match_tag(soap, soap->tag, "wsdd:Probe"))      
  10.         return soap_serve___wsdd__Probe(soap);  
  11.     if (!soap_match_tag(soap, soap->tag, "wsdd:ProbeMatches"))      
  12.         return soap_serve___wsdd__ProbeMatches(soap);  
  13.     if (!soap_match_tag(soap, soap->tag, "wsdd:Resolve"))      
  14.         return soap_serve___wsdd__Resolve(soap);  
  15.     if (!soap_match_tag(soap, soap->tag, "wsdd:ResolveMatches"))      
  16.         return soap_serve___wsdd__ResolveMatches(soap);  
  17.     if (!soap_match_tag(soap, soap->tag, "ns1:GetSupportedActions"))      
  18.         return soap_serve___ns1__GetSupportedActions(soap);      
  19.     if (!soap_match_tag(soap, soap->tag, "ns1:GetActions"))      
  20.         return soap_serve___ns1__GetActions(soap);  
  21.     if (!soap_match_tag(soap, soap->tag, "ns1:CreateActions"))      
  22.         return soap_serve___ns1__CreateActions(soap);  
  23.     if (!soap_match_tag(soap, soap->tag, "ns1:DeleteActions"))      
  24.         return soap_serve___ns1__DeleteActions(soap);  
  25.     if (!soap_match_tag(soap, soap->tag, "ns1:ModifyActions"))      
  26.         return soap_serve___ns1__ModifyActions(soap);  
  27.     if (!soap_match_tag(soap, soap->tag, "ns1:GetServiceCapabilities"))      
  28.         .  
  29.         .  
  30.          .  
  31.        //当然了,后来还有很长,很多了,具体实际开发可以根据需要来实现对应的函数体就好了  
  32.            

 

后面还有很多系列函数,都是在对应了接口中调用了需要服务端实现的接口函数,代码框架只是有申明,没有实现,所以开发服务端的第一步,就是需要根据这里,把所以报错没有实现的函数全部实现掉,但是给一个函数体就好,后期开发再确定需要实现那些功能,再一个一个的接口具体实现,所以接下来就是写代码了,即使是拷贝复制工作,你也会有一种手要断了的赶觉的。我记得当时我就是一个整个下午在ctrl+ v 选中,然后p 粘贴.最后弄完眼睛都花了。

因为每个函数的可以用相同的函数体来实现,所以写一个简单宏来代替是比较方面而且直观的方法,我的实现如下:

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. #define ONVIF_NOT_IMPLEMENTED_FUNC(soap, namespaces) \  
  2.     if( namespaces != NULL) \  
  3.         soap_set_namespaces(soap, namespaces); \  
  4.     printf("Func: %s, Path: %s \n", __func__, soap->path); \  
  5.     return soap_receiver_fault_subcode(soap, "test:Action Not Supported", "Test: Not Implemented ", "The requested action is not implemented ");  

好了有了前面的准备工作开始写发现函数了,设备端的回复搜索的接口函数为__wsdd__Probe__wsdd__Probe,实现如下:

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. int SOAP_FMAC6  __wsdd__Probe(struct soap* soap, struct wsdd__ProbeType *wsdd__Probe)  
  2. {  
  3.     printf(" \n ##### Start __wsdd__Probe ##### \n");  
  4.     char _IPAddr[64] = {0};  
  5.     char _HwId[256] = {0};  
  6.   
  7.     wsdd__ProbeMatchesType ProbeMatches;  
  8.     ProbeMatches.ProbeMatch = (struct wsdd__ProbeMatchType *)soap_malloc(soap, sizeof(struct wsdd__ProbeMatchType));  
  9.     memset(ProbeMatches.ProbeMatch, 0,  sizeof(struct wsdd__ProbeMatchType));  
  10.   
  11.     ProbeMatches.ProbeMatch->XAddrs = (char *)soap_malloc(soap, sizeof(char) * 256);  
  12.     memset(ProbeMatches.ProbeMatch->XAddrs, '\0', sizeof(char) * 256);  
  13.   
  14.     ProbeMatches.ProbeMatch->Types = (char *)soap_malloc(soap, sizeof(char) * 256);  
  15.     memset(ProbeMatches.ProbeMatch->Types, '\0', sizeof(char) * 256);  
  16.   
  17.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties = (struct wsa__ReferencePropertiesType*)soap_malloc(soap,sizeof(struct wsa__ReferencePropertiesType));  
  18.     memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties, 0, sizeof(struct wsa__ReferencePropertiesType));  
  19.   
  20.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters = (struct wsa__ReferenceParametersType*)soap_malloc(soap,sizeof(struct wsa__ReferenceParametersType));  
  21.     memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters, 0, sizeof(struct wsa__ReferenceParametersType));  
  22.   
  23.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName = (struct wsa__ServiceNameType*)soap_malloc(soap,sizeof(struct wsa__ServiceNameType));  
  24.     memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName, 0, sizeof(struct wsa__ServiceNameType));  
  25.     ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType = (char **)soap_malloc(soap, sizeof(char *) * 256);  
  26.     memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType, 0, sizeof(char *) * 256);  
  27.   
  28.     ProbeMatches.ProbeMatch->wsa__EndpointReference.__any = (char **)soap_malloc(soap, sizeof(char*) * 256);  
  29.     memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.__any, 0, sizeof(char*) * 256);  
  30.     ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute = (char *)soap_malloc(soap, sizeof(char) * 256);  
  31.     memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute, 0,  sizeof(char) * 256);  
  32.   
  33.     ProbeMatches.ProbeMatch->wsa__EndpointReference.Address = (char *)soap_malloc(soap, sizeof(char) * 256);  
  34.     memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.Address, 0, sizeof(char) * 256);  
  35.   
  36.   
  37.     //这里是一个uid,我在实际开发的过程中是的设备的本身mac地址,这里我取了一个mac地址的地址  
  38.      strcpy(_HwId, "urn:uuid:20131228-AABB-CCDD-EEFF-010203040506");  
  39.     //这是是需要回复给给客户端的基本信息.设备的ip地址以及通信端口  
  40.     sprintf(_IPAddr, "http://%d.%d.%d.%d:%d/onvif/device_service", 192,168,12,103, 8899);  
  41.   
  42.     ProbeMatches.__sizeProbeMatch = 1;  
  43.     ProbeMatches.ProbeMatch->Scopes = (struct wsdd__ScopesType*)soap_malloc(soap, sizeof(struct wsdd__ScopesType) * ProbeMatches.__sizeProbeMatch);  
  44.     memset(ProbeMatches.ProbeMatch->Scopes, 0, sizeof(struct wsdd__ScopesType) * ProbeMatches.__sizeProbeMatch);  
  45.     //Scopes MUST BE  
  46.     ProbeMatches.ProbeMatch->Scopes->__item =(char *)soap_malloc(soap, 1024);  
  47.     memset(ProbeMatches.ProbeMatch->Scopes->__item, '\0', 1024);  
  48.     strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/Network_Video_Transmitter ");  
  49.     strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/video_encoder ");  
  50.     strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/audio_encoder ");  
  51.     strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/location/city/CSDN ");  
  52.     strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/name/csder ");  
  53.     strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/hardware/TEST_Onvif ");  
  54.   
  55.     ProbeMatches.ProbeMatch->Scopes->MatchBy = NULL;  
  56.     strcpy(ProbeMatches.ProbeMatch->XAddrs, _IPAddr);  
  57.     strcpy(ProbeMatches.ProbeMatch->Types, wsdd__Probe->Types);  
  58.     printf("wsdd__Probe->Types=%s\n",wsdd__Probe->Types);  
  59.     ProbeMatches.ProbeMatch->MetadataVersion = 1;  
  60.   
  61.     //ws-discovery规定 为可选项  
  62.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__size = 0;  
  63.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__any = NULL;  
  64.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__size = 0;  
  65.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__any = NULL;  
  66.   
  67.     ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_256);  
  68.     //ws-discovery规定 为可选项  
  69.     strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0], "ttl");  
  70.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__item = NULL;  
  71.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->PortName = NULL;  
  72.     ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__anyAttribute = NULL;  
  73.     ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_256);  
  74.     strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0], "Any");  
  75.     strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute, "Attribute");  
  76.     ProbeMatches.ProbeMatch->wsa__EndpointReference.__size = 0;  
  77.     strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.Address, _HwId);  
  78.       
  79.     soap->header->wsa__To = (char *)"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";  
  80.     soap->header->wsa__Action = (char *)"http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches";  
  81.     soap->header->wsa__RelatesTo = (struct wsa__Relationship*)soap_malloc(soap, sizeof(struct wsa__Relationship));  
  82.     soap->header->wsa__RelatesTo->__item = soap->header->wsa__MessageID;  
  83.     soap->header->wsa__RelatesTo->RelationshipType = NULL;  
  84.     soap->header->wsa__RelatesTo->__anyAttribute = NULL;  
  85.   
  86.     soap->header->wsa__MessageID =(char *)soap_malloc(soap, sizeof(char) * 256);  
  87.     strcpy(soap->header->wsa__MessageID,_HwId+4); //前面四个字节可以是不需要的  
  88.   
  89.   
  90.     if (SOAP_OK == soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &ProbeMatches))  
  91.     {  
  92. //      printf("send ProbeMatches success !\n");  
  93.         return SOAP_OK;  
  94.     }  
  95.   
  96.     printf("[%d] soap error: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));  
  97.     return soap->error;;  
  98.   
  99. }  

搜索的回复函数本分就完成了,现在需要要的工作就是在设备端开启一个udp的socket了。为了不影响设备端其他的业务,所以建议设备端另外开一个线程让socket运行起来,因为这个是一个一直循环的操作了,基本的代码如下:

 

 

[cpp]  view plain  copy
 
 在CODE上查看代码片派生到我的代码片
  1. int Onvif_DeviceDiscovery()  
  2. {  
  3.     struct soap udp_soap;  
  4.     int retval = -1;  
  5.   
  6.     soap_init1(&udp_soap, SOAP_IO_UDP | SOAP_IO_FLUSH);  
  7.     udp_soap.connect_flags = SO_BROADCAST;  
  8.     udp_soap.port = 3702;  
  9.   
  10.     soap_set_namespaces( &udp_soap, namespaces);  
  11.     SOAP_SOCKET udp_sock = -1;  
  12.   
  13.     udp_soap->omode = SOAP_IO_UDP;  
  14.     udp_soap->bind_flags = SO_REUSEADDR;  
  15.   
  16.     udp_sock = soap_bind(udp_soap, NULL, udp_soap->port, 100);  
  17.     if( (udp_sock < 0) && (udp_sock == SOAP_INVALID_SOCKET))  
  18.     {  
  19.         close(udp_sock);  
  20.         printf(" soap_bind failed! %s \n", strerror(errno));  
  21.         return -1;  
  22.     }  
  23.     //这个接口设置一些广播的属性值,下面也有实现提出,  
  24.     retval = udp_add_multicast(&udp_soap);  
  25.     if(retval != 0 )  
  26.     {  
  27.         printf(" udp add multicast failed: %s \n", strerror(errno));  
  28.         return -1;  
  29.     }  
  30.     //每次都是在此循环中接收客户端发过来的广播请求,然后服务端调用__wsdd__Probe函数,返回服务端的一些基本信息  
  31.     while(1)  
  32.     {  
  33.         if( soap_serve( &udp_soap ) != 0)  
  34.         {  
  35.             soap_print_fault(&udp_soap, stderr);  
  36.         }  
  37.   
  38.         soap_destroy(&udp_soap);  
  39.         soap_end( &udp_soap);  
  40.     }  
  41.     soap_done(&udp_soap);  
  42.     return 0;  
  43. }     
  44. int udp_add_multicast( struct soap* socksoap)  
  45. {  
  46.     //  set a route for multicast traffic  
  47.     //  这个执行一个系统命令,之前一直无法被搜索到,后来查了资料才知道需要启动下  
  48.     system("route add -net 224.0.0.0 netmask 224.0.0.0 eth0");  
  49.     int loop;  
  50.     int retval = -1;  
  51.     struct ip_mreq mreqcon;  
  52.     loop = 1;  
  53.     //设置组播的属性  
  54.     retval = setsockopt(socksoap->master, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));  
  55.     if(retval != 0)  
  56.     {  
  57.         printf("setsockopt: IP_MULTICAST_LOOP failed! %s\n ", strerror(errno));  
  58.         return -1;  
  59.     }  
  60.   
  61.     //绑定组播的ip地址  
  62.     mreqcon.imr_multiaddr.s_addr = inet_addr("239.255.255.250");  
  63.     mreqcon.imr_interface.s_addr = htonl(INADDR_ANY);  
  64.     if( (signed int )mreqcon.imr_multiaddr.s_addr == -1)  
  65.     {  
  66.         printf("239.255.255.250 not a legal multicast address! %s\n", strerror(errno));  
  67.         return -1;  
  68.     }  
  69.     retval = setsockopt(socksoap->master, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqcon, sizeof(mreqcon));  
  70.     if( retval != 0 )  
  71.     {  
  72.         printf("setsockopt: IP_ADD_MEMBERSHIP failed! %s\n ", strerror(errno));  
  73.         return -1;  
  74.     }  
  75.   
  76.     return 0;  
  77. }  

完成这些代码之后,通过onvif搜索工具,搜索的结果图如下

看到基本信息也就是上面代码中填写了!设备端的发现功能也就实现了!

纵观前后,其实设备端的发现只是在已经有的代码框架基础上操作两步就好!

1 创建socket,搭建广播接收回复服务

2 实现__wsdd__Probe函数!

 

提供大家一个不错的网站:onvif server

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ONVIF(Open Network Video Interface Forum)是一个由多家全球领先的安防公司联合成立的组织,旨在促进网络摄像机和其他安防产品之间的互操作性。 ONVIF网络摄像机服务端是指符合ONVIF标准的网络摄像机中运行的服务器端软件。该服务端软件可以提供一系列功能,包括视频流传输、视频内容的编码和解码、设备配置和管理等。 首先,ONVIF网络摄像机服务端提供视频流传输功能。它可以将网络摄像机捕获到的视频信号实时传输到网络上,以便用户可以通过互联网或网络内部的设备进行观看和录制。 其次,服务端还能实现视频内容的编码和解码。在视频传输过程中,服务端会对视频信号进行编码,以减少数据传输量,提高传输效率。同时,它也可以对接收到的编码后的视频流进行解码,以还原成原始的视频信号。 此外,ONVIF网络摄像机服务端还拥有设备配置和管理功能。用户可以通过服务端网络摄像机进行配置,例如调整图像质量、设置报警触发条件等。同时,服务端还负责监控网络摄像机的状态,以确保设备的正常运行。 总之,ONVIF网络摄像机服务端是一种关键的软件,它使网络摄像机能够与其他安防产品进行互联互通,并提供视频传输、编码解码以及设备配置和管理等功能。通过使用ONVIF标准,不同厂商的网络摄像机可以实现互操作性,从而提供更加灵活和便捷的安防解决方案。 ### 回答2: ONVIF(Network Video Interface Forum)是一个由多家摄像机制造商和软件开发商共同发起的开放式标准组织。它的目的是为了推动网络摄像机和与之相关的设备之间的互操作性和兼容性。 在ONVIF网络摄像机服务端中,主要实现了以下功能: 1. 视频流传输:ONVIF网络摄像机服务端可以实现视频和音频信号的传输。它将摄像机捕获到的视频和音频数据进行编码,并以标准的网络协议(如RTSP)进行传输,以便客户端可以实时接收和播放视频。 2. 码流控制:ONVIF网络摄像机服务端可以根据客户端的需求调整视频流的码率、分辨率和帧率等参数,以达到不同网络环境下的最佳性能和流畅度。 3. 图像处理:ONVIF网络摄像机服务端支持图像处理功能,可以对摄像机捕获的视频进行诸如自动曝光、自动对焦、图像增强等操作,以提高图像质量和清晰度。 4. 远程控制:ONVIF网络摄像机服务端支持远程控制功能,可以通过网络连接来对摄像机进行远程操作,如镜头控制、光圈控制、云台控制等。 5. 安全性:ONVIF网络摄像机服务端支持一些安全机制,如数据加密、访问控制、权限管理等,以保障视频数据的安全性和隐私保护。 总而言之,ONVIF网络摄像机服务端是一种标准化、可互操作的摄像机系统,它提供了丰富的功能和灵活的配置选项,能够满足不同用户的需求,并方便与其他ONVIF兼容设备进行集成和共享。 ### 回答3: ONVIF 是一个开放的网络视频接口标准,旨在为不同的网络摄像机和视频管理系统提供互操作性和统一的管理接口。ONVIF 网络摄像机服务端是指使用 ONVIF 协议提供视频流和相关功能的摄像机设备。 ONVIF 网络摄像机服务端具有以下特点和功能: 1. 统一的管理接口:ONVIF 定义了摄像机设备的管理和控制接口,使不同品牌的摄像机可以使用相同的方法进行配置和管理,大大方便了系统集成和统一管理。 2. 视频流处理:ONVIF 服务端可以提供实时的视频流,支持不同的视频编码格式和分辨率,允许远程访问和监视。 3. 运动检测与警报:ONVIF 服务端可以通过图像处理技术进行运动检测,并能发送警报或触发其他相关操作。 4. PTZ 控制:ONVIF 服务端支持云台、高清晰度摄像头和镜头控制,可以进行远程方向、旋转和焦距控制等操作。 5. 网络存储:ONVIF 服务端支持网络存储功能,可以将摄像头的视频数据存储到网络服务器或 NAS 存储设备上,方便进行录像回放和存储管理。 6. 安全保护:ONVIF 服务端通过支持安全的网络传输和身份验证机制,确保视频流和相关数据的安全传输和使用。 7. 集成适应性:ONVIF 服务端可以方便地与其他 ONVIF 兼容的设备和系统进行集成,如视频管理软件、网络视频录像机等。 总之,ONVIF 网络摄像机服务端提供了一套开放标准和接口,使得不同品牌的摄像机能够互操作,方便统一管理和集成。它具有丰富的功能和灵活的部署方式,在视频监控领域得到广泛应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值