Qt编写Onvif搜索及云台控制工具
一、前言
这个工具很早以前大概在2013年就想做了,后面杂七杂八的事情一再耽搁,记得当时最初用的是soap类来搜索和解析的,后面发现太大了,每次编译都要等好久,光源码文件加起来都快10MB了,而且函数名非常另类,大量的下划线等,反正本人非常不适应,近期经过一个朋友(QQ:408815041)的前期探索,对整个处理流程熟悉以后,发现其实用纯Qt也可以实现,核心就是udp搜索+post数据。
本程序框架的最大难点在找出对应的数据以及节点数据解析。找出对应的数据可以直接使用官方的ONVIF Device Test Tool,抓包即可。数据解析一开始采用xml的节点解析,发现根本行不通,因为返回的数据不是标准的xml数据,而是soap格式的数据,需要用QXmlQuery来解析。本程序只实现了设备信息的搜索和云台控制,并未实现服务端,服务端一般是IPC或者NVR上来实现。
体验地址:https://pan.baidu.com/s/1bbL2ZughZAgfIGrexyN-9g 提取码:zkeh,下面的bin_onviftool.zip,如果是XP系统,请先执行目录下的fixff.cmd。
二、Onvif介绍
ONVIF致力于通过全球性的开放接口标准来推进网络视频在安防市场的应用,这一接口标准将确保不同厂商生产的网络视频产品具有互通性。2008年11月,正式发布了ONVIF第一版规范——ONVIF核心规范1.0。随着视频监控的网络化应用,产业链的分工将越来越细。有些厂商专门做摄像头,有些厂商专门做DVS,有些厂商则可能专门做平台等,然后通过集成商进行集成,提供给最终客户。这种产业合作模式,已经迫切的需要行业提供越来越标准化的接口平台。
ONVIF规范描述了网络视频的模型、接口、数据类型以及数据交互的模式。并复用了一些现有的标准,如WS系列标准等。ONVIF规范的目标是实现一个网络视频框架协议,使不同厂商所生产的网络视频产品(包括摄录前端、录像设备等)完全互通。
ONVIF规范中设备管理和控制部分所定义的接口均以Web Services的形式提供,设备作为服务提供者为服务端。ONVIF规范涵盖了完全的XML及WSDL的定义。每一个支持ONVIF规范的终端设备均须提供与功能相应的Web Service。服务端与客户端的数据交互采用SOAP协议。ONVIF中的其他部分比如音视频流则通过RTP/RTSP进行。
三、处理流程
- 绑定组播IP(239.255.255.250)和端口(3702),发送固定的xml格式的数据搜索设备。
- 接收到的xml格式的数据解析,得到设备的Onvif地址。
- 对Onvif地址发送对应的数据,收到数据取出对应的节点数据。
- 请求Onvif地址获取Media地址和Ptz地址,Media地址用来获取详细的配置文件,Ptz地址用来云台控制。
- ptz控制是对Ptz地址发送对应的数据即可。
- 设置了用户认证的需要组织用户token信息一块发送,每次都需要作鉴权处理。
- 接收到的数据不是标准的xml数据,没法按照正常的节点解析来处理,只能用QXmlQuery来做。
- 每个厂家设备返回的数据未必完全一致,基本上都不一致,需要进行模糊查找节点值。
- 特意采用底层协议解析,因为soap太臃肿函数名称太另类,特意做的轻量级的。
- 两个必备工具,Onvif Device Manager 和 Onvif Device Test Tool。
四、功能特点
- 广播搜索设备,支持IPC和NVR,依次返回,可选择不同的网卡IP。
- 依次获取Onvif地址、Media地址、Profile文件、Rtsp地址。
- 可对指定的Profile获取视频流Rtsp地址,比如主码流子码流地址。
- 可对每个设备设置Onvif用户信息,用于认证获取详细信息。
- 可实时预览摄像机图像。
- 支持云台控制,可上下左右调节云台,支持绝对移动和相对移动,可放到和缩小图像远近。
- 支持Qt4和Qt5任意Qt版本,亲测Qt4.7.0到Qt5.12.4。
- 支持任意编译器,亲测mingw、msvc、gcc、clang。
- 支持任意操作系统,亲测xp、win7、win10、linux、嵌入式linux、树莓派全志H3等。
- 支持任意Onvif摄像机和NVR,亲测海康、大华、宇视、华为、海思芯片内核等,可定制开发。
- 支持对指定IP地址进行单播搜索,比如跨网段情况下非常有用。
- 纯Qt编写,超级小巧轻量,总共约2000行代码,不依赖任何第三方的库和组件,跨平台。
- 封装好了通用的数据发送和接收解析的函数,可以非常方便的自行拓展其他Onvif处理比如修改IP等。
- 工具上提供了收发数据文本框,显示收发的数据,方便查看和分析。
- 支持所有Onvif设备,代码工整,接口友好,直接引入pri即可使用。
五、效果图

