onvif的应用

一、前言

  • CMU(Center Manager Unit),即中心管理单位
  • PU(Prefocus Unit),即监控前端单元,负责在CMU的控制下使用摄像机采集视频流、使用麦克风采集音频流、使用控制口采集报警信息、对摄像机云台镜头进行控制
  • CU(Client Unit),监控系统的监控客户端单元,负责将PU采集到的视频流、音频流、报警信息提交给监控用户,并根据用户要求操作PU设备,如云台、镜头等

二、传统视频监控系统的一个局域网应用场景

  1. PU设备上线后,向CMU注册,建立连接
  2. CMU与PU进行信令交互,请求能力集,获取配置
  3. CU上线,向CMU注册,建立连接
  4. CMU与CU进行信令交互,传输设备列表
  5. CU向PU请求码流

三、应用onvif规范后对应场景

  1. PU设备上线后,向CMU发送HELLO消息
  2. CMU需要搜寻设备时,向PU发送PROBE消息
  3. CMU与PU进行信令交互,请求能力集,获取配置
  4. CU上线,向CMU注册,建立连接
  5.  CMU与CU进行信令交互,传输设备列表
  6. 在CMU的协调下,CU同PU建立连接传输码流

有了onvif之后

  1. PU与CMU的交互方式发生了改变,CMU不再与PU保持长连接
  2. 遵循ONVIF规范,信令以及消息内容有了统一的标准

四、设备发现main函数说明

#include <iostream>

#include "wsdd.nsmap"

#include "soapH.h"

using namespace std;

int main()

{

   /*****声明变量***********/

     structsoap *soap;              //soap环境变量

     structwsdd__ProbeType req;      //客户端发送的Probe

     struct__wsdd__ProbeMatches resp; //服务端回的Probematchs

     structwsdd__ScopesType sScope;   //Probe里面的范围

     structSOAP_ENV__Header header;   //SOAP的头

     intresult = 0;                    //返回值        

     int count = 0;                   //获得的设信息备个数

    

     /**获取uuid(windows下叫guid,linux下叫uuid),格式为urn:uuid:8-4-4-4-12,由系统随机产生**/

     staticchar buf[64] = {0};   //用来保存uuid号

   

     UUID uuid;     /*声明guid为GUID结构体变量,包含4个变量,分别是

                 unsigned longData1;

                 unsigned short Data2;

                 unsigned short Data3;

                 unsigned char  Data4[ 8 ];

                        */

if (S_OK== CoCreateuuid(&guid))    //如果uuid生成成功,则将其转为字符串,保存在buf中

{

       _snprintf(buf,sizeof(buf)

      ,"urn:uuid:%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X"

      , uuid.Data1

      , uuid.Data2

      , uuid.Data3

      , uuid.Data4[0], uuid.Data4[1]

      , uuid.Data4[2], uuid.Data4[3], uuid.Data4[4],uuid.Data4[5]

      , uuid.Data4[6], uuid.Data4[7]

      );

     }

soap = soap_new(); //初始化soap

    if(soap==NULL)

     {

        return -1;

     }   

     soap_set_namespaces(soap,namespaces);    //设置命名空间    

soap->recv_timeout = 5;      //设置接收Probematchs时间,超过5秒钟没有数据就退出

soap_default_SOAP_ENV__Header(soap,&header);   //将header设置为soap消息的头属性

/*****给头赋值******/

     header.wsa__MessageID =buf;                     

     header.wsa__To="urn:schemas-xmlsoap-org:ws:2005:04:discovery";

     header.wsa__Action="http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";

     soap->header = &header;

     /*设置所需寻找设备的类型和范围,二者至少设定一个,否则可能收到非ONVIF设备,出现异常*/

     soap_default_wsdd__ScopesType(soap,&sScope);

     sScope.__item ="onvif://www.onvif.org";     //设置所需设备的sScope

     soap_default_wsdd__ProbeType(soap,&req);     

     req.Scopes = &sScope;

     req.Types ="tdn:NetworkVideoTransmitter";

     /*设置所需设备的类型,tdn为命名空间前缀,为wsdd.nsmap文件中{"tdn","http://www.onvif.org/ver10/network/wsdl"}的tdn,如果不是tdn,而是其它,如ns1这里也要随之改为ns1*/

 

     //通过组播发送Probe探针,发送成功返回0,否则-1

result = soap_send___wsdd__Probe(soap,"soap.udp://239.255.255.250:3702", NULL, &req);

     if(result==-1)

     {

   cout<<"soap error:"<<soap->error<<soap_faultcode(soap)

<<"---"<<soap_faultstring(soap)<<endl; 

     }else                  

     {

         do{    

             result = soap_recv___wsdd__ProbeMatches(soap,&resp);

//接收ProbeMatches,成功返回0,否则-1 

              if (result==-1)   

               {

               cout<<"共发现"<<count<<"个设备"<<endl;

cout<<"soap error:"<<soap->error<<soap_faultcode(soap)

<<"---"<<soap_faultstring(soap)<<endl;

                break;

                }else  

               {

                    count++;

                    cout<<"========================================="<<endl;              

                    cout<<"UUID:"<<""<<resp.wsdd__ProbeMatches->ProbeMatch->

wsa__EndpointReference.Address<<endl;             

cout<<"Type:"<<""<<resp.wsdd__ProbeMatches->ProbeMatch->Types<<endl;

                    cout<<"Scopes:"<<""<< resp.wsdd__ProbeMatches->

ProbeMatch->Scopes->__item<<endl;                       

                    cout<<"DeviceService Address:"<<""<<resp.wsdd__ProbeMatches->

ProbeMatch->XAddrs<<endl;                      

                    cout<<"MetadataVersion:"<<""<<resp.wsdd__ProbeMatches->

ProbeMatch->MetadataVersion<<endl;

                }

          }while(1);

     }                       

/********清除变量************/

     soap_destroy(soap); // removedeserialized class instances (C++ only)

     soap_end(soap);     //clean up and remove deserialized data

     soap_done(soap);

     return result;

}

