C语言开发:Onvif(一)

根据ONVIF官网 的介绍:

ONVIF是一个开放的安防行业组织,致力于为安防行业提供和促进标准化开放接口,以实现IP网络安防产品和服务的有效互操作性。

在具体实现上,ONVIF使用了Web Service的方式,设备通过WSDL定义的接口提供服务。ONVIF支持的接口众多,本文仅涉及使用C语言与Onvif摄像机互操作的过程。

C语言使用Web Service

在C语言中使用Web Service,可以用gsoap来自动生相应的实现。

方法分为三步:

  1. 安装gsoap软件包。
  2. 取得Web Service的xsd、wsdl。
  3. 生成接口函数。
  4. 调用接口函数,完成Web Service的使用。

安装gsoap软件包

安装gsoap软件包的过程,与其它软件并无二致。唯一需要注意的是,安装的版本如果比较低,可能个别API的实现稍有不同。

另外,有的系统上把gsoap分成了gsoap与gsoap-devel多个包。因为我们是开发Web Service,所以需要安装gsoap-devel包,安装完成之后,/usr/share/gsoap目录下会有:

~/$ ls /usr/share/gsoap/  
custom  import  plugin  WS

这些目录。

对于不同的Web Service服务,会使用这里面提供的实现。

比如,如果我们的Onvif摄像机需要认证,就需要使用/usr/share/gsoap/plugin里面的httpda.hhttpda.c等实现。

取得Web Service的xsd、wsdl

与Onvif摄像机取流相关的文件,大概有:

b-2.xsd   common.xsd       event.wsdl   media.wsdl  t-1.xsd      ws-discovery.wsdl  
bf-2.xsd  devicemgmt.wsdl  media2.wsdl  onvif.xsd   typemap.dat

其中,xsd主要是一些结构定义,wsdl则是接口定义。这些文件可以从Onvif 官网的网络接口规范页面下载。

生成接口函数

我们使用gsoap的工具软件,根据这些wsdl文件,生成接口函数。

主要使用两个工具,wsdl2h与soapcpp2。

wsdl2h

wsdl2h的功能,是把我们下载的xsd、wsdl等文件,生成相应的数据结构以及接口定义。参数比较多,我们只需要调整其中的很少的一部分参数就足够了。

比如:

wsdl2h -c -d -o onvif.h -t typemap.dat *.xsd *.wsdl

其中,

  • -c 表示生成C语言的定义
  • -d 表示使用Dom来表示xs:any等
  • -o onvif.h 表示生成到onvif.h这个头文件中
  • -t typemap.dat 表示使用自定义的typemap

执行完成之后,将会生成一个onvif.h头文件。我们的程序中,使用这个头文件即可完成Web Service相关函数的引入。

soapcpp2

soapcpp2的功能是根据onvif.h来生成接口实现的代码片段。

如:

soapcpp2 -c -d ./impl -L -x -T -I/usr/include

其中,

  • -c 表示生成C语言源文件
  • -d 表示生成文件的路径
  • -L 表示不用生成Server相关的实现
  • -x 表示不用生成示例消息文件
  • -T 表示生成Server测试代码
  • -I 表示头文件包含路径

我们执行上面的命令,将在./impl 目录中得到soapC.c、soapClient.c、soapServer.c 等源文件。

当然,为了做Onvif的认证授权,我们还需要在项目中编译连接

wsseapi.c  
mecevp.c  
smdevp.c  
wsaapi.c  
wsddapi.c  
httpda.c

等源文件。

使用接口函数

有了onvif.h头文件,又有了soapC.c等实现文件,我们就可以使用Onvif的相关函数,进行Onvif的开发了。

使用gsoap生成的接口函数,核心需要一个struct soap结构的指针。

使用struct soap的大概步骤为:

  1. 生成struct soap指针
  2. 执行struct soap相应的函数
  3. 释放struct soap指针

其中在第二步,也就是使用struct soap相应的函数过程中,会使用我们前面根据wsdl生成的接口函数,来处理Web Service相应的结构。

生成struct soap指针

生成struct soap的方法为使用soap_new()函数。

如果打开/usr/include/stdsoap2.h查看,会发现struct soap结构的定义很长,包括了各种各样的参数。

其中大部分参数,都可以见文知义,只有一少部分,需要额外解释。