六、核心代码
#include "qonvifsearch.h"
#include "qonviffunction.h"
#include "qonvifquery.h"
//onvif协议固定的IP和端口
#define OnvifAddr QHostAddress("239.255.255.250")
#define OnvifPort 3702
QOnvifSearch::QOnvifSearch(QObject *parent) : QObject(parent)
{
isOk = false;
//定时器排队发送搜索命令,有好几种
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(sendData()));
timer->setInterval(300);
udpSocket = new QUdpSocket(this);
#if (QT_VERSION >= QT_VERSION_CHECK(4,8,5))
udpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption, 1);
#endif
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readData()));
}
QOnvifSearch::~QOnvifSearch()
{
if (timer->isActive()) {
timer->stop();
}
}
void QOnvifSearch::sendData()
{
QByteArray data = QOnvifFunction::getFile(currentFile);
if(!data.isEmpty()) {
data = QString(data).arg(QOnvifFunction::getUuid()).toUtf8();
udpSocket->writeDatagram(data, OnvifAddr, OnvifPort);
emit sendData(data);
}
//依次发送数据,如果到了最后一个则停止
//根据onvif device test工具抓包分析,只要发送前面两个就行,后面两个是ONVIF Device Manager抓包的
//在收到结果的地方要对重复的进行过滤,因为部分设备两种协议请求都会返回
if (currentFile == ":/send/search1.xml") {
currentFile = ":/send/search2.xml";
} else if (currentFile == ":/send/search2.xml") {
currentFile = ":/send/search3.xml";
} else if (currentFile == ":/send/search3.xml") {
currentFile = ":/send/search4.xml";
} else if (currentFile == ":/send/search4.xml") {
timer->stop();
}
}
void QOnvifSearch::readData()
{
QByteArray data;
QHostAddress host;
quint16 port = 0;
while (udpSocket->hasPendingDatagrams()) {
data.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(data.data(), data.size(), &host, &port);
emit receiveData(data);
}
QOnvifQuery query;
query.setData(data);
QString addr_path = QString("//%1:ProbeMatches/%1:ProbeMatch/%1:XAddrs").arg(query.getDiscovery());
QString scopes_path = QString("//%1:ProbeMatches/%1:ProbeMatch/%1:Scopes").arg(query.getDiscovery());
QString addr = query.getValue(addr_path);
QString scopes = query.getValue(scopes_path);
if(!addr.isEmpty()) {
//过滤下IPV6地址 http://192.168.1.64/onvif/device_service http://[fe80::9a8b:aff:fe6e:867c]/onvif/device_service
QStringList list = addr.split(" ");
addr = list.first();
//过滤掉重复的设备,发送搜索设备的命令有好几种,某些设备支持多种命令,所以会返回多次
foreach (DeviceInfo deviceInfo, deviceInfos) {
if (deviceInfo.addr == addr) {
return;
}
}
//定义结构体存储设备信息
DeviceInfo deviceInfo;
deviceInfo.addr = addr;
deviceInfo.ip = QOnvifFunction::getIP(addr);
//取出其他信息 onvif://www.onvif.org/type/NetworkVideoTransmitter onvif://www.onvif.org/name/NVR onvif://www.onvif.org/hardware/hisi onvif://www.onvif.org/location/shanghai
//这里的信息是通过广播搜索返回的无需密码,这里还可以根据打印出来的 scopes 自行增加设备信息
list = scopes.split(" ");
foreach (QString str, list) {
QStringList l = str.split("/");
if (l.contains("name")) {
deviceInfo.name = l.last();
} else if (l.contains("location")) {
deviceInfo.location = l.last();
} else if (l.contains("hardware")) {
deviceInfo.hardware = l.last();
}
}
deviceInfos << deviceInfo;
emit receiveDevice(deviceInfo);
emit receiveInfo(QString("发现新设备-> %1").arg(addr));
}
}
bool QOnvifSearch::search(const QString &ip)
{
deviceInfos.clear();
if (!QOnvifFunction::isIP(ip)) {
return false;
}
//如果还未成功则先绑定
if (!isOk) {
isOk = udpSocket->bind(QHostAddress(ip), 0, QUdpSocket::ShareAddress);
//udpSocket->joinMulticastGroup(OnvifAddr);
}
if (isOk) {
//之前是直接全部放在这里发送,发现部分设备要好几次才能回来
//改成定时器排队发送多种广播搜索数据,就没有问题
currentFile = ":/send/search1.xml";
timer->stop();
timer->start();
} else {
emit receiveError(QString("绑定组播失败-> %1").arg(udpSocket->errorString()));
}
return isOk;
}
QList<QOnvifSearch::DeviceInfo> QOnvifSearch::getDeviceInfos()
{
return this->deviceInfos;
}
QStringList QOnvifSearch::getAddrs()
{
QStringList addrs;
foreach (DeviceInfo deviceInfo, deviceInfos) {
addrs << deviceInfo.addr;
}
return addrs;
}
Qt编写Onvif搜索及云台控制工具的更多相关文章
- Qt编写气体安全管理系统28-模拟工具
一.前言 模拟工具在一些涉及到硬件通信的程序中特别有用,也特别需要,回顾这十年来做过的项目,95%的项目都是软硬件交互的,貌似软硬件结合的项目更有生命力一些,纯软件的或者纯硬件的,并没有那么好控制,如 ...
- Qt编写项目作品大全(自定义控件+输入法+大屏电子看板+视频监控+楼宇对讲+气体安全等)
一.自定义控件大全 (一).控件介绍 超过160个精美控件,涵盖了各种仪表盘.进度条.进度球.指南针.曲线图.标尺.温度计.导航条.导航栏,flatui.高亮按钮.滑动选择器.农历等.远超qwt集成的 ...
- EasyNVR网页摄像机无插件H5、谷歌Chrome直播方案-Onvif(三)使用Onvif协议进行设备PTZ云台控制
背景分析 熟悉EasyNVR产品的盆友们应该都知道,EasyNVR主要完成的是RTSP视频流到RTMP/HLS/Flv的转码,并提供了一套api和一个可视化管理平台来便于调用.同时支持ONVIF协议进 ...
- Qt编写的开源帖子集合(懒人专用)
回顾自己学习Qt以来九年了,在这九年多时间里面,从本论坛学习不到不少的东西,今天特意整了一下自己开源过的资源的帖子,整理一起方便大家直接跳转下载,不统计不知道,一统计吓一跳,不知不觉开源了这么多代码, ...
- Qt编写安防视频监控系统18-云台控制
一.前言 云台控制是视频监控系统中必备的一个功能,对球机进行上下左右的移动,还有焦距的控制,其实核心就是控制XYZ三个坐标轴,为了开发这个模块,特意研究了各种云台控制的方法和开源库比如soap,有些厂 ...
- Qt编写安防视频监控系统16-设备播放
一.前言 设备播放模块是后面增加的,核心就是通过组合rtsp视频流地址来播放实时视频和历史视频,目前市面上很多厂家比如排第一的海康都是支持直接rtsp通过NVR来播放某个通道视频流和回放某个通道的视频 ...
- Qt小项目之串口助手控制LED
Qt小项目之串口助手控制LED 前言 最近刚学了一点Qt开发上位机,尝试着做个小软件练练手.查找了很多资料,做了一个简单的串口助手,可以实现串口基本发送和接收功能,支持中文显示,还可以控制STM32开 ...
- Qt编写安防视频监控系统17-在线地图
一.前言 在线地图模块在一开始设计整个系统的时候就考虑进去了,主要功能就是在摄像机管理中,提供经纬度信息,然后加载百度地图在浏览器中显示,根据摄像机信息表中的每个摄像机的经纬度信息,自动生成设备点在地 ...
- Qt编写安防视频监控系统14-本地回放
一.前言 在上一篇文章将视频文件存储好了,需要提供界面方便用户查询视频文件进行回放,其实这个回放就是播放历史存储的视频文件,并不是什么高大上的东西,视频回放在这个系统中分三种,第一种是本地回放,回放存 ...
随机推荐
- 数据结构(python)
列表 list 在头部进行插入是个相当耗时的操作(需要把后边的元素一个一个挪个位置).假如你需要频繁在数组两头增删,list 就不太合适.数组是最常用到的一种线性结构,其实 python 内置了一个 ...
- celery timeout的拦截
0X01 场景 celery任务超时报错,想查看是传入哪一类数据运行时导致的超时(哪一个插件),但是该报错难以拦截. [2019-06-30 17:23:21,070: ERROR/MainProce ...
- 使用PS进行切图
一,设置PS 使用PS进行切图前的设置: 1,打开PS----打开PSD图片----点击窗口-----分别把:历史记录,信息,图层,三个打勾. 历史记录:可以回到之前想要的步骤,特别是不小心把图层的文 ...
- 25 | MySQL是怎么保证高可用的?
在上一篇文章中,我和你介绍了binlog的基本内容,在一个主备关系中,每个备库接收主库的binlog并执行. 正常情况下,只要主库执行更新生成的所有binlog,都可以传到备库并被正确地执行,备库就能 ...
- Oracle 通过sqlnet.ora文件控制对Oracle数据库的访问
一.通过sqlnet.ora文件控制对Oracle数据库的访问 出于数据安全考虑,对Oracle数据库的IP做一些限制,只有固定的IP才能访问.修改$JAVA_HOME/NETWORK/ADMIN/s ...
- BZOJ 2839: 集合计数 广义容斥
在一个 $N$ 个元素集合中的所有子集中选择若干个,且交集大小为 $k$ 的方案数. 按照之前的套路,令 $f[k]$ 表示钦定交集大小为 $k$,其余随便选的方案数. 令 $g[k]$ 表示交集恰好 ...
- 数据结构实验之查找五:平方之哈希表 (SDUT 3377)
Hash表的平方探测思路:如果当前这个没存放数值,就放进去,如果当前这个地方Hash [ i ] 已经有数值了,就以平方的间隔左右寻找没有存放数的空白 Hash [ i ]. #include < ...
- 转载:CentOS 6.5下安装Python 3.5.2(与Python2并存)
原文:https://www.jb51.net/article/115370.htm 这篇文章主要给大家介绍了在CentOS 6.5下安装Python 3.5.2的方法教程,安装后的python3与P ...
- P3180 [HAOI2016]地图
P3180 [HAOI2016]地图 显然,这是一个仙人掌图 inline void tarjan(LL u,LL fa){ low[u]=dfn[u]=++tot, pre[tot]=u; for( ...
- hadoop 2.x HA 出现ssh不能解析问题记录。
在docker里面安装hadoop HA 在启动或者停止的时候报ssh不能解析问题. 问题现象: 发现图片不清晰:把问题现象粘贴如下: root@master:/usr/local/hadoop-2. ...