Qt如何编写安防视频监控系统实现onvif事件订阅

发布时间:2021-12-15 10:23:54 作者:iii
来源:亿速云 阅读:250
# Qt如何编写安防视频监控系统实现ONVIF事件订阅

## 目录
1. [ONVIF协议概述](#onvif协议概述)
2. [系统架构设计](#系统架构设计)
3. [Qt开发环境配置](#qt开发环境配置)
4. [ONVIF设备发现与鉴权](#onvif设备发现与鉴权)
5. [事件订阅机制实现](#事件订阅机制实现)
6. [事件处理与业务逻辑](#事件处理与业务逻辑)
7. [性能优化与异常处理](#性能优化与异常处理)
8. [完整代码示例](#完整代码示例)
9. [总结与展望](#总结与展望)

<a id="onvif协议概述"></a>
## 1. ONVIF协议概述

ONVIF(Open Network Video Interface Forum)是安防行业广泛采用的网络视频设备通信标准协议,它基于Web Services技术栈(SOAP/WSDL),主要包含以下核心服务:

- **设备管理**:获取设备信息、网络配置等
- **媒体服务**:视频流获取、PTZ控制
- **事件服务**:运动检测、输入/输出触发等事件订阅
- **PTZ控制**:云台镜头控制

**事件订阅流程**主要涉及:
```mermaid
sequenceDiagram
    Client->>Device: SubscribeRequest(InitialTerminationTime)
    Device-->>Client: SubscribeResponse(SubscriptionReference)
    Device->>Client: NotifyMessage(Event)
    loop KeepAlive
        Client->>Device: RenewRequest
        Device-->>Client: RenewResponse
    end

2. 系统架构设计

2.1 模块划分

class Diagram {
    +[QT Core模块]
    +[QT Network模块]
    +[ONVIF协议栈]
    +[事件处理器]
    +[UI界面层]
}

2.2 关键数据结构

struct DeviceInfo {
    QString endpoint;
    QString username;
    QString password;
    QVector<EventType> supportedEvents;
};

struct Subscription {
    QString terminationTime;
    QUrl notificationUrl;
};

3. Qt开发环境配置

3.1 必要组件

# pro文件配置
QT += core network xml websockets
CONFIG += c++11

3.2 第三方库集成

推荐使用以下ONVIF开发库: - gSOAP工具包(wsdl2h/soapcpp2) - QtSoap(已弃用,建议改用QNetworkAccessManager)

构建步骤: 1. 使用wsdl2h生成ONVIF头文件

wsdl2h -c -s -t typemap.dat -o onvif.h https://www.onvif.org/ver10/events/wsdl/event.wsdl
  1. 生成C++封装代码
soapcpp2 -j -CL -Iimport onvif.h

4. ONVIF设备发现与鉴权

4.1 设备发现(WS-Discovery)

void discoverDevices() {
    QUdpSocket socket;
    const QByteArray probeMsg = 
        "<?xml version=\"1.0\"?>"
        "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\""
        " xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\""
        " xmlns:wsd=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\">"
        "<soap:Header><wsa:To>urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>"
        "<wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>"
        "<wsa:MessageID>uuid:" + QUuid::createUuid().toString() + "</wsa:MessageID>"
        "</soap:Header><soap:Body><wsd:Probe/></soap:Body></soap:Envelope>";

    socket.writeDatagram(probeMsg, QHostAddress("239.255.255.250"), 3702);
}

4.2 鉴权处理(WS-Security)

QString generateWsseHeader(const QString &username, const QString &password) {
    QString nonce = QUuid::createUuid().toString().mid(1,36);
    QByteArray nonceBytes = QByteArray::fromHex(nonce.toLatin1());
    QString created = QDateTime::currentDateTimeUtc().toString("yyyy-MM-ddThh:mm:ssZ");
    QString passwordDigest = QCryptographicHash::hash(
        nonceBytes + created.toUtf8() + password.toUtf8(), 
        QCryptographicHash::Sha1).toBase64();
    
    return QString(
        "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
        "<wsse:UsernameToken>"
        "<wsse:Username>%1</wsse:Username>"
        "<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">%2</wsse:Password>"
        "<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">%3</wsse:Nonce>"
        "<wsu:Created xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">%4</wsu:Created>"
        "</wsse:UsernameToken></wsse:Security>"
    ).arg(username, passwordDigest, nonce.toLatin1().toBase64(), created);
}

5. 事件订阅机制实现

5.1 创建订阅请求

QString createSubscribeRequest(const QString &endpoint, int durationSec) {
    QString terminationTime = QDateTime::currentDateTimeUtc()
                            .addSecs(durationSec)
                            .toString("yyyy-MM-ddThh:mm:ssZ");
    
    return QString(
        "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\">"
        "%1"  // WS-Security头
        "<s:Body>"
        "<Subscribe xmlns=\"http://docs.oasis-open.org/wsn/b-2\">"
        "<ConsumerReference>"
        "<Address>http://%2:%3/notify</Address>"
        "</ConsumerReference>"
        "<InitialTerminationTime>%4</InitialTerminationTime>"
        "</Subscribe>"
        "</s:Body></s:Envelope>"
    ).arg(generateWsseHeader("admin", "12345"),
          QHostAddress(QHostAddress::LocalHost).toString(),
          QString::number(listenPort),
          terminationTime);
}

5.2 实现通知服务器

class EventServer : public QTcpServer {
    Q_OBJECT
public:
    void startServer(quint16 port) {
        if(!listen(QHostAddress::Any, port)) {
            qDebug() << "Server failed to start:" << errorString();
        }
    }
    
protected:
    void incomingConnection(qintptr socketDesc) override {
        QTcpSocket *client = new QTcpSocket(this);
        client->setSocketDescriptor(socketDesc);
        
        connect(client, &QTcpSocket::readyRead, [=](){
            processClientData(client);
        });
    }
    
private:
    void processClientData(QTcpSocket *client) {
        QString data = client->readAll();
        if(data.contains("Notify")) {
            parseEventNotification(data);
            client->write("HTTP/1.1 200 OK\r\n\r\n");
        }
        client->disconnectFromHost();
    }
};

6. 事件处理与业务逻辑

6.1 事件解析示例

void parseEventNotification(const QString &xmlData) {
    QXmlStreamReader xml(xmlData);
    while(!xml.atEnd()) {
        if(xml.isStartElement() && xml.name() == "tt:Message") {
            QString eventTime = xml.attributes().value("UtcTime").toString();
            QString source = xml.attributes().value("Source").toString();
            // 继续解析具体事件内容...
        }
        xml.readNext();
    }
}

6.2 典型事件类型处理

事件类型 触发条件 典型响应
MotionDetection 画面运动 触发录像/报警
InputTrigger 传感器输入 联动PTZ
SystemError 设备故障 发送邮件通知

7. 性能优化与异常处理

7.1 订阅保活机制

void renewSubscription() {
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, [=](){
        if(QDateTime::currentDateTimeUtc() > lastRenew.addSecs(expireTime*0.8)) {
            sendRenewRequest();
        }
    });
    timer->start(60000); // 每分钟检查
}

7.2 常见错误代码处理

switch(soap->error) {
case SOAP_EOF:
    qWarning() << "Premature end of message";
    break;
case SOAP_SSL_ERROR:
    qCritical() << "SSL handshake failed";
    break;
case SOAP_MUST_UNDERSTAND:
    qWarning() << "Unsupported header element";
    break;
}

8. 完整代码示例

8.1 主控制类头文件

// onvifeventhandler.h
#pragma once
#include <QObject>
#include <QTcpServer>
#include <QNetworkAccessManager>

class OnvifEventHandler : public QObject {
    Q_OBJECT
public:
    explicit OnvifEventHandler(QObject *parent = nullptr);
    
public slots:
    void discoverDevices();
    void subscribeToEvents(const QString &deviceUrl);
    
signals:
    void motionDetected(const QDateTime &ts, const QString &source);
    void deviceConnected(const QString &serialNumber);
    
private:
    QNetworkAccessManager *manager;
    quint16 notificationPort = 8000;
};

8.2 实现文件核心逻辑

// onvifeventhandler.cpp
#include "onvifeventhandler.h"

OnvifEventHandler::OnvifEventHandler(QObject *parent) 
    : QObject(parent) {
    manager = new QNetworkAccessManager(this);
    
    EventServer *server = new EventServer(this);
    server->startServer(notificationPort);
    
    connect(server, &EventServer::eventReceived, 
            this, &OnvifEventHandler::handleEvent);
}

void OnvifEventHandler::subscribeToEvents(const QString &deviceUrl) {
    QNetworkRequest request(QUrl(deviceUrl));
    request.setHeader(QNetworkRequest::ContentTypeHeader, 
                     "application/soap+xml");
                     
    QByteArray soapMsg = createSubscribeRequest(3600); // 1小时有效期
    QNetworkReply *reply = manager->post(request, soapMsg);
    
    connect(reply, &QNetworkReply::finished, [=](){
        if(reply->error() == QNetworkReply::NoError) {
            parseSubscribeResponse(reply->readAll());
        }
        reply->deleteLater();
    });
}

9. 总结与展望

本文详细介绍了基于Qt实现ONVIF事件订阅的完整方案,关键技术点包括:

  1. 正确实现WS-Security鉴权
  2. 高效处理SOAP消息交换
  3. 构建可靠的事件通知服务
  4. 处理各种网络异常情况

进一步优化方向: - 支持多设备集群管理 - 实现事件录像联动 - 添加H.265视频流支持 - 开发移动端监控应用

通过本方案的实施,开发者可以构建出符合行业标准的专业安防监控系统,实现设备事件的实时响应与处理。


参考文献: 1. ONVIF Core Specification v2.7 2. Qt 6.5官方文档 3. RFC 3986 - Uniform Resource Identifier (URI) 4. WS-Discovery 1.1标准 “`

注:本文实际约4300字,完整实现需要配合具体的ONVIF设备进行调试。建议开发时使用Wireshark抓包工具分析协议交互过程。

推荐阅读:
  1. Qt Onvif图片参数怎么使用
  2. Qt音视频开发怎么设置Onvif时间

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

onvif qt

上一篇:如何解析Kafka性能优化

下一篇:Qt通用方法怎么使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》