一、前言:
本篇的OnvifManager工程是在vs2010下进行开发编译,它实现了对onvif库的封装调用,目前工程接口实现了对onvif的搜索、码流地址获取、设备重启接口,其他接口后续可以通过更改工程代码进行添加。qt工程myonvif是对OnvifManager生成的动态库进行调用,用QTableview显示搜索后的设备信息,支持码流地址获取及设备重启功能,支持单击网页访问。
二、OnvifManager 动态库接口说明
/*****************************************************
- 设备搜索 接口1
- @pUser 用户名 输入
- @pPwd 密码 输入
- @pLocalIP 本地电脑IP 输入
- @vecDevInfo 搜索到的设备信息 输出
- @搜索超时时间 输入
- @返回值 0:成功 其他:失败
- ***************************************************/
int FF_Onvif_Discovery1(char *pUser, char *pPwd, char *pLocalIP,
std::vector<ONVIF_DEVICE_INFO_T>& vecDevInfo, int nTimeout);
/*****************************************************
- 设备搜索 接口2
- @pUser 用户名 输入
- @pPwd 密码 输入
- @pLocalIP 本地电脑IP 输入
- @搜索超时时间
- @返回值:ONVFI_DISCOVERY_DEINFO_T 结构体设备信息
- ***************************************************/
ONVFI_DISCOVERY_DEINFO_T FF_Onvif_Discovery2(char *pUser, char *pPwd, char *pLocalIP, int nTimeout);
/*****************************************************
- 获取码流地址
- @pMediaXAddress 媒体服务地址
- @pUser 用户名 输入
- @pPwd 密码 输入
- @pOutUrl 码流地址 输出
- @nOutUrlLen 码流地址长度 输入
- @返回值:0:成功 其他:失败
- ***************************************************/
int FF_Onvif_GetStreamUrl(char *pMediaXAddress, char *pUser, char *pPwd,
char *pOutUrl, int nOutUrlLen);
/*****************************************************
- 重启设备
- @pDeviceXAddress 设备服务地址
- @pUser 用户名 输入
- @pPwd 密码 输入
- ***************************************************/
int FF_Onvif_Reboot(char *pDeviceXAddress, char *pUser, char *pPwd);
库头文件:OnvifManager.h 代码
/**************************************************************************
Description:Onvif Lib
Author:ybLin
**************************************************************************/
#ifndef ONVIFMANAGER_H
#define ONVIFMANAGER_H
#include <windows.h>
#include <iostream>
#include <vector>
#include <list>
#include <string>
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_DEV_LEN 64
typedef struct onvif_device_info_t
{
std::string sDevIP;
std::string sMac;
std::string sNetMask;
std::string sGateWay;
std::string sModel;
std::string sVersion;
std::string sManufacturer;
std::string sDeviceXAddrs;
std::string sMediaAddress;
std::string Item;
int nPort;
}ONVIF_DEVICE_INFO_T;
typedef struct onvif_devinfo_t
{
int nPort;
char sDevIP[64];
char sMac[64];
char sNetMask[64];
char sGateWay[64];
char sModel[64];
char sVersion[64];
char sManufacturer[64];
char sDeviceXAddrs[128];
char sMediaAddress[128];
char Item[512];
}ONVIF_DEVINFO_T;
typedef struct onvif_disocvey_devinfo_t
{
ONVIF_DEVINFO_T dev[MAX_DEV_LEN];
int nDevNum;
}ONVFI_DISCOVERY_DEINFO_T;
//搜索接口1
extern __declspec(dllexport) int WINAPI FF_Onvif_Discovery1(char *pUser, char *pPwd, char *pLocalIP,
std::vector<ONVIF_DEVICE_INFO_T>& vecDevInfo, int nTimeout);
//搜索接口2
extern __declspec(dllexport) ONVFI_DISCOVERY_DEINFO_T WINAPI FF_Onvif_Discovery2(char *pUser, char *pPwd, char *pLocalIP, int nTimeout);
//获取码流地址
extern __declspec(dllexport) int WINAPI FF_Onvif_GetStreamUrl(char *pMediaXAddress, char *pUser, char *pPwd,
char *pOutUrl, int nOutUrlLen);
//重启
extern __declspec(dllexport) int WINAPI FF_Onvif_Reboot(char *pDeviceXAddress, char *pUser, char *pPwd);
#ifdef __cplusplus
}
#endif
#endif
三、qt-demo工程myonvif
3.1 操作介绍
1)点击搜索按钮,等待数据加载
2)数据加载完成(设备信息加载不全的,是因为密码不对)
3)单击表格数据行,获取到服务地址
4)点击获取码流地址按钮,获取到设备的rtsp码流地址:
5)点击设备重启,可以对指定设备进行重启操作:
6) web访问
3.2 demo核心代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QStandardItemModel>
#include <QRunnable>
namespace Ui {
class MainWindow;
}
enum COLUMN_NUM
{
DCOLUMN_IP = 0,
DCOLUMN_MAC_ADDRESS,
DCOLUMN_PORT,
DCOLUMN_NETMASK,
DCOLUMN_GATEWAY,
DCOLUMN_MANUFACTURER,
DCOLUMN_MODEL,
DCOLUMN_SOFT_VERSION,
DCOLUMN_WEB
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void initTableView();
signals:
void sig_CloseWaitBox();
public slots:
void on_fiterSingleClick(QModelIndex index); // 过滤单双击事件
void on_tableViewClick(); //单击响应
void slot_finshTask(bool bSuc);
private slots:
void on_pushButton_Search_clicked();
void on_pushButton_GetStreamUrl_clicked();
void on_pushButton_Restart_clicked();
private:
QStandardItemModel *m_tableModel;//表数据模型
// 单双击区分
bool m_bDBclick;
QTimer *m_click; //单击的时候触发定时器
QModelIndex m_bakIndex;
private:
Ui::MainWindow *ui;
};
class COnvifDiscoveryTask :public QObject, public QRunnable
{
Q_OBJECT
public:
COnvifDiscoveryTask(QObject *parent, QString sUser, QString sPwd, QString sIP, QStandardItemModel *pTableModel): QObject(parent),
m_sUser(sUser), m_sPwd(sPwd), m_sIP(sIP), m_tableModel(pTableModel) {}
virtual ~COnvifDiscoveryTask() {}
void run();
signals:
void sig_finshTask(bool bSuc);
private:
QString m_sUser;
QString m_sPwd;
QString m_sIP;
QStandardItemModel *m_tableModel;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLinkedList>
#include <QStringList>
#include "OnvifManager.h"
#include <QMessageBox>
#include <QDebug>
#include <string.h>
#include <QTimer>
#include <QThreadPool>
#include <QDesktopServices>
#include <QUrl>
#include "CtWaitBox.h"
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
initTableView();
connect(this, &MainWindow::sig_CloseWaitBox,
CtWaitBox::getInstance(), &CtWaitBox::onWaitBoxClose);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initTableView()
{
m_tableModel = new QStandardItemModel(this);
ui->tableView->setModel(m_tableModel);
QStringList lables;
lables << QObject::tr("IP") << QObject::tr("Mac")
<< QObject::tr("Port") << QObject::tr("NetMask")
<< QObject::tr("Gateway") << QObject::tr("Manufacturer")
<< QObject::tr("Model") << QObject::tr("Version") << QObject::tr("Web");
m_tableModel->setHorizontalHeaderLabels(lables);
//ui->tableView->horizontalHeader()->setSectionResizeMode(DCOLUMN_WEB, QHeaderView::Fixed);
int width = 840;
ui->tableView->setColumnWidth(DCOLUMN_IP, qRound(0.13*width));
ui->tableView->setColumnWidth(DCOLUMN_MAC_ADDRESS, qRound(0.13*width));
ui->tableView->setColumnWidth(DCOLUMN_PORT, qRound(0.05*width));
ui->tableView->setColumnWidth(DCOLUMN_NETMASK, qRound(0.13*width));
ui->tableView->setColumnWidth(DCOLUMN_GATEWAY, qRound(0.13*width));
ui->tableView->setColumnWidth(DCOLUMN_MANUFACTURER, qRound(0.12*width));
ui->tableView->setColumnWidth(DCOLUMN_MODEL, qRound(0.12*width));
ui->tableView->setColumnWidth(DCOLUMN_SOFT_VERSION, qRound(0.12*width));
ui->tableView->setColumnWidth(DCOLUMN_WEB, qRound(0.05*width));
m_click = new QTimer(this);
m_click->setSingleShot(true);
m_bDBclick = false;
connect(ui->tableView, &QTableView::clicked,
this, &MainWindow::on_fiterSingleClick); //单击检测
connect(m_click, &QTimer::timeout,
this, &MainWindow::on_tableViewClick); // 处理单击
}
void MainWindow::on_fiterSingleClick(QModelIndex index)
{
if(m_bDBclick)
{
m_bDBclick = false;
}
else
{
m_click->start(200); // double click interval 200ms
m_bakIndex = index;
}
}
void MainWindow::on_tableViewClick()
{
int nRow = m_bakIndex.row();//选中数据的行
int nCol = m_bakIndex.column();//选中数据的列
QString sIP = m_tableModel->item(nRow, DCOLUMN_IP)->text();
QString sPort = m_tableModel->item(nRow, DCOLUMN_PORT)->text();
QString sMediaAddr = QString("http://%1:%2/onvif/Media").arg(sIP).arg(sPort);
QString sDevAddr = QString("http://%1:%2/onvif/device_service").arg(sIP).arg(sPort);
ui->lineEdit_MediaAddress->setText(sMediaAddr);
ui->lineEdit_devAddress->setText(sDevAddr);
if(nCol == DCOLUMN_WEB)
{
QString sUrl = QString("http://%1:%2").arg(sIP).arg(sPort);
QDesktopServices::openUrl(QUrl(sUrl));
}
}
void MainWindow::slot_finshTask(bool bSuc)
{
Q_UNUSED(bSuc)
emit sig_CloseWaitBox();
}
void MainWindow::on_pushButton_Search_clicked()
{
QString sUserName = ui->lineEdit_User->text();
if(sUserName.isEmpty())
{
QMessageBox::critical(this, "myOnvif", "错误:用户名不能为空.");
return;
}
QString sPwd = ui->lineEdit_Pwd->text();
if(sPwd.isEmpty())
{
QMessageBox::critical(this, "myOnvif", "错误:密码不能为空.");
return;
}
QString sIP = ui->lineEdit_IP->text();
if(sIP.isEmpty())
{
QMessageBox::critical(this, "myOnvif", "错误:本机IP不能为空.");
return;
}
COnvifDiscoveryTask* pTask = new COnvifDiscoveryTask(NULL, sUserName, sPwd, sIP, m_tableModel);
connect(pTask, SIGNAL(sig_finshTask(bool)),
this, SLOT(slot_finshTask(bool)));
QThreadPool::globalInstance()->start(pTask);
CtWaitBox::loading(true, geometry().x()+geometry().width()/2-100, geometry().y()+geometry().height()/2-100, 60, true);
}
void MainWindow::on_pushButton_GetStreamUrl_clicked()
{
char sUrl[128] = {0};
QString sMediaAddr = ui->lineEdit_MediaAddress->text();
if(sMediaAddr.isEmpty())
{
QMessageBox::critical(this, "myOnvif", tr("媒体服务地址不能为空"));
return;
}
QString sUser = ui->lineEdit_User->text();
if(sUser.isEmpty())
{
QMessageBox::critical(this, "myOnvif", tr("用户名不能为空"));
return;
}
QString sPwd = ui->lineEdit_Pwd->text();
if(sPwd.isEmpty())
{
QMessageBox::critical(this, "myOnvif", "密码不能为空");
return;
}
if(FF_Onvif_GetStreamUrl(sMediaAddr.toLatin1().data(), sUser.toLatin1().data(), sPwd.toLatin1().data(), sUrl, sizeof(sUrl)) != 0)
{
QMessageBox::critical(this, "myOnvif", "错误:获取码流地址失败.");
}
else
{
QString sRtspUrl = QString(sUrl);
ui->lineEdit_Url->setText(sRtspUrl);
}
}
void MainWindow::on_pushButton_Restart_clicked()
{
QString sDevAddr = ui->lineEdit_devAddress->text();
if(sDevAddr.isEmpty())
{
QMessageBox::critical(this, "myOnvif", "设备服务地址不能为空");
return;
}
QString sUser = ui->lineEdit_User->text();
if(sUser.isEmpty())
{
QMessageBox::critical(this, "myOnvif", "用户名不能为空");
return;
}
QString sPwd = ui->lineEdit_Pwd->text();
if(sPwd.isEmpty())
{
QMessageBox::critical(this, "myOnvif", "密码不能为空");
return;
}
if(FF_Onvif_Reboot(sDevAddr.toLatin1().data(), sUser.toLatin1().data(), sPwd.toLatin1().data()) == 0)
QMessageBox::information(this, "myOnvif", "重启成功");
else
QMessageBox::critical(this, "myOnvif", "重启失败.");
}
void COnvifDiscoveryTask::run()
{
if(m_tableModel->rowCount() > 0)
{
m_tableModel->removeRows(0, m_tableModel->rowCount());
}
ONVFI_DISCOVERY_DEINFO_T devInfos = FF_Onvif_Discovery2(m_sUser.toLatin1().data(), m_sPwd.toLatin1().data(), m_sIP.toLatin1().data(), 5);
qDebug() << "devInfos.nDevNum:" << devInfos.nDevNum;
//数据
for(int i = 0; i < devInfos.nDevNum; i++)
{
qDebug() << "Dev" << i << " IP:" << devInfos.dev[i].sDevIP;
qDebug() << "Dev" << i << " Port:" << devInfos.dev[i].nPort;
qDebug() << "Dev" << i << " Mac:" << devInfos.dev[i].sMac;
qDebug() << "Dev" << i << " NetMask:" << devInfos.dev[i].sNetMask;
qDebug() << "Dev" << i << " GateWay:" << devInfos.dev[i].sGateWay;
qDebug() << "Dev" << i << " Manufacturer:" << devInfos.dev[i].sManufacturer;
qDebug() << "Dev" << i << " Model:" << devInfos.dev[i].sModel;
qDebug() << "Dev" << i << " Version:" << devInfos.dev[i].sVersion;
qDebug() << "\r\n"<< endl;
m_tableModel->insertRow(i, QModelIndex());
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_IP), devInfos.dev[i].sDevIP);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_MAC_ADDRESS), devInfos.dev[i].sMac);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_PORT), devInfos.dev[i].nPort);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_NETMASK), devInfos.dev[i].sNetMask);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_GATEWAY), devInfos.dev[i].sGateWay);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_MANUFACTURER), devInfos.dev[i].sManufacturer);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_MODEL), devInfos.dev[i].sModel);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_SOFT_VERSION), devInfos.dev[i].sVersion);
m_tableModel->setData(m_tableModel->index(i, DCOLUMN_WEB), QImage(":/image/web.png"), Qt::DecorationRole);
// 设置全部列居中显示
for(int j = DCOLUMN_IP; j < DCOLUMN_WEB; j++)
{
m_tableModel->item(i, j)->setTextAlignment(Qt::AlignCenter);
}
}
emit sig_finshTask(true);
}
四、下载
体验地址下载:https://download.csdn.net/download/linyibin_123/88036919
onvif库源码及qt-demo工程源码下载:https://download.csdn.net/download/linyibin_123/88036934