比如,

  • user 上层应用的指针
  • modeimodeomode指定协议,比如使用soap_new1(SOAO_IO_UDP)来生成一个UDP的soap结构。
  • bind_flags 绑定的标识,比如SO_REUSEADDR。

以下代码,生成了一个struct soap,又设置了一些超时相关的参数,最后注册了HTTP认证插件。

struct soap *s;s = soap_new ();  s->connect_timeout = 2;  
s->recv_timeout = 2;  
s->send_timeout = 2;  
s->transfer_timeout = 2;soap_register_plugin (service->s, http_da);

释放struct soap指针

soap_destroy (s);
soap_end (s);
soap_free (s);

执行struct soap相应的函数

void
soap_getdeviceinformation (struct soap *soap)  
{  struct _tds__GetDeviceInformation req[1];  struct _tds__GetDeviceInformationResponse response[1];int res;  res = soap_call___tds__GetDeviceInformation(soap, req, response);if (res == 0){  if (response->SerialNumber != NULL)  {    printf ("Manufacturer: %s\n",  response->Manufacturer); printf ("Model: %s\n", response->Model);  printf ("FirmwareVersion: %s\n", response->FirmwareVersion);  printf ("SerialNumber: %s\n", response->SerialNumber);  printf ("HardwareId: %s\n", response->HardwareId);}}  soap_destroy(soap);soap_end(soap);  
}

以上代码中,struct _tds__GetDeviceInformationstruct _tds__GetDeviceInformationResponse结构,以及soap_call___tds__GetDeviceInformation函数的定义,都是gsoap的工具自动生成的。

soapClient.c中, soap_call___tds__GetDeviceInformation实现如下:

SOAP_FMAC5 int SOAP_FMAC6 soap_call___tds__GetDeviceInformation(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct _tds__GetDeviceInformation *tds__GetDeviceInformation, struct _tds__GetDeviceInformationResponse *tds__GetDeviceInformationResponse)  
{   if (soap_send___tds__GetDeviceInformation(soap, soap_endpoint, soap_action, tds__GetDeviceInformation) || soap_recv___tds__GetDeviceInformation(soap, tds__GetDeviceInformationResponse))  return soap->error;  return SOAP_OK;  
}

这个函数的下面,就是soap_send___tds__GetDeviceInformationsoap_recv___tds__GetDeviceInformation的实现,也都是这样类似的代码:

