ledset增加视频传输, ledok修改指定ip
This commit is contained in:
parent
7626902534
commit
caf3ef0add
|
@ -22,11 +22,11 @@ DevicePanel::DevicePanel(QSettings &settings, QWidget *parent) : QWidget(parent)
|
||||||
pal.setBrush(QPalette::Window, QColor(0xeeeeee));
|
pal.setBrush(QPalette::Window, QColor(0xeeeeee));
|
||||||
setPalette(pal);
|
setPalette(pal);
|
||||||
|
|
||||||
auto vBox = new QVBoxLayout(this);
|
auto vBox = new VBox(this);
|
||||||
vBox->setContentsMargins(0, 0, 0, 0);
|
vBox->setContentsMargins(0, 0, 0, 0);
|
||||||
vBox->setSpacing(0);
|
vBox->setSpacing(0);
|
||||||
|
|
||||||
auto hBox = new QHBoxLayout();
|
auto hBox = new HBox(vBox);
|
||||||
hBox->setContentsMargins(6, 2, 6, 2);
|
hBox->setContentsMargins(6, 2, 6, 2);
|
||||||
hBox->setSpacing(2);
|
hBox->setSpacing(2);
|
||||||
|
|
||||||
|
@ -68,9 +68,6 @@ DevicePanel::DevicePanel(QSettings &settings, QWidget *parent) : QWidget(parent)
|
||||||
bnSpecifyIP->setGeometry(0, 0, areaFlash->width(), areaFlash->height());
|
bnSpecifyIP->setGeometry(0, 0, areaFlash->width(), areaFlash->height());
|
||||||
bnSpecifyIP->setItemDelegate(new QStyledItemDelegate);
|
bnSpecifyIP->setItemDelegate(new QStyledItemDelegate);
|
||||||
connect(bnSpecifyIP, &QComboBox::textActivated, this, [this] {
|
connect(bnSpecifyIP, &QComboBox::textActivated, this, [this] {
|
||||||
if(specifyIPDlg==0) {
|
|
||||||
|
|
||||||
}
|
|
||||||
mUdpTimer.stop();
|
mUdpTimer.stop();
|
||||||
specifyIPDlg->exec();
|
specifyIPDlg->exec();
|
||||||
mUdpTimer.start(30000);
|
mUdpTimer.start(30000);
|
||||||
|
@ -111,8 +108,6 @@ QPushButton:hover {background-color: #08b;}
|
||||||
|
|
||||||
hBox->addWidget(areaFlash);
|
hBox->addWidget(areaFlash);
|
||||||
|
|
||||||
vBox->addLayout(hBox);
|
|
||||||
|
|
||||||
mHBox = new QHBoxLayout();
|
mHBox = new QHBoxLayout();
|
||||||
|
|
||||||
mDeviceTable = new LoQTreeWidget(this);
|
mDeviceTable = new LoQTreeWidget(this);
|
||||||
|
@ -190,28 +185,28 @@ QPushButton:hover {background-color: #08b;}
|
||||||
|
|
||||||
connect(mDeviceTable, SIGNAL(sigCheckStateChanged(int)), this, SLOT(onCheckStateChanged(int)));
|
connect(mDeviceTable, SIGNAL(sigCheckStateChanged(int)), this, SLOT(onCheckStateChanged(int)));
|
||||||
mDeviceTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
mDeviceTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
mDeviceTable->hideColumn(0);
|
||||||
|
mDeviceTable->fdIsSelAll->hide();
|
||||||
|
|
||||||
|
|
||||||
//开始轮训查找局域网内的控制卡
|
|
||||||
sendGetInfo();
|
|
||||||
mUdpTimer.start(30000);
|
|
||||||
{
|
|
||||||
specifyIPDlg = new QDialog(this);
|
specifyIPDlg = new QDialog(this);
|
||||||
specifyIPDlg->setWindowTitle(tr("Specify IP"));
|
specifyIPDlg->setWindowTitle(tr("Specify IP"));
|
||||||
|
|
||||||
auto vBox = new VBox(specifyIPDlg);
|
vBox = new VBox(specifyIPDlg);
|
||||||
vBox->addStretch();
|
vBox->addStretch();
|
||||||
|
|
||||||
auto label = new QLabel(tr("Specify IP list"));
|
label = new QLabel(tr("Specify IP list"));
|
||||||
label->setAlignment(Qt::AlignCenter);
|
label->setAlignment(Qt::AlignCenter);
|
||||||
vBox->addWidget(label);
|
vBox->addWidget(label);
|
||||||
|
|
||||||
|
fdIP = new QTextEdit;
|
||||||
auto ipstr = settings.value("SpecifyIP").toString();
|
auto ipstr = settings.value("SpecifyIP").toString();
|
||||||
fdIP = new QTextEdit(ipstr);
|
if(! ipstr.isEmpty()) fdIP->setText(ipstr);
|
||||||
fdIP->setPlaceholderText("192.168.1.1\n192.168.1.2\n ...");
|
fdIP->setPlaceholderText("192.168.1.1\n192.168.1.2\n ...");
|
||||||
fdIP->setMinimumWidth(160);
|
fdIP->setMinimumWidth(160);
|
||||||
vBox->addWidget(fdIP);
|
vBox->addWidget(fdIP);
|
||||||
|
|
||||||
auto hBox = new HBox(vBox);
|
hBox = new HBox(vBox);
|
||||||
hBox->addStretch();
|
hBox->addStretch();
|
||||||
|
|
||||||
auto bnSearch = new QPushButton(tr("Search"));
|
auto bnSearch = new QPushButton(tr("Search"));
|
||||||
|
@ -239,17 +234,10 @@ QPushButton:hover {background-color: #08b;}
|
||||||
hBox->addWidget(btnCancel);
|
hBox->addWidget(btnCancel);
|
||||||
hBox->addStretch();
|
hBox->addStretch();
|
||||||
|
|
||||||
if(! ipstr.isEmpty()) {
|
|
||||||
auto ips = ipstr.split("\n", Qt::SkipEmptyParts);
|
|
||||||
QByteArray data = QJsonDocument({{"action", "getInfo"}}).toJson(QJsonDocument::Compact);
|
|
||||||
foreach(auto ip, ips) {
|
|
||||||
if(gDevicePanel->mUdpSocket.writeDatagram(data, QHostAddress(ip), 22222) != data.length()) qDebug() << "Specify IP write Failed." << ip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mDeviceTable->hideColumn(0);
|
|
||||||
mDeviceTable->fdIsSelAll->hide();
|
|
||||||
transUi();
|
transUi();
|
||||||
|
|
||||||
|
sendGetInfo();
|
||||||
|
mUdpTimer.start(30000);
|
||||||
}
|
}
|
||||||
|
|
||||||
DevicePanel::~DevicePanel() {
|
DevicePanel::~DevicePanel() {
|
||||||
|
@ -276,6 +264,13 @@ void DevicePanel::sendGetInfo() {
|
||||||
if(mUdpSocket.writeDatagram(data, broadcast, 22222) != data.length()) qDebug() << "getInfo writeDatagram Failed." << ip.toString() << "->" << broadcast.toString();
|
if(mUdpSocket.writeDatagram(data, broadcast, 22222) != data.length()) qDebug() << "getInfo writeDatagram Failed." << ip.toString() << "->" << broadcast.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto ipstr = fdIP->toPlainText();
|
||||||
|
if(! ipstr.isEmpty()) {
|
||||||
|
auto ips = ipstr.split("\n", Qt::SkipEmptyParts);
|
||||||
|
foreach(auto ip, ips) {
|
||||||
|
if(gDevicePanel->mUdpSocket.writeDatagram(data, QHostAddress(ip), 22222) != data.length()) qDebug() << "Specify IP write Failed." << ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePanel::ShowDevicesInfoOrControlWidget(int index){
|
void DevicePanel::ShowDevicesInfoOrControlWidget(int index){
|
||||||
|
|
|
@ -399,8 +399,8 @@ MainWindow::~MainWindow() {
|
||||||
settings.setValue("MainIsMax", isMaximized());
|
settings.setValue("MainIsMax", isMaximized());
|
||||||
settings.setValue("PlayPos", gPlayPos);
|
settings.setValue("PlayPos", gPlayPos);
|
||||||
if(mDevicePanel->fdIP) {
|
if(mDevicePanel->fdIP) {
|
||||||
auto ips = mDevicePanel->fdIP->toPlainText();
|
auto ipstr = mDevicePanel->fdIP->toPlainText();
|
||||||
if(! ips.isEmpty()) settings.setValue("SpecifyIP", ips);
|
if(! ipstr.isEmpty()) settings.setValue("SpecifyIP", ipstr);
|
||||||
}
|
}
|
||||||
if(m_pTimerSendResoreIpOneKey!=nullptr) {
|
if(m_pTimerSendResoreIpOneKey!=nullptr) {
|
||||||
if(m_pTimerSendResoreIpOneKey->isActive()) m_pTimerSendResoreIpOneKey->stop();
|
if(m_pTimerSendResoreIpOneKey->isActive()) m_pTimerSendResoreIpOneKey->stop();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef CRC_H
|
||||||
|
#define CRC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short int uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
|
||||||
|
|
||||||
|
//void crc8_GenerateTable();
|
||||||
|
//void crc8_rohc_GenerateTable();
|
||||||
|
//void crc4_itu_GenerateTable();
|
||||||
|
//void crc5_itu_GenerateTable();
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t crc4_itu_calc (uint8_t *data, uint32_t length);
|
||||||
|
|
||||||
|
uint8_t crc5_epc_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint8_t crc5_itu_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint8_t crc5_usb_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint8_t crc6_itu_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint8_t crc7_mmc_calc (uint8_t *data, uint32_t length);
|
||||||
|
|
||||||
|
uint8_t crc8_Calc (uint8_t *data, uint32_t length);
|
||||||
|
uint8_t crc8_itu_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint8_t crc8_rohc_Calc (uint8_t *data, uint32_t length);
|
||||||
|
uint8_t crc8_maxim_calc (uint8_t *data, uint32_t length);
|
||||||
|
|
||||||
|
uint16_t crc16_ibm_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_maxim_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_usb_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_modbus_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_ccitt_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_ccitt_false_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_x25_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_xmodem_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint16_t crc16_dnp_calc (uint8_t *data, uint32_t length);
|
||||||
|
|
||||||
|
uint32_t crc32_calc (uint8_t *data, uint32_t length);
|
||||||
|
uint32_t crc32_mpeg_2_calc (uint8_t *data, uint32_t length);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif // CRC_H
|
|
@ -27,6 +27,7 @@ win32 {
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
basewin.cpp \
|
basewin.cpp \
|
||||||
brightwin.cpp \
|
brightwin.cpp \
|
||||||
|
crc.c \
|
||||||
expertscreenconnwin.cpp \
|
expertscreenconnwin.cpp \
|
||||||
expertsmartpointsetwin.cpp \
|
expertsmartpointsetwin.cpp \
|
||||||
expertwin.cpp \
|
expertwin.cpp \
|
||||||
|
@ -37,11 +38,13 @@ SOURCES += \
|
||||||
pcapthread.cpp \
|
pcapthread.cpp \
|
||||||
pcapwin.cpp \
|
pcapwin.cpp \
|
||||||
screenunit.cpp \
|
screenunit.cpp \
|
||||||
table.cpp
|
table.cpp \
|
||||||
|
videowin.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
basewin.h \
|
basewin.h \
|
||||||
brightwin.h \
|
brightwin.h \
|
||||||
|
crc.h \
|
||||||
expertscreenconnwin.h \
|
expertscreenconnwin.h \
|
||||||
expertsmartpointsetwin.h \
|
expertsmartpointsetwin.h \
|
||||||
expertwin.h \
|
expertwin.h \
|
||||||
|
@ -51,7 +54,8 @@ HEADERS += \
|
||||||
pcapthread.h \
|
pcapthread.h \
|
||||||
pcapwin.h \
|
pcapwin.h \
|
||||||
screenunit.h \
|
screenunit.h \
|
||||||
table.h
|
table.h \
|
||||||
|
videowin.h
|
||||||
|
|
||||||
TRANSLATIONS += \
|
TRANSLATIONS += \
|
||||||
translations/app_en.ts
|
translations/app_en.ts
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "expertwin.h"
|
#include "expertwin.h"
|
||||||
#include "brightwin.h"
|
#include "brightwin.h"
|
||||||
#include "pcapwin.h"
|
#include "pcapwin.h"
|
||||||
|
#include "videowin.h"
|
||||||
#include "gqt.h"
|
#include "gqt.h"
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
@ -12,6 +13,8 @@
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPainterPath>
|
#include <QPainterPath>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
class ImgBtn : public QToolButton {
|
class ImgBtn : public QToolButton {
|
||||||
public:
|
public:
|
||||||
|
@ -104,9 +107,10 @@ MainWin::MainWin() {
|
||||||
auto ins = PcapWin::newIns(this);
|
auto ins = PcapWin::newIns(this);
|
||||||
if(ins) ins->show();
|
if(ins) ins->show();
|
||||||
});
|
});
|
||||||
btnImg = addImg(imgsBar, QPixmap(":/imgs/idea.png").scaledToWidth(128, Qt::SmoothTransformation), "创意显示");
|
btnImg = addImg(imgsBar, QPixmap(":/imgs/idea.png").scaledToWidth(128, Qt::SmoothTransformation), "视频传输");
|
||||||
connect(btnImg, &ImgBtn::clicked, this, [=](){
|
connect(btnImg, &ImgBtn::clicked, this, [=](){
|
||||||
//qDebug()<<"geometry"<<win->geometry()<<"screen"<<win->screen();
|
auto ins = VideoWin::newIns(this);
|
||||||
|
ins->show();
|
||||||
});
|
});
|
||||||
vBox->addLayout(imgsBar);
|
vBox->addLayout(imgsBar);
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,7 @@ class CapThread : public QThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CapThread(pcap *pcap, QObject *parent = nullptr);
|
explicit CapThread(pcap *pcap, QObject *parent = nullptr);
|
||||||
void setPacketList(QList<Packet> *p){p->clear();packet_list=p;}
|
|
||||||
pcap *pcap{0};
|
pcap *pcap{0};
|
||||||
QList<Packet> *packet_list;
|
|
||||||
Packet packet;
|
Packet packet;
|
||||||
protected:
|
protected:
|
||||||
void run();
|
void run();
|
||||||
|
|
|
@ -0,0 +1,360 @@
|
||||||
|
#include "videowin.h"
|
||||||
|
#include "table.h"
|
||||||
|
#include "gqt.h"
|
||||||
|
#include "crc.h"
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QTimerEvent>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
QByteArray getNetDev(QWidget *parent) {
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
pcap_if_t *devs;
|
||||||
|
if(pcap_findalldevs(&devs, errbuf) == -1) {
|
||||||
|
QMessageBox::critical(parent, "Error", QString("寻找网卡失败")+errbuf);
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
auto table = new Table{
|
||||||
|
{"name", "网卡名称", 400},
|
||||||
|
{"desc", "网卡描述", 300},
|
||||||
|
{"loopback","Loopback"},
|
||||||
|
{"ip","IP"},
|
||||||
|
{"netmask","Netmask"},
|
||||||
|
{"broadaddr","Broad Addr"},
|
||||||
|
{"dstaddr","Dst Addr"}
|
||||||
|
};
|
||||||
|
|
||||||
|
pcap_if_t *device = 0;
|
||||||
|
for(pcap_if_t *dev = devs; dev; dev = dev->next) {
|
||||||
|
pcap_addr_t *a;
|
||||||
|
for(a=dev->addresses; a; a=a->next) {
|
||||||
|
auto sa_family = a->addr->sa_family;
|
||||||
|
if(sa_family==AF_INET) {
|
||||||
|
auto rr = table->rowCount();
|
||||||
|
table->setRowCount(rr+1);
|
||||||
|
table->setValue(rr, "name", dev->name);
|
||||||
|
table->setValue(rr, "desc", dev->description);
|
||||||
|
table->setValue(rr, "loopback", (dev->flags & PCAP_IF_LOOPBACK)?"True":"False");
|
||||||
|
auto ip = (u_char *) &((sockaddr_in *) a->addr)->sin_addr.s_addr;
|
||||||
|
table->setValue(rr, "ip", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||||||
|
if(a->netmask) {
|
||||||
|
ip = (u_char *) &((sockaddr_in *) a->netmask)->sin_addr.s_addr;
|
||||||
|
table->setValue(rr, "netmask", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||||||
|
}
|
||||||
|
if(a->broadaddr) {
|
||||||
|
ip = (u_char *) &((sockaddr_in *) a->broadaddr)->sin_addr.s_addr;
|
||||||
|
table->setValue(rr, "broadaddr", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||||||
|
}
|
||||||
|
if(a->dstaddr) {
|
||||||
|
ip = (u_char *) &((sockaddr_in *) a->dstaddr)->sin_addr.s_addr;
|
||||||
|
table->setValue(rr, "dstaddr", QString::asprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]));
|
||||||
|
}
|
||||||
|
if(device==0) device = dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pcap_freealldevs(devs);
|
||||||
|
|
||||||
|
auto rowCnt = table->rowCount();
|
||||||
|
if(rowCnt==0) {
|
||||||
|
table->deleteLater();
|
||||||
|
QMessageBox::critical(parent, "Error", "没找到 internet 设备");
|
||||||
|
return QByteArray();
|
||||||
|
} else if(rowCnt==1) {
|
||||||
|
table->deleteLater();
|
||||||
|
return table->item(0, "name")->text().toLocal8Bit();
|
||||||
|
} else {
|
||||||
|
auto dlg = new BaseDlg(parent);
|
||||||
|
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
dlg->setWindowTitle("选择网卡");
|
||||||
|
dlg->resize(1200, 300);
|
||||||
|
|
||||||
|
auto vBox = new QVBoxLayout(dlg->center);
|
||||||
|
vBox->setContentsMargins(0,0,0,0);
|
||||||
|
vBox->setSpacing(3);
|
||||||
|
vBox->addSpacing(30);
|
||||||
|
|
||||||
|
table->setDefs();
|
||||||
|
table->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
|
table->selectRow(0);
|
||||||
|
QByteArray name;
|
||||||
|
dlg->connect(table, &Table::cellDoubleClicked, dlg, [dlg, table, &name](int row) {
|
||||||
|
name = table->item(row, "name")->text().toLocal8Bit();
|
||||||
|
dlg->accept();
|
||||||
|
});
|
||||||
|
vBox->addWidget(table);
|
||||||
|
|
||||||
|
auto hBox = new QHBoxLayout;
|
||||||
|
hBox->addStretch();
|
||||||
|
auto btnOk = new QPushButton("确定");
|
||||||
|
btnOk->setMinimumWidth(80);
|
||||||
|
dlg->connect(btnOk, &QPushButton::clicked, dlg, [dlg, table, &name] {
|
||||||
|
auto sels = table->selectedRanges();
|
||||||
|
if(sels.isEmpty()) {
|
||||||
|
QMessageBox::warning(dlg, "Warning", "请选择网卡");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
name = table->item(sels[0].topRow(), "name")->text().toLocal8Bit();
|
||||||
|
dlg->accept();
|
||||||
|
});
|
||||||
|
hBox->addWidget(btnOk);
|
||||||
|
|
||||||
|
hBox->addStretch();
|
||||||
|
|
||||||
|
auto btnClose = new QPushButton("关闭");
|
||||||
|
btnClose->setMinimumWidth(80);
|
||||||
|
dlg->connect(btnClose, &QPushButton::clicked, dlg, &QDialog::reject);
|
||||||
|
hBox->addWidget(btnClose);
|
||||||
|
hBox->addStretch();
|
||||||
|
|
||||||
|
vBox->addLayout(hBox);
|
||||||
|
dlg->exec();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoWin *VideoWin::newIns(QWidget *parent) {
|
||||||
|
auto name = getNetDev(parent);
|
||||||
|
if(name.isEmpty()) return 0;
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE]{'\0'};
|
||||||
|
auto pcapRe = pcap_open(name.data(), 65535, PCAP_OPENFLAG_PROMISCUOUS | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 15, 0, errbuf);
|
||||||
|
if(pcapRe == 0) {
|
||||||
|
QMessageBox::critical(parent, "Error", QString("打开网卡失败")+errbuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto pcapSend = pcap_open(name.data(), 65535, 0, 15, 0, errbuf);
|
||||||
|
if(pcapSend == 0) {
|
||||||
|
QMessageBox::critical(parent, "Error", QString("打开网卡失败")+errbuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return new VideoWin(pcapRe, pcapSend, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoWin::VideoWin(pcap_t *pcapRece, pcap_t *pcapSend, QWidget *parent) : BaseWin{parent} {
|
||||||
|
setWindowModality(Qt::WindowModal);
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
setWindowTitle("视频传输");
|
||||||
|
resize(800, 600);
|
||||||
|
|
||||||
|
auto vBox = new QVBoxLayout(center);
|
||||||
|
vBox->setContentsMargins(0,0,0,0);
|
||||||
|
vBox->setSpacing(3);
|
||||||
|
vBox->addLayout(addBtns(new QHBoxLayout()));
|
||||||
|
|
||||||
|
auto hBox = new HBox(vBox);
|
||||||
|
|
||||||
|
fdWidth = new QSpinBox;
|
||||||
|
fdWidth->setRange(1, 9999);
|
||||||
|
fdWidth->setValue(320);
|
||||||
|
hBox->addWidget(fdWidth);
|
||||||
|
|
||||||
|
hBox->addWidget(new QLabel("x"));
|
||||||
|
|
||||||
|
fdHeight = new QSpinBox;
|
||||||
|
fdHeight->setRange(1, 9999);
|
||||||
|
fdHeight->setValue(180);
|
||||||
|
hBox->addWidget(fdHeight);
|
||||||
|
|
||||||
|
hBox->addSpacing(20);
|
||||||
|
|
||||||
|
auto fdStart = new QRadioButton("发送");
|
||||||
|
connect(fdStart, &QRadioButton::toggled, this, [this](bool checked) {
|
||||||
|
if(! checked) return;
|
||||||
|
screen = QGuiApplication::primaryScreen();
|
||||||
|
if(timerId==0) timerId = startTimer(17);
|
||||||
|
});
|
||||||
|
hBox->addWidget(fdStart);
|
||||||
|
hBox->addSpacing(20);
|
||||||
|
|
||||||
|
fdEnd = new QRadioButton("停止");
|
||||||
|
connect(fdEnd, &QRadioButton::toggled, this, [this](bool checked) {
|
||||||
|
if(! checked) return;
|
||||||
|
if(timerId) {
|
||||||
|
killTimer(timerId);
|
||||||
|
timerId = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hBox->addWidget(fdEnd);
|
||||||
|
hBox->addSpacing(20);
|
||||||
|
|
||||||
|
fdInfo = new QLabel;
|
||||||
|
fdInfo->setStyleSheet("QLabel{color: #f22;}");
|
||||||
|
hBox->addWidget(fdInfo);
|
||||||
|
hBox->addStretch();
|
||||||
|
|
||||||
|
hBox = new HBox(vBox);
|
||||||
|
|
||||||
|
hBox->addWidget(new QLabel("接收:"));
|
||||||
|
hBox->addStretch();
|
||||||
|
|
||||||
|
auto fdReceive = new QLabel;
|
||||||
|
vBox->addWidget(fdReceive, 1);
|
||||||
|
|
||||||
|
thdRece = new VideoRecThread(pcapRece);
|
||||||
|
connect(thdRece, &QThread::finished, this, [this] {
|
||||||
|
thdRece = 0;
|
||||||
|
});
|
||||||
|
connect(thdRece, &VideoRecThread::onMsg, fdReceive, [fdReceive](QImage img) {
|
||||||
|
fdReceive->setPixmap(QPixmap::fromImage(img));
|
||||||
|
});
|
||||||
|
thdRece->start();
|
||||||
|
|
||||||
|
sendThd = new VideoSendThread(pcapSend);
|
||||||
|
connect(sendThd, &QThread::finished, this, [this] {
|
||||||
|
fdEnd->setChecked(true);
|
||||||
|
sendThd = 0;
|
||||||
|
});
|
||||||
|
connect(sendThd, &VideoSendThread::onErr, this, [this](QString err) {
|
||||||
|
fdEnd->setChecked(true);
|
||||||
|
QMessageBox::critical(this, "Error", err);
|
||||||
|
});
|
||||||
|
sendThd->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoWin::timerEvent(QTimerEvent *event) {
|
||||||
|
if(event->timerId()!=timerId) BaseWin::timerEvent(event);
|
||||||
|
else {
|
||||||
|
int width = fdWidth->value();
|
||||||
|
int height = fdHeight->value();
|
||||||
|
if(width < 32 || height < 32) return;
|
||||||
|
auto devicePixelRatio = screen->devicePixelRatio();
|
||||||
|
auto pixmap = screen->grabWindow(0, 0, 0, width/devicePixelRatio, height/devicePixelRatio);
|
||||||
|
auto img = pixmap.toImage();
|
||||||
|
img.convertTo(QImage::Format_RGB888);
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(sendThd->mtx);
|
||||||
|
if(sendThd->imgs.size()>2) return;
|
||||||
|
sendThd->imgs.append(img);
|
||||||
|
}
|
||||||
|
auto now_epoch = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now().time_since_epoch()).count();
|
||||||
|
int dur = now_epoch - last_epoch;
|
||||||
|
last_epoch = now_epoch;
|
||||||
|
fdInfo->setText(info = "帧间隔: "+QString::number(dur)+" 帧缓存: "+QString::number(sendThd ? sendThd->imgs.size() : 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoSendThread::VideoSendThread(pcap_t *pcap) : pcap(pcap) {
|
||||||
|
connect(this, &QThread::finished, this, &QThread::deleteLater);
|
||||||
|
}
|
||||||
|
#define MAX_ONCE 1482
|
||||||
|
void VideoSendThread::run() {
|
||||||
|
QImage img;
|
||||||
|
while(status!=2) {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
|
img = imgs.isEmpty() ? QImage() : imgs.takeFirst();
|
||||||
|
}
|
||||||
|
if(img.isNull()) {
|
||||||
|
QThread::msleep(15);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QByteArray bytes;
|
||||||
|
bytes.append("\x55\x55\x9a\x3d"); //前导, 版本号, 服务类型
|
||||||
|
bytes.append("\0\x4", 2); //数据长度
|
||||||
|
bytes.append(4, '\xff'); //目的地址
|
||||||
|
bytes.append(4, 0); //源地址
|
||||||
|
bytes.append("\x35\0\xc\xbb", 4); //内存指针
|
||||||
|
bytes.append(2, 0); //应答填充项
|
||||||
|
auto crc32 = crc32_calc((uint8_t*)bytes.data()+2, bytes.length()-2);
|
||||||
|
bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32);
|
||||||
|
bytes.append(img.width()>>8).append(img.width()).append(img.height()>>8).append(img.height());
|
||||||
|
crc32 = crc32_calc((uint8_t*)bytes.data()+bytes.length()-4, 4);
|
||||||
|
bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32);
|
||||||
|
auto queue = pcap_sendqueue_alloc(img.width()*img.height()*4);
|
||||||
|
{
|
||||||
|
struct pcap_pkthdr pktheader;
|
||||||
|
pktheader.len = pktheader.caplen = bytes.size();
|
||||||
|
if(pcap_sendqueue_queue(queue, &pktheader, (u_char*)bytes.data()) == -1) {
|
||||||
|
onErr(QString("添加开始失败: ")+pcap_geterr(pcap));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
auto lineLen = img.width() * 3;
|
||||||
|
int once;
|
||||||
|
if(lineLen > MAX_ONCE) {
|
||||||
|
int cnt = (lineLen + MAX_ONCE - 1) / MAX_ONCE;
|
||||||
|
once = (lineLen + cnt - 1) / cnt;
|
||||||
|
} else once = lineLen;
|
||||||
|
auto bytesPerLine = img.bytesPerLine();
|
||||||
|
auto bits = img.constBits();
|
||||||
|
for(uint i=0; i<img.height(); i++) for(uint j=0; j<lineLen; j+=once) {
|
||||||
|
int dataLen = lineLen - j;
|
||||||
|
if(dataLen > once) dataLen = once;
|
||||||
|
dataLen += 4;
|
||||||
|
bytes.clear();
|
||||||
|
bytes.append("\x55\x55\x1\x33"); //前导, 版本号, 服务类型
|
||||||
|
bytes.append(dataLen>>8).append(dataLen); //数据长度
|
||||||
|
bytes.append(4, '\xff'); //目的地址
|
||||||
|
bytes.append(4, 0); //源地址
|
||||||
|
bytes.append(i>>8).append(i).append(j>>8).append(j); //内存指针
|
||||||
|
bytes.append(2, 0); //应答填充项
|
||||||
|
crc32 = crc32_calc((uint8_t*)bytes.data()+2, bytes.length()-2);
|
||||||
|
bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32);
|
||||||
|
bytes.append(i>>24).append(i>>16).append(i>>8).append(i);
|
||||||
|
bytes.append((const char*)bits + i * bytesPerLine + j, dataLen - 4);
|
||||||
|
crc32 = crc32_calc((uint8_t*)bytes.data()+bytes.length()-dataLen, dataLen);
|
||||||
|
bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32);
|
||||||
|
pktheader.len = pktheader.caplen = bytes.size();
|
||||||
|
if(pcap_sendqueue_queue(queue, &pktheader, (u_char*)bytes.data()) == -1) {
|
||||||
|
onErr(QString("添加数据失败: ")+pcap_geterr(pcap));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bytes.clear();
|
||||||
|
bytes.append("\x55\x55\x9a\x3d"); //前导, 版本号, 服务类型
|
||||||
|
bytes.append(2, 0); //数据长度
|
||||||
|
bytes.append(4, '\xff'); //目的地址
|
||||||
|
bytes.append(4, 0); //源地址
|
||||||
|
bytes.append("\x35\0\xc\xcc", 4); //内存指针
|
||||||
|
bytes.append(2, 0); //应答填充项
|
||||||
|
crc32 = crc32_calc((uint8_t*)bytes.data()+2, bytes.length()-2);
|
||||||
|
bytes.append(crc32>>24).append(crc32>>16).append(crc32>>8).append(crc32);
|
||||||
|
pktheader.len = pktheader.caplen = bytes.size();
|
||||||
|
if(pcap_sendqueue_queue(queue, &pktheader, (u_char*)bytes.data()) == -1) {
|
||||||
|
onErr(QString("添加结束失败: ")+pcap_geterr(pcap));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
int res;
|
||||||
|
if((res = pcap_sendqueue_transmit(pcap, queue, 0)) < queue->len) {
|
||||||
|
onErr(QString::asprintf("发送包出错: %s. 仅发了 %d bytes", pcap_geterr(pcap), res));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
pcap_sendqueue_destroy(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoRecThread::VideoRecThread(pcap_t *pcap) : pcap(pcap) {
|
||||||
|
connect(this, &QThread::finished, this, &QThread::deleteLater);
|
||||||
|
}
|
||||||
|
void VideoRecThread::run() {
|
||||||
|
pcap_pkthdr *header;
|
||||||
|
const u_char *data;
|
||||||
|
QImage img;
|
||||||
|
int res;
|
||||||
|
while((res = pcap_next_ex(pcap, &header, &data)) >= 0) {
|
||||||
|
if(status==2) return;
|
||||||
|
if(status==1 || res == 0) continue; //超时
|
||||||
|
if(header->caplen<24) continue;
|
||||||
|
if(data[0]!=0x55 || data[1]!=0x55) continue;
|
||||||
|
if(data[2]==0x9a && data[3]==0x3d) {
|
||||||
|
if(data[17]==0xBB) img = QImage(((int)data[24] << 8) + data[25], ((int)data[26] << 8) + data[27], QImage::Format_RGB888);
|
||||||
|
else if(data[17]==0xCC) emit onMsg(img);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(data[2]!=0x1 || data[3]!=0x33) continue;
|
||||||
|
int len = ((int)data[4] << 8) + data[5];
|
||||||
|
int row = ((int)data[14] << 8) + data[15];
|
||||||
|
int col = ((int)data[16] << 8) + data[17];
|
||||||
|
memcpy(img.bits()+row*img.bytesPerLine()+col, &data[28], len-4);
|
||||||
|
}
|
||||||
|
emit onErr(pcap_geterr(pcap));
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
#ifndef VIDEOWIN_H
|
||||||
|
#define VIDEOWIN_H
|
||||||
|
#include "basewin.h"
|
||||||
|
|
||||||
|
#define HAVE_REMOTE
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include "pcap.h"
|
||||||
|
#include <QThread>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QRadioButton>
|
||||||
|
#include "Win32-Extensions.h"
|
||||||
|
|
||||||
|
#pragma comment(lib, "wpcap.lib")
|
||||||
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
|
|
||||||
|
QByteArray getNetDev(QWidget *parent);
|
||||||
|
|
||||||
|
class VideoSendThread : public QThread {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VideoSendThread(pcap *pcap);
|
||||||
|
~VideoSendThread() {
|
||||||
|
pcap_close(pcap);
|
||||||
|
}
|
||||||
|
pcap *pcap;
|
||||||
|
std::atomic<char> status{0};
|
||||||
|
QList<QImage> imgs;
|
||||||
|
std::mutex mtx;
|
||||||
|
protected:
|
||||||
|
void run();
|
||||||
|
signals:
|
||||||
|
void onErr(QString);
|
||||||
|
};
|
||||||
|
class VideoRecThread : public QThread {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit VideoRecThread(pcap *pcap);
|
||||||
|
~VideoRecThread() {
|
||||||
|
pcap_close(pcap);
|
||||||
|
}
|
||||||
|
pcap *pcap;
|
||||||
|
std::atomic<char> status{0};
|
||||||
|
protected:
|
||||||
|
void run();
|
||||||
|
signals:
|
||||||
|
void onMsg(QImage);
|
||||||
|
void onErr(char *);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VideoWin : public BaseWin {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static VideoWin *newIns(QWidget *);
|
||||||
|
|
||||||
|
explicit VideoWin(pcap *, pcap *, QWidget *parent = nullptr);
|
||||||
|
~VideoWin() {
|
||||||
|
if(thdRece) thdRece->status = 2;
|
||||||
|
if(sendThd) sendThd->status = 2;
|
||||||
|
if(timerId) killTimer(timerId);
|
||||||
|
}
|
||||||
|
VideoRecThread *thdRece{0};
|
||||||
|
VideoSendThread *sendThd{0};
|
||||||
|
QScreen *screen;
|
||||||
|
int timerId{0};
|
||||||
|
QSpinBox *fdWidth, *fdHeight;
|
||||||
|
QRadioButton *fdEnd;
|
||||||
|
QLabel *fdInfo;
|
||||||
|
QString info;
|
||||||
|
qint64 last_epoch{0};
|
||||||
|
protected:
|
||||||
|
void timerEvent(QTimerEvent *event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // VIDEOWIN_H
|
Loading…
Reference in New Issue
Block a user