zoukankan      html  css  js  c++  java
  • 如何检测 ONVIF 图像设备?

    WSDiscoveryClient 类实现了检测 支持 ONVIF 协议的摄像头设备。该类主要实现了 WSDiscovery 协议(精简版)检测设备部分。

    wsdiscoveryclient.h

    #ifndef WSDISCOVERYCLIENT_H
    #define WSDISCOVERYCLIENT_H
    
    #include <QObject>
    #include <QtCore>
    #include <QtNetwork>
    
    struct WSDiscoveryClientData
    {
        QString EPAddress;
        QString type;
        QString deviceIP;
        QString deviceServiceAddress;
        QStringList scopes;
        QString metadataVersion;
        QDateTime lastUpdate;
    };
    
    class WSDiscoveryClient : public QObject
    {
        Q_OBJECT
    public:
        explicit WSDiscoveryClient(QObject *parent = nullptr);
        ~WSDiscoveryClient();
        void probe();//检测
    signals:
        void discoveryNVT(QString ip,QString serviceAddress);//检测到设备会发送该信号,连接即可。
    private:
        void initSocket();
        void readPendingDatagrams();
        void processTheDatagram(const QNetworkDatagram &datagram);
    private:
        QUdpSocket *m_socket;
        QHash<QString,WSDiscoveryClientData> m_data;
    };
    
    QDebug operator<<(QDebug dbg,const WSDiscoveryClientData &obj);
    #endif // WSDISCOVERYCLIENT_H
    

    wsdiscoveryclient.cpp

    #include "wsdiscoveryclient.h"
    
    #define WS_DISCOVERY_ADDRESS "239.255.255.250"
    #define WS_DISCOVERY_PORT 3702
    
    //Q_LOGGING_CATEGORY(WSDiscoveryClient, "WSDiscoveryClient.log",QtInfoMsg)
    
    static QString ProbeXML(int device_type/*Device,NVT NetworkVideoTransmitter*/)
    {
        QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
        QString device = device_type ? "tds:Device" : "tdn:NetworkVideoTransmitter";
        QString cmd(R"(<?xml version="1.0" encoding="utf-8"?><Envelope xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns="http://www.w3.org/2003/05/soap-envelope"><Header><wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">uuid:%1</wsa:MessageID><wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To><wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action></Header><Body><Probe xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery"><Types>%2</Types><Scopes /></Probe></Body></Envelope>)");
        return cmd.arg(uuid).arg(device).remove("
    ");
    }
    
    WSDiscoveryClient::WSDiscoveryClient(QObject *parent) : QObject(parent)
      ,m_socket(new QUdpSocket(this))
    {
        connect(m_socket,&QUdpSocket::readyRead,this,&WSDiscoveryClient::readPendingDatagrams);
        connect(m_socket,QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),[=](QAbstractSocket::SocketError socketError){
            qDebug() << socketError;
        });
        connect(m_socket,QOverload<QAbstractSocket::SocketState>::of(&QAbstractSocket::stateChanged),[=](QAbstractSocket::SocketState socketState){
            qDebug() << socketState;
        });
    
        initSocket();
    }
    
    WSDiscoveryClient::~WSDiscoveryClient()
    {
    }
    
    void WSDiscoveryClient::probe()
    {
        for(auto &v:{/*1,*/0}){
            QByteArray data = ProbeXML(v).toUtf8();
            int ret = m_socket->writeDatagram(data.data(),data.length(),QHostAddress(WS_DISCOVERY_ADDRESS),WS_DISCOVERY_PORT);
            if(!ret){
                qWarning() << "Probe Send Failed";
            }
        }
    }
    
    void WSDiscoveryClient::initSocket()
    {
        if(!m_socket->bind(QHostAddress(WS_DISCOVERY_ADDRESS),WS_DISCOVERY_PORT,QAbstractSocket::ShareAddress)){
            qCritical() << QString("Binding [address:%1] [port:%2] failure.").arg(WS_DISCOVERY_ADDRESS).arg(WS_DISCOVERY_PORT);
        }
    }
    
    void WSDiscoveryClient::readPendingDatagrams()
    {
        //qDebug() << "readPendingDatagrams";
        while (m_socket->hasPendingDatagrams()) {
            QNetworkDatagram datagram = m_socket->receiveDatagram();
            processTheDatagram(datagram);
        }
    }
    
    /*!
    <?xml version="1.0" encoding="utf-8" ?>
    <SOAP-ENV:Envelope
        xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
        xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
        xmlns:env="http://www.w3.org/2003/05/soap-envelope"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
        xmlns:dndl="http://www.onvif.org/ver10/network/wsdl/DiscoveryLookupBinding"
        xmlns:dnrd="http://www.onvif.org/ver10/network/wsdl/RemoteDiscoveryBinding"
        xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery"
        xmlns:dn="http://www.onvif.org/ver10/network/wsdl">
        <SOAP-ENV:Header>
            <wsa:MessageID>urn:uuid:c25a2a64-1dd1-11b2-8339-00040502673d</wsa:MessageID>
            <wsa:RelatesTo>uuid:28e58635-58a1-4d5e-b1f6-c2557fa253d2</wsa:RelatesTo>
            <wsa:To SOAP-ENV:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
            <wsa:Action>http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches</wsa:Action>
        </SOAP-ENV:Header>
        <SOAP-ENV:Body>
            <d:ProbeMatches><d:ProbeMatch>
            <wsa:EndpointReference>
                <wsa:Address>urn:uuid:c25a2a64-1dd1-11b2-8339-00040502673d</wsa:Address>
            </wsa:EndpointReference>
            <d:Types>dn:NetworkVideoTransmitter</d:Types>
            <d:Scopes>
                onvif://www.onvif.org/type/Network_Video_Transmitter
                onvif://www.onvif.org/type/video_encoder
                onvif://www.onvif.org/location/MyCamera
                onvif://www.onvif.org/hardware/RDC
                onvif://www.onvif.org/name/IPCAMERA
                onvif://www.onvif.org/type/audio_encoder
                onvif://www.onvif.org/Profile/Streaming
            </d:Scopes>
            <d:XAddrs>http://192.168.1.180/onvif/device_service</d:XAddrs>
            <d:MetadataVersion>1</d:MetadataVersion>
            </d:ProbeMatch></d:ProbeMatches>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    */
    void WSDiscoveryClient::processTheDatagram(const QNetworkDatagram &datagram)
    {
        const QByteArray &request = datagram.data();
    
        auto GetElementValue = [&](const QByteArray &start,const QByteArray &end,const QByteArray &data)->QByteArray{
            int s_pos = data.lastIndexOf(start);
            int e_pos = data.lastIndexOf(end);
            if(s_pos != -1 && e_pos != -1){
                return data.mid(s_pos + start.length(),e_pos - s_pos - start.length());
            }
            return QByteArray();
        };
    
        const QByteArray body = GetElementValue("<SOAP-ENV:Body>","</SOAP-ENV:Body>",request);
        WSDiscoveryClientData discoveryClientData;
        discoveryClientData.EPAddress = GetElementValue("<wsa:Address>","</wsa:Address>",body);
        discoveryClientData.type = GetElementValue("<d:Types>","</d:Types>",body);
        QString scopes = GetElementValue("<d:Scopes>","</d:Scopes>",body);
        discoveryClientData.scopes = scopes.split(" ");
        discoveryClientData.deviceServiceAddress = GetElementValue("<d:XAddrs>","</d:XAddrs>",body);
        if(!discoveryClientData.deviceServiceAddress.isEmpty()){
            QString serviceAddress = discoveryClientData.deviceServiceAddress;
            serviceAddress.remove("http://");
            serviceAddress.remove("https://");
            int pos = serviceAddress.indexOf(R"(/)");
            if(pos != -1){
                discoveryClientData.deviceIP = serviceAddress.mid(0,pos);
                discoveryClientData.lastUpdate = QDateTime::currentDateTimeUtc();
            }
        }
        discoveryClientData.metadataVersion = GetElementValue("<d:MetadataVersion>","</d:MetadataVersion>",body);
    
        qDebug() << discoveryClientData;
    }
    
    QDebug operator<<(QDebug dbg, const WSDiscoveryClientData &obj)
    {
        QDebugStateSaver saver(dbg);
        dbg << obj.EPAddress
            << obj.type
            << obj.deviceIP
            << obj.deviceServiceAddress
            << obj.scopes
            << obj.metadataVersion
            << obj.lastUpdate;
        return dbg;
    }
    
  • 相关阅读:
    基于p2p聊天室的原理介绍.个人学习笔记
    一个可移植数据库操作组件的简单介绍
    常见任务
    sql常用语句
    认真写写SQLAlchemy
    Jenkins 安装与使用手册
    Ajax
    支持主流注册中心,SolarMesh发布新版本 SolarMesh
    API标准化对Dapr的重要性
    企业数字化转型,你知道有哪些关键要素吗?
  • 原文地址:https://www.cnblogs.com/cheungxiongwei/p/14266001.html
Copyright © 2011-2022 走看看