SOAP_FMAC5 int SOAP_FMAC6 soap_send___tds__GetDeviceInformation(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct _tds__GetDeviceInformation *tds__GetDeviceInformation)
{	struct __tds__GetDeviceInformation soap_tmp___tds__GetDeviceInformation;if (soap_action == NULL)soap_action = "http://www.onvif.org/ver10/device/wsdl/GetDeviceInformation";soap_tmp___tds__GetDeviceInformation.tds__GetDeviceInformation = tds__GetDeviceInformation;soap_begin(soap);soap->encodingStyle = NULL; /* use SOAP literal style */soap_serializeheader(soap);soap_serialize___tds__GetDeviceInformation(soap, &soap_tmp___tds__GetDeviceInformation);if (soap_begin_count(soap))return soap->error;if ((soap->mode & SOAP_IO_LENGTH)){	if (soap_envelope_begin_out(soap)|| soap_putheader(soap)|| soap_body_begin_out(soap)|| soap_put___tds__GetDeviceInformation(soap, &soap_tmp___tds__GetDeviceInformation, "-tds:GetDeviceInformation", "")|| soap_body_end_out(soap)|| soap_envelope_end_out(soap))return soap->error;}if (soap_end_count(soap))return soap->error;if (soap_connect(soap, soap_endpoint, NULL)|| soap_envelope_begin_out(soap)|| soap_putheader(soap)|| soap_body_begin_out(soap)|| soap_put___tds__GetDeviceInformation(soap, &soap_tmp___tds__GetDeviceInformation, "-tds:GetDeviceInformation", "")|| soap_body_end_out(soap)|| soap_envelope_end_out(soap)|| soap_end_send(soap))return soap_closesock(soap);return SOAP_OK;
}SOAP_FMAC5 int SOAP_FMAC6 soap_recv___tds__GetDeviceInformation(struct soap *soap, struct _tds__GetDeviceInformationResponse *tds__GetDeviceInformationResponse)
{if (!tds__GetDeviceInformationResponse)return soap_closesock(soap);soap_default__tds__GetDeviceInformationResponse(soap, tds__GetDeviceInformationResponse);if (soap_begin_recv(soap)|| soap_envelope_begin_in(soap)|| soap_recv_header(soap)|| soap_body_begin_in(soap))return soap_closesock(soap);soap_get__tds__GetDeviceInformationResponse(soap, tds__GetDeviceInformationResponse, "tds:GetDeviceInformationResponse", NULL);if (soap->error)return soap_recv_fault(soap, 0);if (soap_body_end_in(soap)|| soap_envelope_end_in(soap)|| soap_end_recv(soap))return soap_closesock(soap);return soap_closesock(soap);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/912065.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/912065.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中科米堆三维扫描仪耳机3D扫描尺寸测量数字化建模

当下,耳机已从单纯的音频输出设备进化为集娱乐、健康、办公于一体的智能穿戴终端。相关数据显示,2025年全球智能个人音频设备出货量突破4.55亿台,中国以22%的增速领跑全球,其中开放式耳机(OWS)出货量占比达…

学习接口自动化框架pytest有哪些好处?

学习 pytest 作为接口自动化测试框架,具有以下显著优势,能大幅提升测试效率和质量: Pytest自动化测试教程,自动化必备之Pytest测试框架训练营,只需一小时速成,学会直接上手实操! 1. 代码简洁&…

LinuxBridge的作用与发展历程:从基础桥接到云原生网络基石

LinuxBridge作为Linux网络虚拟化的核心组件,已悄然支撑互联网基础设施20余年。它不仅是虚拟机网络连接的桥梁,更是容器网络、云原生架构的隐形支柱。 一、LinuxBridge的核心作用剖析 1. 二层网络虚拟化的实现者 本质功能:模拟物理交换机行为…

探讨 SYSCFG 时钟对 ADC 采样的影响

探讨 SYSCFG 时钟对 ADC 采样的影响 在嵌入式系统开发中,对于 GD32F4 系列微控制器,理解 SYSCFG 时钟与 ADC 采样之间的关系至关重要。 以下是详细分析: 一、SYSCFG 时钟对 ADC 采样过程的基础性作用 1. 提供采样时钟信号 ADC 采样需要时钟…

Spring Boot 项目实训 - 图书信息网站

文章目录 1. 实训目的2. 系统设计3. 运行演示4. 实现步骤4.1 创建数据库与表4.2 创建Spring Boot项目4.3 创建实体类4.4 创建映射器接口4.5 编写应用配置文件4.6 测试映射器接口4.7 创建服务类4.8 创建控制器4.9 准备静态资源4.10 创建模板页面4.11 测试整个项目 5. 实训总结 1…

GPU 性能可变性分析框架

大家读完觉得有帮助记得关注和点赞!!! 抽象。 分析来自 GPU 分析器的大规模性能日志通常需要数 TB 的内存和数小时的运行时间,即使是基本摘要也是如此。这些限制会阻止及时洞察,并阻碍将性能分析集成到自动化工作流程中…

Redis主从复制原理

一、Redis主从复制概述 Redis主从复制(Master-Slave Replication)是Redis实现高可用性和读写分离的基础架构。通过主从复制,数据可以从一个Redis服务器(主节点)复制到一个或多个Redis服务器(从节点&#x…

将ONNX模型转换为(OPENMV可用的格式)TensorFlow Lite格式

将ONNX模型转换为TensorFlow Lite格式 在深度学习模型部署过程中,我们常常需要将模型从一种格式转换为另一种格式,以适应不同的硬件平台和应用场景。本文将详细介绍如何将ONNX格式的模型转换为TensorFlow Lite格式,以便在移动设备或嵌入式设…

EXILIUM×亚矩云手机:重构Web3虚拟生存法则,开启多端跨链元宇宙自由征途

在链游与元宇宙赛道竞争加剧的当下,EXILIUM凭借其去中心化开放世界、链上资产确权与玩家自治经济系统,成为Web3原住民逃离“中心化牢笼”的首选之地。然而,其多链交互门槛高、跨设备身份管理复杂、链上安全风险频发等问题,让普通玩…

用3个字符表示2字节二进制数据

把1字节二进制数据&#xff0c;用可打印字符表示&#xff0c;可用十六进制。这样一来&#xff0c;1字节变2字节&#xff0c;2倍。 2字节的二进制数据&#xff0c;可以用3个字符来表示&#xff0c;1.5倍。 2562略小于413&#xff0c;65536<68921 需要准备41个符号 包括&…

第 3 章:神经网络如何学习

第 3 章&#xff1a;神经网络如何学习 在第二章中&#xff0c;我们详细了解了神经网络的静态结构&#xff1a;由神经元组成的层&#xff0c;以及连接它们的权重和偏置。现在&#xff0c;我们将进入整个教程最核心的部分&#xff1a;神经网络是如何从数据中"学习"的&…

RocketMQ 消息长轮询

文章目录 问题所在&#xff1a;消费者如何高效地获取消息&#xff1f;解决方案&#xff1a;长轮询 (Long Polling - “等待与观察”模式)长轮询 vs. 短轮询&#xff08;可视化对比&#xff09;为什么这个机制对 RocketMQ 这么好&#xff1f;关键的配置参数 让我们用一个简单易懂…

TensorFlow Serving学习笔记3: 组件调用关系

一、整体架构 TensorFlow Serving 采用模块化设计&#xff0c;核心组件包括&#xff1a; Servables&#xff1a;可服务对象&#xff08;如模型、查找表&#xff09;Managers&#xff1a;管理 Servable 生命周期&#xff08;加载/卸载&#xff09;Loaders&#xff1a;负责 Ser…

视图、索引介绍

目录 1、视图 1.1、什么是视图 1.2、创建视图 1.3、使用视图 1.4、修改视图 1.5、删除视图 1.6、视图的优点 2、MySQL存储结构 2.1、MySQL中的页 3、索引 3.1、索引的数据结构 3.2、B树 和 B树 3.3、B树在MySQL索引中的应用 3.4、索引分类 1、视图 1.1、什么是视…

QT6(46)5.2 QStringListModel 和 QListView :列表的模型与视图的界面搭建与源代码实现

&#xff08;154&#xff09;理论讲解 &#xff1a; 例题程序的界面搭建 &#xff1a; &#xff08;155&#xff09;以下开始完善代码 &#xff0c;先准备要给 model 的源数据&#xff0c;一些字符串 &#xff1a; 给出该头文件&#xff0c;以全面展示其内容&#xff1a; #i…

C++设计模式(GOF-23)——03 C++观察者模式(Observer / Event、发布-订阅模式、事件模式)

文章目录 一、观察者模式概述二、传统代码 vs 观察者模式对比1. 传统实现&#xff08;紧耦合&#xff09;2. 观察者模式实现&#xff08;松耦合&#xff09; 三、Mermaid 类图说明四、核心设计要点1. 接口分层设计2. 通知机制实现3. 扩展性验证 五、应用场景与注意事项适用场景…

海外 AI 部署:中国出海企业如何选择稳定、安全的云 GPU 基础设施?

2025年&#xff0c;中国 AI 企业在模型训练、产品落地和创新应用上不断刷新人们的认知。DeepSeek-R1、Qwen3 等国产大模型密集亮相&#xff0c;国内大模型产业热潮持续升温。与此同时&#xff0c;一个现实的问题也在被越来越多企业关注&#xff1a;模型虽然训练得起&#xff0c…

AI绘画工具实测:Stable Diffusion本地部署指

对于想要深度体验AI绘画的创作者来说&#xff0c;本地部署Stable Diffusion能带来更自由的创作空间。本文将详细介绍Windows系统下的部署流程&#xff0c;帮助你在个人电脑上搭建专业的AI绘画环境。 硬件准备与基础环境配置 部署前需确认电脑配置&#xff1a;建议NVIDIA显卡&…

macOS - 快速上手使用 YOLO

文章目录 一、关于 yolo二、安装三、命令行使用官方示例yolo cfgyolo predict 四、Python 调用results 数据 一、关于 yolo YOLO(YOLO&#xff08;You Only Look Once&#xff09;是一种流行的物体检测和图像分割模型&#xff0c;由华盛顿大学的约瑟夫-雷德蒙&#xff08;Jose…

<script setup> 语法糖

下面&#xff0c;我们来系统的梳理关于 Vue 3 <script setup> 语法糖 的基本知识点&#xff1a; 一、<script setup> 核心概念 1.1 什么是 <script setup>&#xff1f; <script setup> 是 Vue 3 中 Composition API 的编译时语法糖&#xff0c;它通过…