如何检测 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("\n");
}
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;
}
转载请注明出处并保持作品的完整性,谢谢