五、CMakeList说明

  • soap目录编译成了libonvif_soap,依赖openssl,还需要定义两个宏WITH_OPENSSL和 WITH_DOM
  • onvif目录编译成了libonvif,依赖libonvif_soap.
cmake_minimum_required(VERSION 3.0)
project(OnvifDemo)
 
set(CMAKE_CXX_STANDARD 11)
 
set(CMAKE_CXX_FLAGS "-g -O0")
 
set(LIB_SOAP_SRC
    soap/struct_timeval.cpp
    soap/duration.cpp
    soap/wsaapi.cpp
    soap/dom.cpp
    soap/wsseapi.cpp
    soap/smdevp.cpp
    soap/mecevp.cpp
    soap/threads.cpp
    soap/stdsoap2.cpp)
 
add_library(onvif_soap STATIC ${LIB_SOAP_SRC})
target_link_libraries(onvif_soap PUBLIC ssl crypto)
target_compile_definitions(onvif_soap PUBLIC WITH_OPENSSL WITH_DOM)
target_include_directories(onvif_soap PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/onvif)
 
add_library(onvif STATIC onvif/soapC.cpp onvif/soapClient.cpp)
target_include_directories(onvif PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(onvif PUBLIC onvif_soap)
 
add_executable(dev_scan tests/scan_device.cpp)
target_link_libraries(dev_scan PRIVATE onvif)

六、调试过程注意事项

1)出现如下语法错误

error C2143:语法错误 : 缺少“{”(在“:”的前面)

error C2059:语法错误 : “:”

error C2143:语法错误 : 缺少“{”(在“:”的前面)

需要将工程中的.c文件改成.cpp文件即可

2)无法解析的外部命令错误soap_check_faultsubcode

在stdsoap2.h中,声明的soap_check_faultsubcode(structsoap *soap)函数在soapC.cpp中未实现, 可在soapC.cpp中添加如下实现

SOAP_FMAC3 const char * SOAP_FMAC4soap_check_faultsubcode(struct soap *soap)

{

    soap_fault(soap);

    if(soap->version == 2)

    {  

if(soap->fault->SOAP_ENV__Code &&soap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode &&soap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode)

returnsoap->fault->SOAP_ENV__Code->SOAP_ENV__Subcode->SOAP_ENV__Value;

        return NULL;

    }

    returnsoap->fault->faultcode;

}

3) 无法解析的外部命令错误soap_check_faultdetail

在stdsoap2.h中,声明的soap_check_faultdetail(struct soap *soap)函数在soapC.cpp中未实现,,可在soapC.cpp中添加如下实现

SOAP_FMAC3 const char * SOAP_FMAC4soap_check_faultdetail(struct soap *soap)

{

    soap_fault(soap);

    if(soap->version == 2 && soap->fault->SOAP_ENV__Detail)

        returnsoap->fault->SOAP_ENV__Detail->__any;

    if(soap->fault->detail)

        return soap->fault->detail->__any;

    returnNULL;

}

4) 出现无法解析的外部符号_soap_in_xsd__duration

无法解析的外部符号_soap_in_xsd__duration,该符号在函数_soap_getelement中被引用soapC.obj : error LNK2019: 无法解析的外部符号_soap_out_xsd__duration,该符号在函数_soap_putelement中被引用

soapC.obj: error LNK2019: 无法解析的外部符号_soap_default_xsd__duration,该符号在函数_soap_default__tse__FindMetadata中被引用

需要将custom文件夹下面的duration.h和duration.c导入工程中

5)如果是调用soap_call_XXXX_Probe()来实现设备发现时,不能发现所有onvif设备

该函数实现过程中只有一次接收过程,所以无法发现所有的设备的问题。如果使用该函数,还需要对函数的实现做以下更改:

函数的接收部分,将原来的XXXX:Response更改为YYYY:ProbeMatches

其中,

6)在VS中出现fatal error C1128: 节数超过对象文件格式限制:请使用/bigobj 进行编译的错误

这是由于源代码文件太大,需添加选项/bigobj,在项目属性-> C/C++ ->命令行的附加选项中添加/bigobj

七、总结

1)了解gsoap工具的使用方法、编程方法以及文件结构,参考Genivia - gSOAP 用户指南,可根据需要查找相关内容

2)学会利用抓包工具,用于分析客户端所发出的消息,以及服务端回复的消息

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值