Compare commits

..

2 Commits

@ -1,7 +1,6 @@
QT += core gui webenginewidgets
QT += network
QT += quickwidgets qml
QT += sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
@ -60,7 +59,6 @@ INCLUDEPATH += $$PWD/3rdparty/ffmpeg/include \
$$PWD/Src/VideoGL/ \
$$PWD/Src/Video/ \
$$PWD/3rdparty/QNotify/include \
$$PWD/Src/UserManage \
LIBS += -L$$PWD/3rdparty/ffmpeg/lib \
-lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc \
@ -89,4 +87,3 @@ include($$PWD/Src/RescueLoad/RescueLoad.pri)
include($$PWD/Src/GDDC/GDDC.pri)
include($$PWD/Src/Video/Video.pri)
include($$PWD/Src/VideoGL/VideoGL.pri)
include($$PWD/Src/UserManage/UserManage.pri)

@ -14,52 +14,9 @@ SDFPDlg::SDFPDlg(QWidget *parent)
setWindowFlags(Qt::CustomizeWindowHint|Qt::FramelessWindowHint);
hide();
ui->label_version->setText(g_SoftwareVersion);
initButton();
}
SDFPDlg::~SDFPDlg()
{
delete ui;
}
void SDFPDlg::initButton()
{
ui->loginButton->setStyleSheet("QPushButton {"
"border: none;" // 没有边框
"color: #CFCFCF;" // 默认字体颜色为白色
"font-size: 18px;" // 字体大小为 20
"font-weight: bold;"
"background-color: transparent;" // 背景透明
"font-family: 'STHeiti';"
"}"
// 设置按钮悬停时的样式
"QPushButton:hover {"
"color: #5289C1;" // 悬停时字体颜色变为橙色
"}"
// 设置按钮按下时的字体颜色
"QPushButton:pressed {"
"color: #4A7DB0;" // 按下时字体颜色变为绿色
"}"
// 设置按钮选中时的样式
"QPushButton:checked {"
"color: #5289C1;" // 选中时字体颜色变为绿色
"}"
);
}
void SDFPDlg::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
// double weidgeteWidth = (double)(this->width());
// // 设置按钮位置和大小
// _loginBtn->move(weidgeteWidth - _loginBtn->width() - 20,20);
}
void SDFPDlg::on_loginButton_clicked()
{
emit clickLoginBtn();
}

@ -3,7 +3,6 @@
#include <QWidget>
#include "global.h"
#include <QPushButton>
namespace Ui {
class SDFPDlg;
@ -19,16 +18,6 @@ public:
private:
Ui::SDFPDlg *ui;
void initButton();
QPushButton* _loginBtn;
protected:
void resizeEvent(QResizeEvent *event) override;
private slots:
void on_loginButton_clicked();
signals:
void clickLoginBtn();
};
#endif // SDFPDLG_H

@ -17,39 +17,7 @@
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<item row="0" column="2">
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@ -62,41 +30,31 @@
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QWidget" name="widget_2" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
<item row="1" column="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_version">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="spacing">
<number>0</number>
<property name="text">
<string>版本号V0.00.00</string>
</property>
<item row="0" column="0">
<spacer name="horizontalSpacer_3">
</widget>
</item>
</layout>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
@ -105,8 +63,8 @@
</property>
</spacer>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_4">
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
@ -115,45 +73,12 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="loginButton">
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>登录</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_version">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>版本号V0.00.00</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>

@ -3,7 +3,6 @@ SOURCES += \
$$PWD/gddcdlg.cpp \
$$PWD/gddcSet.cpp \
$$PWD/gddcStateInfo.cpp \
$$PWD/udppushdlg.cpp \
HEADERS += \
$$PWD/gddcCmdDlg.h \
@ -12,14 +11,13 @@ HEADERS += \
$$PWD/gddcStateInfo.h \
$$PWD/structDefineMyslef.h \
$$PWD/DCFrameCkCmd.h \
$$PWD/udppushdlg.h \
FORMS += \
$$PWD/gddcCmdDlg.ui \
$$PWD/gddcdlg.ui \
$$PWD/gddcSet.ui \
$$PWD/gddcStateInfo.ui \
$$PWD/udppushdlg.ui \
RESOURCES += \
$$PWD/res.qrc

@ -14,15 +14,6 @@ GDDCSet::GDDCSet(QWidget *parent) : QWidget(parent), ui(new Ui::GDDCSet) {
ui->label_3->setVisible(false);
ui->comboBox_streamType->setVisible(false);
QString urlFile = QCoreApplication::applicationDirPath() + "/config.ini";
std::unique_ptr<QSettings> configIni = std::make_unique<QSettings>(urlFile, QSettings::IniFormat);
QString podIp = configIni->value("Pod/IP").toString();
initPullURL(podIp);
m_udpPushDlg = new udpPushDlg(this);
m_udpPushDlg->setWindowFlags(Qt::Dialog);
m_udpPushDlg->setWindowModality(Qt::WindowModal);//设置为模态对话框
connect(this->m_udpPushDlg,&udpPushDlg::sendUdpPushUrl,this,&GDDCSet::processUdpUrl);
}
GDDCSet::~GDDCSet() {
@ -61,14 +52,12 @@ void GDDCSet::initParam() {
ui->comboBox_playURL1->setEditable(true);
ui->comboBox_streamSource->addItem("地面端");
ui->comboBox_streamSource->addItem("载荷端");
ui->comboBox_streamSource->addItem("局域网");
ui->comboBox_streamSource->setCurrentIndex(0);
// 应急厅指挥平台----->push.uavideo.cn
ui->comboBox_pushURL->addItem(QStringLiteral("应急厅指挥平台"));
// 应急厅铁塔平台----->182.92.130.23
ui->comboBox_pushURL->addItem(QStringLiteral("应急厅铁塔平台"));
ui->comboBox_pushURL->addItem(QStringLiteral("局域网设备平台"));
ui->radioButton_NetCtrlUDP->setChecked(true);
ui->radioButton_NetCtrlTCP->setChecked(false);
@ -125,7 +114,6 @@ void GDDCSet::initParam() {
// 视频连接-显示窗口1-连接
void GDDCSet::on_pushButton_ConnectURL1_clicked() {
ui->pushButton_ConnectURL1->setEnabled(false);
qDebug() << "点击后的拉流地址" << ui->comboBox_playURL1->currentText();
saveDataToLocalIni();
if (ui->pushButton_ConnectURL1->text() == "连接") {
emit SignalStartConnect(1);
@ -411,46 +399,3 @@ void GDDCSet::on_radioButton_clicked() {
ui->uavIDSpinBox->setEnabled(true);
}
}
void GDDCSet::on_comboBox_pushURL_activated(int index)
{
if(index == 2)//下拉列表选中局域网设备推流
{
if(!m_udpPushDlg->isVisible())
{
m_udpPushDlg->show();
}
qDebug()<<"当前索引:"<< index;
m_udpPushDlg->setStateByPushOrPull(udpPushDlg::pushStreamUrl);
}
}
void GDDCSet::processUdpUrl(QString udpUrl, int index)
{
switch(index)
{
case udpPushDlg::pushStreamUrl:
m_pushURL = udpUrl;
break;
case udpPushDlg::pullStreamUrl:
ui->comboBox_playURL1->setCurrentText(udpUrl);
break;
default:
break;
}
}
void GDDCSet::on_comboBox_streamSource_activated(int index)
{
if(index == 2)//下拉列表选中局域网设备拉流
{
if(!m_udpPushDlg->isVisible())
{
m_udpPushDlg->show();
}
qDebug()<<"当前索引:"<< index;
m_udpPushDlg->setStateByPushOrPull(udpPushDlg::pullStreamUrl);
}
}

@ -10,8 +10,6 @@
#include "Src/GDDC/structDefineMyslef.h"
#include "global.h"
#include "udppushdlg.h"
namespace Ui {
class GDDCSet;
}
@ -28,8 +26,7 @@ private:
std::map<int, QString> mapPushURL_yjzh;
std::map<int, QString> mapPushURL_yjtt;
public:
udpPushDlg* m_udpPushDlg;
public:
void initUDPSocket(); // 初始化UDPSocket
void initWindow(); // 初始化窗口
@ -75,9 +72,6 @@ private slots:
void on_uavIDSpinBox_valueChanged(int arg1);
void on_comboBox_streamSource_currentIndexChanged(int index);
void on_radioButton_clicked();
void on_comboBox_pushURL_activated(int index);
void processUdpUrl(QString udpUrl, int index);
void on_comboBox_streamSource_activated(int index);
};
#endif // GDDCSET_H

@ -95,8 +95,6 @@ void GDDCdlg::initWindow() {
// Qt::UniqueConnection);
connect(ui->WgtffmpegVideo, &VideoWidget::sendErrorMessageSignal, this,
&GDDCdlg::showErrorMessage, Qt::UniqueConnection);
connect(m_DlgGDDCSet->m_udpPushDlg,&udpPushDlg::sendErrorMessageSignal,this,
&GDDCdlg::showErrorMessage);
ui->WgtffmpegVideo->setVedioSaveFileDirPath("./Video");
}
@ -473,7 +471,7 @@ void GDDCdlg::resizeUI() {
void GDDCdlg::setGlobalSetMap(
std::unordered_map<QString, settingStruct> &gSetMap) {
if (m_DlgGDDCSet) {
m_DlgGDDCSet->initPullURL(gSetMap["光电吊舱"].net.remoteIp);
m_DlgGDDCSet->initPullURL(gSetMap["Pod"].net.remoteIp);
}
}
@ -524,8 +522,7 @@ void GDDCdlg::startConnectURL1() {
*/
VideoWidget *videoWidget = ui->WgtffmpegVideo;
qDebug() << "当前拉流地址" << m_DlgGDDCSet->m_playURL1;
if (!videoWidget->play(m_DlgGDDCSet->m_playURL1,true)) {
if (!videoWidget->play(m_DlgGDDCSet->m_playURL1)) {
g_notifyManager->notify("获取视频流失败!", "", 2, 3000);
// ui->WgtffmpegVideo->stopPlay();
// m_DlgGDDCSet->setPullBtnText(false);

@ -1,87 +0,0 @@
#include "udppushdlg.h"
#include "ui_udppushdlg.h"
#include <QRegularExpression>
#include <QRegularExpressionValidator>
udpPushDlg::udpPushDlg(QWidget *parent)
: QWidget(parent)
, ui(new Ui::udpPushDlg)
{
ui->setupUi(this);
this->setFixedSize(400,300);
initLineEdit();
QString urlFile = QCoreApplication::applicationDirPath() + "/config.ini";
_configIni = std::make_unique<QSettings>(urlFile, QSettings::IniFormat);
showParam4Ini();
}
udpPushDlg::~udpPushDlg()
{
delete ui;
}
void udpPushDlg::initLineEdit()
{
// 定义正则表达式:允许大写字母、小写字母、数字和特殊符号
QRegularExpression regExp("^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
// 创建验证器
QRegularExpressionValidator *validator = new QRegularExpressionValidator(regExp, this);
QRegularExpression rx("[0-9]+"); // 只允许数字
QRegularExpressionValidator *validator1 = new QRegularExpressionValidator(rx, this);
// 设置验证器
ui->lineEdit->setValidator(validator);
ui->lineEdit_2->setValidator(validator1);
}
void udpPushDlg::showParam4Ini()
{
QString udpPushIp = _configIni->value("UDPPushStream/IP").toString();
int udpPushPort = _configIni->value("UDPPushStream/Port").toInt();
ui->lineEdit->setText(udpPushIp);
ui->lineEdit_2->setText(QString::number(udpPushPort));
}
void udpPushDlg::setStateByPushOrPull(udpUrlType tpye)
{
m_state = tpye;
}
//保存界面IP及端口号参数
void udpPushDlg::saveParam2Ini()
{
_configIni->setValue("UDPPushStream/IP", ui->lineEdit->text());
_configIni->setValue("UDPPushStream/Port", ui->lineEdit_2->text());
}
//点击确定按钮
void udpPushDlg::on_okPushBtn_clicked()
{
if(ui->lineEdit->text().isEmpty())
{
emit sendErrorMessageSignal("输入IP地址不能为空",3);
return;
}
if(ui->lineEdit_2->text().isEmpty())
{
emit sendErrorMessageSignal("输入端口号不能为空",3);
return;
}
if(this->isVisible())
this->hide();
m_udpPushUrl = QString("udp://%1:%2").arg(ui->lineEdit->text()).arg(ui->lineEdit_2->text());
if(m_state == pushStreamUrl)
emit sendUdpPushUrl(m_udpPushUrl, pushStreamUrl);
else if(m_state == pullStreamUrl)
emit sendUdpPushUrl(m_udpPushUrl, pullStreamUrl);
saveParam2Ini();
}

@ -1,38 +0,0 @@
#ifndef UDPPUSHDLG_H
#define UDPPUSHDLG_H
#include <QWidget>
#include <QSettings>
namespace Ui {
class udpPushDlg;
}
class udpPushDlg : public QWidget
{
Q_OBJECT
public:
explicit udpPushDlg(QWidget *parent = nullptr);
~udpPushDlg();
enum udpUrlType{ pullStreamUrl=0, pushStreamUrl=1};
void setStateByPushOrPull(udpUrlType tpye); //设置推拉流状态
private slots:
void on_okPushBtn_clicked();
private:
Ui::udpPushDlg *ui;
QString m_udpPushUrl;//udp推流地址
void initLineEdit();
void saveParam2Ini();
void showParam4Ini();
std::unique_ptr<QSettings> _configIni; //配置文件写入
int m_state = -1; //推拉流状态初始化为-1
signals:
void sendErrorMessageSignal(QString message, int type);
void sendUdpPushUrl(QString udpUrl, int index);
};
#endif // UDPPUSHDLG_H

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>udpPushDlg</class>
<widget class="QWidget" name="udpPushDlg">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>网络设置</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>局域网视频流网络设置</string>
</property>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>90</x>
<y>57</y>
<width>201</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>20</x>
<y>113</y>
<width>51</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>端口号:</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>20</x>
<y>57</y>
<width>36</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>IP:</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_2">
<property name="geometry">
<rect>
<x>90</x>
<y>113</y>
<width>201</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="okPushBtn">
<property name="geometry">
<rect>
<x>200</x>
<y>169</y>
<width>80</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>确定</string>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

@ -1,59 +0,0 @@
#include "udppushdlg.h"
#include "ui_udppushdlg.h"
#include <QRegularExpression>
#include <QRegularExpressionValidator>
udpPushDlg::udpPushDlg(QWidget *parent)
: QWidget(parent)
, ui(new Ui::udpPushDlg)
{
ui->setupUi(this);
this->setFixedSize(400,300);
initLineEdit();
}
udpPushDlg::~udpPushDlg()
{
delete ui;
}
void udpPushDlg::initLineEdit()
{
// 定义正则表达式:允许大写字母、小写字母、数字和特殊符号
QRegularExpression regExp("^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\."
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
// 创建验证器
QRegularExpressionValidator *validator = new QRegularExpressionValidator(regExp, this);
QRegularExpression rx("[0-9]+"); // 只允许数字
QRegularExpressionValidator *validator1 = new QRegularExpressionValidator(rx, this);
// 设置验证器
ui->lineEdit->setValidator(validator);
ui->lineEdit_2->setValidator(validator1);
}
//点击确定按钮
void udpPushDlg::on_okPushBtn_clicked()
{
if(ui->lineEdit->text().isEmpty())
{
emit sendErrorMessageSignal("输入IP地址不能为空",3);
return;
}
if(ui->lineEdit_2->text().isEmpty())
{
emit sendErrorMessageSignal("输入端口号不能为空",3);
return;
}
if(this->isVisible())
this->hide();
m_udpPushUrl = QString("udp://%1:%2").arg(ui->lineEdit->text()).arg(ui->lineEdit_2->text());
emit sendUdpPushUrl(m_udpPushUrl, pushStreamUrl);
}

@ -1,33 +0,0 @@
#ifndef UDPPUSHDLG_H
#define UDPPUSHDLG_H
#include <QWidget>
namespace Ui {
class udpPushDlg;
}
class udpPushDlg : public QWidget
{
Q_OBJECT
public:
explicit udpPushDlg(QWidget *parent = nullptr);
~udpPushDlg();
enum udpUrlType{ pullStreamUrl=0, pushStreamUrl=1};
private slots:
void on_okPushBtn_clicked();
private:
Ui::udpPushDlg *ui;
QString m_udpPushUrl;//udp推流地址
void initLineEdit();
signals:
void sendErrorMessageSignal(QString message, int type);
void sendUdpPushUrl(QString url, int index);
};
#endif // UDPPUSHDLG_H

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>udpPushDlg</class>
<widget class="QWidget" name="udpPushDlg">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>网络设置</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>局域网视频流网络设置</string>
</property>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>90</x>
<y>57</y>
<width>201</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>20</x>
<y>113</y>
<width>51</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>端口号:</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>20</x>
<y>57</y>
<width>36</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>IP:</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit_2">
<property name="geometry">
<rect>
<x>90</x>
<y>113</y>
<width>201</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="okPushBtn">
<property name="geometry">
<rect>
<x>200</x>
<y>169</y>
<width>80</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>确定</string>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

@ -1,13 +0,0 @@
HEADERS += \
$$PWD/mydatabase.h \
$$PWD/userlogin.h
SOURCES += \
$$PWD/mydatabase.cpp \
$$PWD/userlogin.cpp
RESOURCES += \
$$PWD/res.qrc
FORMS += \
$$PWD/userlogin.ui

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

@ -1,274 +0,0 @@
#include "mydatabase.h"
#include <QCoreApplication>
MyDatabase::MyDatabase()
{
if (QSqlDatabase::contains("qt_sql_default_connection"))
{
database = QSqlDatabase::database("qt_sql_default_connection");
}
else
{
// 建立和SQlite数据库的连接
database = QSqlDatabase::addDatabase("QSQLITE");
QString dbPath = QCoreApplication::applicationDirPath() + "//UserDataBase.db";
// 设置数据库文件的名字
database.setDatabaseName(dbPath);
database.setUserName("root");
database.setPassword("123456");
}
openDb();
if(!isTableExist("user"))
{
createTable();
}
QList<userData> list;
userData u1 = {"htsdfp1","123456","emergency"};
userData u2 = {"htsdfp2","123456","seaRescue"};
userData u3 = {"htsdfp3","123456","emergency"};
list += {u1,u2,u3};
multipleInsertData(list);
userData u4 = {"htsdfp4","123456","admin"};
singleInsertData(u4);
// deleteData("wanghaoyu4");
// queryDataByUsername("wanghaoyu3");
// userData u5 = {"wanghaoyu8","123456","yingji1"};
// updateDataByUsername(u5,1);
}
bool MyDatabase::openDb()
{
if (!database.open())
{
qDebug() << "Error: Failed to connect database." << database.lastError();
return false;
}
else
{
qDebug() << "数据库打开成功." ;
}
return true;
}
void MyDatabase::createTable()
{
// 用于执行sql语句的对象
QSqlQuery sqlQuery;
// 构建创建数据库的sql语句字符串
QString createSql = QString("CREATE TABLE IF NOT EXISTS user (\
id INTEGER PRIMARY KEY AUTOINCREMENT,\
username VARCHAR(50) UNIQUE NOT NULL,\
password VARCHAR(50) NOT NULL,\
scene VARCHAR(100) NOT NULL,\
is_del INTEGER DEFAULT 0,\
created_at TIMESTAMP DEFAULT (DATETIME('now', 'localtime')),\
updated_at TIMESTAMP DEFAULT (DATETIME('now', 'localtime')))");
sqlQuery.prepare(createSql);
// 创建触发器
QString triggerSql = R"(
CREATE TRIGGER IF NOT EXISTS update_user_updated_at
AFTER UPDATE ON user
FOR EACH ROW
BEGIN
UPDATE user SET updated_at = CURRENT_TIMESTAMP WHERE id = OLD.id;
END;
)";
// 执行sql语句
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to create table. " << sqlQuery.lastError();
}
else
{
qDebug() << "Table created!";
}
}
bool MyDatabase::isTableExist(const QString &tableName)
{
if(!database.isOpen())
{
return false;
}
return database.tables().contains(tableName);
}
bool MyDatabase::singleInsertData(userData &singleData)
{
database.transaction();//开启事务
QSqlQuery sqlQuery;
sqlQuery.prepare("INSERT INTO user (username, password, scene) VALUES(?, ?, ?)");
sqlQuery.addBindValue(singleData.username);
sqlQuery.addBindValue(singleData.password);
sqlQuery.addBindValue(singleData.scene);
if(!sqlQuery.exec())
{
if(sqlQuery.lastError().text().contains("UNIQUE constraint failed"))
{
qDebug() << "用户名已存在:" << singleData.username;
}
qDebug() << "Error: Fail to insert data. " << sqlQuery.lastError();
database.rollback();//回滚
return false;
}
else
{
database.commit();//提交
return true;
}
}
bool MyDatabase::multipleInsertData(QList<userData> &multipleData)
{
database.transaction();//开启事务
QSqlQuery sqlQuery;
sqlQuery.prepare("INSERT INTO user (username, password, scene) VALUES(?, ?, ?)");
QVariantList usernameList,passwordList,sceneList;
for(userData value : multipleData)
{
usernameList << value.username;
passwordList << value.password;
sceneList << value.scene;
}
sqlQuery.addBindValue(usernameList);
sqlQuery.addBindValue(passwordList);
sqlQuery.addBindValue(sceneList);
if(!sqlQuery.execBatch())
{
qDebug() << "Error: Fail to insert data. " << sqlQuery.lastError();
database.rollback();//回滚
return false;
}
else
{
database.commit();//提交
return true;
}
}
bool MyDatabase::deleteData(const QString &username)
{
database.transaction();
QSqlQuery sqlQuery;
sqlQuery.prepare("UPDATE user SET is_del=?,updated_at=(DATETIME('now', 'localtime')) WHERE username=?");
sqlQuery.addBindValue(1);
sqlQuery.addBindValue(username);
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to delete data. "<< sqlQuery.lastError();
database.rollback();
return false;
}
else
{
qDebug() << "delete data success!";
database.commit();
return true;
}
}
bool MyDatabase::updateDataByUsername(const userData &data, const int &is_del)
{
if(!queryConuntByUsername(data.username))//根据用户名没有查询到数据-不进行更新操作 查询已有数据
{
return false;
}
database.transaction();
QSqlQuery sqlQuery;
sqlQuery.prepare("UPDATE user SET password=? ,scene=?, is_del=?, updated_at=(DATETIME('now', 'localtime')) WHERE username=? AND scene != 'admin'");
sqlQuery.addBindValue(data.password);
sqlQuery.addBindValue(data.scene);
sqlQuery.addBindValue(is_del);
sqlQuery.addBindValue(data.username);
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to update data. "<< sqlQuery.lastError();
database.rollback();
return false;
}
else
{
qDebug() << "update data success!";
database.commit();
return true;
}
}
bool MyDatabase::queryDataByUsername(const QString &username, const int &isDel)
{
QSqlQuery sqlQuery;
sqlQuery.prepare("SELECT * FROM user WHERE is_del = ? AND username=?");
sqlQuery.addBindValue(isDel);
sqlQuery.addBindValue(username);
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to query table. " << sqlQuery.lastError();
return false;
}
else
{
qDebug() << "query data success!";
if(!sqlQuery.next())
{
qDebug() << "No data found!";//没找到数据
return false;
}
// sqlQuery.previous();
do{
int id = sqlQuery.value("id").toInt();
_queryUserData.username = sqlQuery.value("username").toString();
_queryUserData.password = sqlQuery.value("password").toString();
_queryUserData.scene = sqlQuery.value("scene").toString();
qDebug()<<QString("id:%1 username:%2 password:%3 scene:%4")
.arg(id).arg(_queryUserData.username).arg(_queryUserData.password).arg(_queryUserData.scene);
}while(sqlQuery.next());
return true;
}
}
bool MyDatabase::queryConuntByUsername(const QString &username)
{
QSqlQuery checkQuery;
checkQuery.prepare("SELECT COUNT(*) FROM user WHERE username=?");
checkQuery.addBindValue(username);
if (!checkQuery.exec()) {
qDebug() << "Error: Failed to execute count_query." << checkQuery.lastError();
return false;
}
//直接调用 next(),然后取值
if (checkQuery.next()) {
int count = checkQuery.value(0).toInt();
qDebug() << "User count:" << count;
if (count == 0) {
qDebug() << "Error: count = 0 Username does not exist.";
return false;
}
} else {
qDebug() << "Error: Query returned no results.";
return false;
}
return true;
}
userData MyDatabase::getQueryUserData()
{
return _queryUserData;
}

@ -1,54 +0,0 @@
#ifndef MYDATABASE_H
#define MYDATABASE_H
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QList>
typedef struct
{
QString username;
QString password;
QString scene;
}userData;
class MyDatabase
{
public:
MyDatabase();
// 打开数据库
bool openDb();
// 创建数据表
void createTable();
// 判断数据表是否存在
bool isTableExist(const QString& tableName);
// 插入数据
bool singleInsertData(userData &singleData); // 插入单条数据
bool multipleInsertData(QList<userData> &multipleData); // 插入多条数据
//删除数据
bool deleteData(const QString &username);
//修改数据-密码 场景
bool updateDataByUsername(const userData &data, const int &is_del);
//查询数据-isDel用于判断查询的数据是否是已经删除的数据
bool queryDataByUsername(const QString &username, const int &isDel);
//查询用户名数据的数量
bool queryConuntByUsername(const QString &username);
//获取查询到的数据
userData getQueryUserData();
private:
QSqlDatabase database;// 用于建立和数据库的连接
userData _queryUserData;
};
#endif // MYDATABASE_H

@ -1,6 +0,0 @@
<RCC>
<qresource prefix="/">
<file>img/eyesOpen.png</file>
<file>img/eyesOpen1.png</file>
</qresource>
</RCC>

@ -1,310 +0,0 @@
#include "userlogin.h"
#include "ui_userlogin.h"
#include <QMessageBox>
#include <QRegularExpressionValidator>
#include <QLabel>
#include "global.h"
UserLogin::UserLogin(QWidget *parent)
: QWidget(parent)
, ui(new Ui::UserLogin)
{
ui->setupUi(this);
initLineEdit();
initControls();
}
UserLogin::~UserLogin()
{
delete ui;
}
void UserLogin::initLineEdit()
{
// 定义正则表达式:允许大写字母、小写字母、数字和特殊符号
QRegularExpression regExp("[A-Za-z0-9!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]+");
// 创建验证器
QRegularExpressionValidator *validator = new QRegularExpressionValidator(regExp, this);
// 设置验证器
ui->userlineEdit->setValidator(validator);
ui->passwordlineEdit->setValidator(validator);
}
void UserLogin::initControls()
{
QPixmap pixmap(":/res/SDFP3.png");
ui->loginlabel->setPixmap(pixmap);
ui->loginlabel->setScaledContents(true);
ui->widget_2->setStyleSheet("background-color: #1E1E1D;"
"border-top-left-radius: 20px; "
"border-top-right-radius: 20px;");
ui->widget_3->setObjectName("widget_3"); // 给 widget_3 设置对象名称
ui->widget_3->setStyleSheet("QWidget#widget_3 {"
"background-color: #363636;"
// "border-bottom-left-radius: 20px; "
// "border-bottom-right-radius: 20px;"
"}");
ui->stackedWidget_2->setObjectName("stackedWidget_2");
ui->stackedWidget_2->setStyleSheet("QWidget {"
"background-color: #363636;"
"border-bottom-left-radius: 20px; "
"border-bottom-right-radius: 20px;"
"margin-left: 0px;"
"margin-right: 0px;"
"}");
ui->userlineEdit->setStyleSheet("border-radius: 5px;");
ui->passwordlineEdit->setStyleSheet("border-radius: 5px;");
ui->loginButton->setStyleSheet(g_okButtonStyle);
ui->exitButton->setStyleSheet("QPushButton{"
"font-family: STHupo;"
"border-radius: 15px;"
"color: white;"
"font-weight: bold;"
"border: none;"
"background-color: #A52A2A;"
"font-size: 20px;"
"}"
// 设置按钮悬停时的样式
"QPushButton:hover {"
"background-color: #8B1C1C;" // 悬停时的背景颜色
"}"
// 设置按钮按下或选中时的渐变背景
"QPushButton::pressed, QPushButton::checked {"
"color: #FFFFFF;" // 字体颜色为白色
"background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, "
"stop:0 #5C1919, stop:1 #9E2A2A);" // 渐变背景
"}");
_passwordCheckBox = new QCheckBox(ui->passwordlineEdit);
//设置样式表(图片为眼睛样式)
_passwordCheckBox->setStyleSheet("QCheckBox::indicator {"
"width: 20px;"
"height: 20px;"
"image: url(:/res/eyec1.png);" // 未选中时的图片
"}"
"QCheckBox::indicator:checked {"
"image: url(:/res/eye3.png);" // 选中时的图片
"}");
ui->label->setStyleSheet("QLabel {"
"font-family: 'STHupo';" // 使用艺术字体
"font-size: 40px;" // 设置字体大小
"font-weight: bold;" // 设置加粗
"color: #5289C1;" // 设置字体颜色
"text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);" // 添加阴影效果
"}");
ui->label->setAlignment(Qt::AlignCenter);
ui->pushButton->setStyleSheet(g_loginButtonStyle);
ui->pushButton_login->setStyleSheet(g_loginButtonStyle);
ui->pushButton_register->setStyleSheet(g_loginButtonStyle);
ui->label_2->setStyleSheet("font-size: 18px;"
"color: #CFCFCF;");
//注册页面
ui->registerButton->setStyleSheet(g_okButtonStyle);
ui->senceComboBox->addItem("应急场景", QVariant("emergency"));
ui->senceComboBox->addItem("海上救捞", QVariant("seaRescue"));
ui->senceComboBox->setStyleSheet("QComboBox {"
"border-radius: 5px;"/*圆角*/
"}");
connect(_passwordCheckBox,&QCheckBox::checkStateChanged,this,[this](int state){
if(state == Qt::Checked)
{
ui->passwordlineEdit->setEchoMode(QLineEdit::Normal);
}
else if(state == Qt::Unchecked)
{
ui->passwordlineEdit->setEchoMode(QLineEdit::Password);
}
});
}
bool UserLogin::checkEditFormat(const QString &edit, const QString &origins)
{
if(edit.isEmpty())
{
showTopMessage("输入"+origins+"不能为空!", LOGINERROR);
return false;
}
else
{
// 定义正则表达式:至少 8 个字符,且只能是大写字母、小写字母、数字和特殊符号
QRegularExpression regExp("[A-Za-z0-9!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]{6,}");
// 检查输入内容
if (!regExp.match(edit).hasMatch())
{
showTopMessage(origins +"至少输入 6 个字符,且只能包含大写字母、小写字母、数字和特殊符号!", LOGINERROR);
return false;
}
}
return true;
}
void UserLogin::showTopMessage(QString message, MyNotifyType type)
{
if(g_notifyManager)
{
g_notifyManager->notify(message, "", type, 3000);
}
}
bool UserLogin::queryDataByUsername(const QString &username)
{
if(dataBase.queryDataByUsername(username, 0))
{
_queryUserData = dataBase.getQueryUserData();
if(_queryUserData.password == ui->passwordlineEdit->text())//密码匹配
{
return true;
}
else
{
showTopMessage("密码输入错误!", LOGINERROR);
return false;
}
}
else
{
//用户名不存在
showTopMessage("用户名不存在!", LOGINERROR);
return false;
}
}
void UserLogin::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
_passwordCheckBox->setGeometry(ui->passwordlineEdit->width()-30,(ui->passwordlineEdit->height()/2)-10,20,20);
}
void UserLogin::on_loginButton_clicked()
{
if(!checkEditFormat(ui->userlineEdit->text(),"用户名"))
return;
if(!checkEditFormat(ui->passwordlineEdit->text(),"密码"))
return;
//查询到数据
if(queryDataByUsername(ui->userlineEdit->text()))
{
//判断场景
if(_queryUserData.scene == "emergency")
{
emit sendSenceData(use_sence::Emergency);
//QMessageBox::information(NULL, "提示", "进入应急场景!");
showTopMessage("进入应急场景!", LONGINSUCCESS);
}
else if(_queryUserData.scene == "seaRescue")
{
emit sendSenceData(use_sence::Sea_Rescue);
showTopMessage("进入海上救捞场景!", LONGINSUCCESS);
}
else if(_queryUserData.scene == "admin")
{
showTopMessage("进入注册页面!", LONGINSUCCESS);
ui->userlineEdit->setText("");
ui->passwordlineEdit->setText("");
ui->stackedWidget_2->setCurrentWidget(ui->page_register);
}
}
}
void UserLogin::on_pushButton_clicked()
{
emit loginDlgClick(click_type::HomePageClick);
}
void UserLogin::on_exitButton_clicked()
{
emit loginDlgClick(click_type::ExitLogin);
}
void UserLogin::on_pushButton_register_clicked()
{
showTopMessage("请输入管理员账号及密码!", LOGININFORMATION);
if(!checkEditFormat(ui->userlineEdit->text(),"用户名"))
return;
if(!checkEditFormat(ui->passwordlineEdit->text(),"密码"))
return;
//校验管理员账号
if(queryDataByUsername(ui->userlineEdit->text()))
{
//判断场景
if(_queryUserData.scene == "admin")
{
showTopMessage("进入注册页面!", LONGINSUCCESS);
ui->stackedWidget_2->setCurrentWidget(ui->page_register);
ui->userlineEdit->setText("");
ui->passwordlineEdit->setText("");
}
else
{
showTopMessage("请输入管理员账号及密码!", LOGINERROR);
}
}
}
void UserLogin::on_pushButton_login_clicked()
{
ui->stackedWidget_2->setCurrentWidget(ui->page_login);
}
void UserLogin::on_registerButton_clicked()
{
if(!checkEditFormat(ui->userlineEdit->text(),"用户名"))
return;
if(!checkEditFormat(ui->passwordlineEdit->text(),"密码"))
return;
//查询用户名,用户名不存在方可注册 注意 注册的时候需要查询是否是被删掉的数据
//先查询是否是数据库中已经删除的数据
if(dataBase.queryDataByUsername(ui->userlineEdit->text(),1))
{
QVariant currentSenceData = ui->senceComboBox->currentData();//获取当前下拉列表数据
userData registerUser = {ui->userlineEdit->text(),ui->passwordlineEdit->text(),currentSenceData.toString()};
if(dataBase.updateDataByUsername(registerUser, 0))
{
showTopMessage("注册成功!", LONGINSUCCESS);
return;
}
}
if(!dataBase.queryDataByUsername(ui->userlineEdit->text(),0))
{
QVariant currentSenceData = ui->senceComboBox->currentData();//获取当前下拉列表数据
userData registerUser = {ui->userlineEdit->text(),ui->passwordlineEdit->text(),currentSenceData.toString()};
if(dataBase.singleInsertData(registerUser))
{
showTopMessage("注册成功!", LONGINSUCCESS);
}
}
else
{
showTopMessage("用户名已存在,请换一个!", LOGINERROR);
}
}

@ -1,116 +0,0 @@
#ifndef USERLOGIN_H
#define USERLOGIN_H
#include <QCheckBox>
#include <QWidget>
#include "mydatabase.h"
namespace Ui {
class UserLogin;
}
class UserLogin : public QWidget
{
Q_OBJECT
public:
explicit UserLogin(QWidget *parent = nullptr);
~UserLogin();
enum use_sence : unsigned char
{
Emergency = 1, //应急 1
Sea_Rescue, //海上救捞 2
AdminUser, //管理员用户
};
enum click_type : unsigned char
{
HomePageClick = 0, //主页点击
ExitLogin, //退出登录
};
enum MyNotifyType : unsigned char
{ LOGININFORMATION = 0,
LONGINSUCCESS = 1,
LOGINERROR = 2,
LOGINWARNING = 3,
};
private slots:
void on_loginButton_clicked();
void on_pushButton_clicked();
void on_exitButton_clicked();
void on_pushButton_register_clicked();
void on_pushButton_login_clicked();
void on_registerButton_clicked();
private:
Ui::UserLogin *ui;
MyDatabase dataBase;
void initLineEdit();
void initControls();
bool checkEditFormat(const QString &edit, const QString &origins);
void showTopMessage(QString message, MyNotifyType type);
userData _queryUserData;
QCheckBox *_passwordCheckBox;
signals:
void sendSenceData(use_sence sence);
void loginDlgClick(int clickType);
public:
bool queryDataByUsername(const QString &username);
protected:
void resizeEvent(QResizeEvent *event) override;
};
const QString g_loginButtonStyle = "QPushButton {"
"border: none;" // 没有边框
"color: #CFCFCF;" // 默认字体颜色为白色
"font-size: 18px;" // 字体大小为 20
"font-weight: bold;"
"background-color: transparent;" // 背景透明
"font-family: 'STHeiti';"
"}"
// 设置按钮悬停时的样式
"QPushButton:hover {"
"color: #5289C1;" // 悬停时字体颜色变为橙色
"}"
// 设置按钮按下时的字体颜色
"QPushButton:pressed {"
"color: #4A7DB0;" // 按下时字体颜色变为绿色
"}"
// 设置按钮选中时的样式
"QPushButton:checked {"
"color: #5289C1;" // 选中时字体颜色变为绿色
"}";
const QString g_okButtonStyle = "QPushButton{"
"font-family: STHupo;"
"border-radius: 15px;"
"color: white;"
"font-weight: bold;"
"border: none;"
"background-color: #5289C1;"
"font-size: 20px;"
"}"
// 设置按钮悬停时的样式
"QPushButton:hover {"
"background-color: #4078A9;" // 悬停时的背景颜色
"}"
// 设置按钮按下或选中时的渐变背景
"QPushButton::pressed, QPushButton::checked {"
"color: #FFFFFF;" // 字体颜色为白色
"background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, "
"stop:0 #273c75, stop:1 #487eb0);" // 渐变背景
"}";
#endif // USERLOGIN_H

@ -1,808 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UserLogin</class>
<widget class="QWidget" name="UserLogin">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1288</width>
<height>869</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1">
<widget class="QWidget" name="widget_l" native="true">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widget_2" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>220</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="verticalSpacing">
<number>0</number>
</property>
<item row="1" column="0">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QLabel" name="loginlabel">
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
<width>0</width>
<height>39</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>HTFP-PayLoad</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignHCenter|Qt::AlignmentFlag::AlignTop</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_3" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>28</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="userlineEdit">
<property name="minimumSize">
<size>
<width>400</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>480</width>
<height>50</height>
</size>
</property>
<property name="placeholderText">
<string>用户名</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>30</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="passwordlineEdit">
<property name="minimumSize">
<size>
<width>400</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>480</width>
<height>50</height>
</size>
</property>
<property name="echoMode">
<enum>QLineEdit::EchoMode::Password</enum>
</property>
<property name="placeholderText">
<string>密码</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>30</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget_2">
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page_login">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="loginButton">
<property name="minimumSize">
<size>
<width>200</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>480</width>
<height>50</height>
</size>
</property>
<property name="text">
<string>登录</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_14">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>30</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="exitButton">
<property name="minimumSize">
<size>
<width>200</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>480</width>
<height>50</height>
</size>
</property>
<property name="text">
<string>退出登录</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_15">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_register">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_18">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="senceComboBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>50</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_19">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>30</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_16">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="registerButton">
<property name="minimumSize">
<size>
<width>200</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>480</width>
<height>50</height>
</size>
</property>
<property name="text">
<string>注册</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_17">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>11</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_4" native="true">
<layout class="QVBoxLayout" name="verticalLayout_5"/>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>130</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="3">
<widget class="QWidget" name="widget" native="true">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="8">
<spacer name="horizontalSpacer_13">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButton">
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>主页</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QPushButton" name="pushButton_login">
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>登录</string>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="7">
<widget class="QPushButton" name="pushButton_register">
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>注册</string>
</property>
</widget>
</item>
<item row="0" column="4">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="6">
<widget class="QLabel" name="label_2">
<property name="text">
<string>|</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

@ -24,11 +24,6 @@ void AVPacketQueueManager::enqueuePushPacket(AVPacket *pkt) {
if (clonedPacket) m_pushQueue.enqueue(clonedPacket);
}
void AVPacketQueueManager::enqueueSeekTime(int64_t time) {
QMutexLocker locker(&m_seekMutex);
m_seekQueue.enqueue(time);
}
AVPacket *AVPacketQueueManager::dequeueDecodePacket() {
QMutexLocker locker(&m_decodeMutex);
if (!m_decodeQueue.isEmpty()) {
@ -56,11 +51,6 @@ AVPacket *AVPacketQueueManager::dequeuePushPacket() {
return nullptr;
}
int64_t AVPacketQueueManager::dequeueSeekTime() {
QMutexLocker locker(&m_seekMutex);
return m_seekQueue.dequeue();
}
void AVPacketQueueManager::clearDecodeQueue() {
QMutexLocker locker(&m_decodeMutex);
m_decodeQueue.clear();
@ -76,22 +66,7 @@ void AVPacketQueueManager::clearPushQueue() {
m_pushQueue.clear();
}
void AVPacketQueueManager::clearSeekQueue() {
QMutexLocker locker(&m_seekMutex);
m_seekQueue.clear();
}
bool AVPacketQueueManager::isEmptyDecodeQueue() {
QMutexLocker locker(&m_decodeMutex);
return m_decodeQueue.isEmpty();
}
bool AVPacketQueueManager::isEmptySaveQueue() {
QMutexLocker locker(&m_saveMutex);
return m_saveQueue.isEmpty();
}
bool AVPacketQueueManager::isEmptySeekQueue() {
QMutexLocker locker(&m_seekMutex);
return m_seekQueue.isEmpty();
}

@ -13,37 +13,26 @@ public:
void enqueueDecodePacket(AVPacket* pkt);
void enqueueSavePacket(AVPacket* pkt);
void enqueuePushPacket(AVPacket* pkt);
void enqueueSeekTime(int64_t time);
AVPacket* dequeueDecodePacket();
AVPacket* dequeueSavePacket();
AVPacket* dequeuePushPacket();
int64_t dequeueSeekTime();
void clearDecodeQueue();
void clearSaveQueue();
void clearPushQueue();
void clearSeekQueue();
bool isEmptyDecodeQueue();
// bool isEmptyDecodeQueue();
bool isEmptySaveQueue();
bool isEmptySeekQueue();
public:
std::atomic<bool> m_isSeeking{false}; // 是否正在跳转
std::atomic<bool> m_isReadEnd{false};
std::atomic<bool> m_isDecodeEnd{false};
private:
int QUEUECAPACITY = 100;
QQueue<AVPacket*> m_decodeQueue;
QQueue<AVPacket*> m_saveQueue;
QQueue<AVPacket*> m_pushQueue;
QQueue<int64_t> m_seekQueue; // 存储目标时间戳
QMutex m_decodeMutex; // 共享的互斥锁
QMutex m_saveMutex; // 共享的互斥锁
QMutex m_pushMutex; // 共享的互斥锁
QMutex m_seekMutex; // 共享的互斥锁
};
#endif // AVPACKETQUEUEMANAGER_H

@ -1,36 +1,18 @@
#include "decodestream.h"
DecodeStream::DecodeStream(QObject *parent) : QObject{parent}, m_playSpeed{1} {}
DecodeStream::DecodeStream(QObject *parent) : QObject{parent} {}
bool DecodeStream::init(AVPacketQueueManager *queueManager,
AVFormatContext *formatContext, int videoIndex) {
// QMutexLocker locker(&m_mutex);
// m_packetsQueue = queue;
m_queueManager = queueManager;
m_formatContext = formatContext;
m_videoIndex = videoIndex;
m_outStreamTimeBase = formatContext->streams[videoIndex]->time_base;
m_startTime = formatContext->start_time;
m_duration = formatContext->duration;
if (strncmp(formatContext->url, "rtsp://", 7) == 0 ||
strncmp(formatContext->url, "rtmp://", 7) == 0 ||
strncmp(formatContext->url, "http://", 7) == 0) {
m_isFile = false;
} else {
m_isFile = true;
}
m_fps = av_q2d(formatContext->streams[videoIndex]->avg_frame_rate);
if (m_fps <= 0) {
m_fps = 30.0; // 默认帧率
}
return initDecoder(formatContext, videoIndex);
}
bool DecodeStream::init(AVPacketQueueManager *queueManager) {
m_queueManager = queueManager;
return initUDPDecoder();
}
// 视频解码线程任务
void DecodeStream::startDecode() {
qDebug() << "deocdeStreamThreadID:" << QThread::currentThreadId();
@ -39,99 +21,15 @@ void DecodeStream::startDecode() {
free();
return;
}
bool isPlayEnd = false;
// m_firstFramePTS = AV_NOPTS_VALUE;
// m_startDecodeTime = AV_NOPTS_VALUE;
int64_t lastPts = AV_NOPTS_VALUE;
auto lastDisplayTime =
std::chrono::high_resolution_clock::now(); // 记录上一帧的显示时间
m_queueManager->m_isDecodeEnd = false;
double startTime = m_startTime / static_cast<double>(AV_TIME_BASE);
int64_t duration = static_cast<int64_t>(m_duration / AV_TIME_BASE);
while (m_start) {
try {
// 检查跳转状态
if (m_queueManager->m_isSeeking) {
m_queueManager->clearDecodeQueue();
// 清空解码器缓冲区
avcodec_flush_buffers(m_codecContext);
continue;
}
AVPacket *inputPacket = m_queueManager->dequeueDecodePacket();
if (inputPacket) {
AVFrame *frame = decodePacket(inputPacket);
if (frame) {
// 播放本地视频
if (m_isFile) {
// 计算帧间隔
if (lastPts != AV_NOPTS_VALUE &&
frame->pts != AV_NOPTS_VALUE) {
int64_t ptsDiff = frame->pts - lastPts;
if (ptsDiff < 0) {
// 如果 ptsDiff 为负数,说明 pts
// 不连续,跳过该帧
continue;
}
double frameDuration = av_q2d(m_outStreamTimeBase) *
ptsDiff; // 转换为秒
// 根据播放速度调整
double adjustedDuration =
frameDuration / m_playSpeed;
// 计算实际延迟
auto now =
std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<
std::chrono::milliseconds>(
now - lastDisplayTime)
.count() /
1000.0;
double sleepTime = adjustedDuration - elapsed;
if (sleepTime > 0) {
std::this_thread::sleep_for(
std::chrono::microseconds(
static_cast<int64_t>(
sleepTime *
1000000))); // 微秒级延迟
}
// qDebug() << "delay:" << sleepTime * 1000;
}
lastPts = frame->pts;
lastDisplayTime = std::chrono::high_resolution_clock::
now(); // 更新上一帧的显示时间
// qDebug() << frame->best_effort_timestamp;
// int64_t aaa = frame->best_effort_timestamp;
// 更新当前播放时间进度
double currentTime = frame->best_effort_timestamp *
av_q2d(m_outStreamTimeBase);
// qDebug() << currentTime - startTime;
int64_t currentTime1 =
static_cast<int64_t>(currentTime - startTime);
emit updateVideoCurrentTime(currentTime1, duration);
if (m_queueManager->isEmptyDecodeQueue() &&
m_queueManager->m_isReadEnd) {
isPlayEnd = true;
}
}
emit repaintSignal(frame);
}
av_packet_unref(inputPacket);
av_packet_free(&inputPacket);
inputPacket = nullptr;
if (isPlayEnd && m_isFile && !m_queueManager->m_isSeeking) {
m_queueManager->m_isDecodeEnd = true;
break;
}
} else {
// QThread::usleep(1000);
// av_usleep(1000);
@ -143,28 +41,16 @@ void DecodeStream::startDecode() {
free();
qDebug() << "Decoding Thread End!";
emit decodeEndSignal();
emit sendErrorMessageSignal("视频解码结束!", 1);
}
void DecodeStream::changePlaySpeedSlot(double speed) {
m_playSpeed = speed;
qDebug() << "receive changePlaySpeedSlot:" << m_playSpeed;
emit sendErrorMessageSignal("视频解码结束!",
NotificationType::NOTIFICATION_SUCCESS);
}
void DecodeStream::close() {
// QMutexLocker locker(&m_mutex);
m_start = false;
qDebug() << "decode Stream close!" << m_start;
}
AVCodecContext *DecodeStream::getCodecContext() {
return m_codecContext;
}
AVCodecParserContext *DecodeStream::getParserContext() {
return m_parser;
}
bool DecodeStream::initObject() {
// 分配AVFrame并将其字段设置为默认值。
m_frame = av_frame_alloc();
@ -232,53 +118,6 @@ bool DecodeStream::initDecoder(AVFormatContext *inputFormatContext,
return true;
}
bool DecodeStream::initUDPDecoder() {
// 通过解码器ID获取视频解码器新版本返回值必须使用const
const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
printf("Cannot find valid decode codec.\n");
return false;
}
m_parser = av_parser_init(codec->id);
if (!m_parser) {
fprintf(stderr, "Parser not found\n");
return false;
}
// 分配AVCodecContext并将其字段设置为默认值。
m_codecContext = avcodec_alloc_context3(codec);
if (!m_codecContext) {
#if PRINT_LOG
qWarning() << "创建视频解码器上下文失败!";
#endif
free();
return false;
}
// AVCodecParserContext *avcodecParserContext =
// av_parser_init(AV_CODEC_ID_H264);
// m_codecContext->lowres = codec->max_lowres;
// m_codecContext->flags2 |=
// AV_CODEC_FLAG2_FAST; // 允许不符合规范的加速技巧。
// m_codecContext->thread_count = 4; // 使用8线程解码
// 设置解码器容错选项,忽略丢失的帧或参数
// m_codecContext->err_recognition = AV_EF_IGNORE_ERR;
// m_codecContext->flags |= AV_CODEC_FLAG2_CHUNKS;
// m_codecContext->pix_fmt = AV_PIX_FMT_YUV420P;
// 初始化解码器上下文如果之前avcodec_alloc_context3传入了解码器这里设置NULL就可以
int ret = avcodec_open2(m_codecContext, codec, nullptr);
if (ret < 0) {
showError(ret);
free();
return false;
}
return true;
}
AVFrame *DecodeStream::decodePacket(AVPacket *inputPacket) {
if (!isValidAVPacket(inputPacket)) return nullptr;
// 将读取到的原始数据包传入解码器
@ -365,27 +204,24 @@ bool DecodeStream::isValidAVFrame(AVFrame *frame) {
bool DecodeStream::isValidAVPacket(AVPacket *pkt) {
if (pkt == nullptr) {
qDebug() << "DecodeStream: Invalid AVPacket: packet pointer is null.";
qDebug() << "Invalid AVPacket: packet pointer is null.";
return false;
}
// 检查数据指针和大小
if (pkt->data == nullptr || pkt->size <= 0) {
qDebug() << "DecodeStream: Invalid AVPacket: data is null or size is "
"non-positive.\n";
qDebug() << "Invalid AVPacket: data is null or size is non-positive.\n";
return false;
}
// 检查时间戳
if (pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE) {
qDebug() << "DecodeStream: Invalid AVPacket: pts or dts is "
"AV_NOPTS_VALUE.\n";
return false;
}
// if (pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE) {
// qDebug() << "Invalid AVPacket: pts or dts is AV_NOPTS_VALUE.\n";
// return false;
// }
// 检查流索引(如果是多流)
if (pkt->stream_index < 0) {
qDebug()
<< "DecodeStream: Invalid AVPacket: stream_index is invalid.\n";
qDebug() << "Invalid AVPacket: stream_index is invalid.\n";
return false;
}

@ -7,7 +7,6 @@
#include <QObject>
#include <QQueue>
#include <QThread>
#include <chrono>
#include "avpacketqueuemanager.h"
#include "ffmpeginclude.h"
@ -18,25 +17,19 @@ public:
DecodeStream(QObject *parent = nullptr);
bool init(AVPacketQueueManager *queueManager,
AVFormatContext *formatContext, int videoIndex);
bool init(AVPacketQueueManager *queueManager);
void close();
AVCodecContext *getCodecContext();
AVCodecParserContext *getParserContext();
public slots:
void startDecode();
void changePlaySpeedSlot(double speed);
signals:
void repaintSignal(AVFrame *frame); // 重绘
void startDecodeSignal();
void sendErrorMessageSignal(QString message, int type);
void updateVideoCurrentTime(int currentTime, int duration);
void decodeEndSignal();
private:
bool initObject(); // 初始化对象
bool initDecoder(AVFormatContext *inputFormatContext,
int videoIndex); // 初始化解码器
bool initUDPDecoder();
AVFrame *decodePacket(AVPacket *inputPacket);
void free(); // 释放
@ -52,17 +45,7 @@ private:
AVFrame *m_frame = nullptr; // 解码后的视频帧
AVFrame *m_frameTemp = nullptr;
AVPacketQueueManager *m_queueManager = nullptr;
AVRational m_outStreamTimeBase;
int64_t m_startTime;
int64_t m_duration;
bool m_isFile = false;
int m_fps;
std::atomic<double> m_playSpeed;
int64_t m_firstFramePTS;
int64_t m_startDecodeTime;
AVCodecParserContext *m_parser = nullptr;
QMutex m_mutex;
};
#endif // DECODESTREAM_H

@ -22,7 +22,7 @@ extern "C" {
#include <QElapsedTimer>
#include <QEventLoop>
// #include "global.h"
#include "global.h"
#define PRINT_LOG 1
#define ERROR_LEN 1024 // 异常信息数组长度

@ -1,5 +1,5 @@
<RCC>
<qresource prefix="/">
<qresource prefix="/gl">
<file>fragment.fsh</file>
<file>vertex.vsh</file>
</qresource>

@ -29,12 +29,8 @@ bool PushStream::openNetworkStream(AVFormatContext *inputFormatCtx) {
// 初始化网络输出流
// QString m_pushStreamIP = "rtsp://182.92.130.23/app/stream999";
QString format_name = "flv";
if (m_pushStreamIP.left(3) == "udp" || m_pushStreamIP.left(3) == "UDP")
format_name = "mpegts";
int ret = avformat_alloc_output_context2(
&m_outputFormatCtx, NULL, format_name.toStdString().data(),
m_pushStreamIP.toUtf8().constData());
&m_outputFormatCtx, NULL, "flv", m_pushStreamIP.toUtf8().constData());
if (ret < 0) {
showError(ret);
free();
@ -71,7 +67,7 @@ bool PushStream::openNetworkStream(AVFormatContext *inputFormatCtx) {
m_inputTimeBase = m_istream->time_base;
m_inputFrameRate = m_istream->r_frame_rate;
m_outputTimeBase = m_istream->time_base;
m_outputTimeBase = m_ostream->time_base;
// 打开输出文件
if (!(m_outputFormatCtx->flags & AVFMT_NOFILE)) {
@ -157,7 +153,6 @@ int PushStream::reconnect(int ret) {
emit sendErrorMessageSignal("重连失败,推流停止!", 2);
return -1;
}
return 0;
}
void PushStream::pushStream(int64_t startTime) {
@ -212,14 +207,14 @@ void PushStream::pushStream(int64_t startTime) {
av_usleep(delay);
// sleepMsec(40);
} else {
if (delay < -80000) {
if (delay < -50000) {
// 滞后50ms以上丢弃非重要帧
if (!(inputPacket->flags & AV_PKT_FLAG_KEY)) {
av_packet_unref(inputPacket);
continue;
}
// 调整基准时间,减少滞后
m_startTime += 80000;
m_startTime += 50000;
}
}
// 计算延时后,重新指定时间戳
@ -254,14 +249,15 @@ void PushStream::pushStream(int64_t startTime) {
av_packet_unref(inputPacket);
av_packet_free(&inputPacket);
} else {
av_usleep(1000);
QThread::usleep(1000);
}
}
if (m_bwriteHeader) av_write_trailer(m_outputFormatCtx);
free();
qDebug() << "Push Stream End!";
emit sendErrorMessageSignal("推流结束!", 1);
emit sendErrorMessageSignal("推流结束!",
NotificationType::NOTIFICATION_SUCCESS);
}
void PushStream::free() {

@ -7,16 +7,7 @@ ReadStream::ReadStream(QObject *parent) : QObject{parent} {
initFFmpeg();
}
ReadStream::~ReadStream() {
if (udpSocket) {
udpSocket->abort();
udpSocket->deleteLater();
}
if (m_saveFile.isOpen()) {
m_saveFile.close();
}
}
ReadStream::~ReadStream() {}
bool ReadStream::openFile(const QString &url) {
if (url.isNull()) return false;
@ -28,7 +19,6 @@ bool ReadStream::openFile(const QString &url) {
// 设置超时断开连接时间,单位微秒//listen_timeout
// av_dict_set(&avdic, "listen_timeout", "200000", 0);
av_dict_set(&dict, "stimeout", "5000000", 0); // 设置超时5秒
if (url.left(4) != "rtmp")
av_dict_set(&dict, "timeout", "5000000", 0); // 设置5秒超时
av_dict_set(&dict, "max_delay", "300000", 0); // 设置最大时延300ms
av_dict_set(&dict, "tune", "zerolatency", 0); // 实时编码
@ -41,10 +31,6 @@ bool ReadStream::openFile(const QString &url) {
// av_dict_set(&dict, "reconnect_at_eof", "1", 0);
av_dict_set(&dict, "reconnect_delay_max", "5",
0); // 最大重连延时 5 秒
av_dict_set(&dict, "probesize", "10000000", 0); // 10 MB
av_dict_set(&dict, "analyzeduration", "20000000", 0); // 20 秒
// 设置 UDP 缓冲区大小
av_dict_set(&dict, "fifo_size", "1000000", 0); // 设置缓冲区大小为1MB
// 设置非阻塞标志
// av_dict_set(&dict, "flags", "+nonblock", 0);
// 打开输入流之前,设置非阻塞模式
@ -66,7 +52,6 @@ bool ReadStream::openFile(const QString &url) {
free();
return false;
}
// m_formatContext->flags |= AVFMT_FLAG_GENPTS; // 设置标志生成时间戳
// 读取媒体文件的数据包以获取流信息。
ret = avformat_find_stream_info(m_formatContext, nullptr);
if (ret < 0) {
@ -84,18 +69,7 @@ bool ReadStream::openFile(const QString &url) {
return false;
}
// 获取视频时长
if (m_formatContext->duration != AV_NOPTS_VALUE) {
m_videoDuration = m_formatContext->duration / (double)AV_TIME_BASE;
qDebug() << m_videoDuration;
} else {
m_videoDuration = -1;
}
m_startTime = m_formatContext->start_time;
m_inStreamTimeBase = m_formatContext->streams[m_videoIndex]->time_base;
// m_startTime = -1;
m_startTime = -1;
m_pullURL = url;
return initObject();
}
@ -115,32 +89,12 @@ bool ReadStream::setStreamDecoder(DecodeStream *decodeStreamer) {
return false;
}
bool ReadStream::setUDPStreamDecoder(DecodeStream *decodeStreamer) {
if (decodeStreamer) {
// QMutexLocker locker(&m_mutex);
m_streamDecoder = decodeStreamer;
m_queueManager.clearDecodeQueue();
m_decodeStreamFlag = m_streamDecoder->init(&m_queueManager);
// codec_ctx = m_streamDecoder->getCodecContext();
// parser = m_streamDecoder->getParserContext();
if (m_decodeStreamFlag) emit decodeStreamer->startDecodeSignal();
return m_decodeStreamFlag;
} else {
m_decodeStreamFlag = false;
}
return false;
}
bool ReadStream::setStreamSaver(SaveStream *streamSaver, bool isUDP) {
bool ReadStream::setStreamSaver(SaveStream *streamSaver) {
if (streamSaver) {
m_streamSaver = streamSaver;
m_queueManager.clearSaveQueue();
if (isUDP) {
m_saveStreamFlag = m_streamSaver->initUDP(&m_queueManager);
} else {
m_saveStreamFlag = m_streamSaver->init(
m_formatContext, &m_queueManager, m_videoIndex);
}
m_saveStreamFlag =
m_streamSaver->init(m_formatContext, &m_queueManager, m_videoIndex);
return m_saveStreamFlag;
} else {
m_saveStreamFlag = false;
@ -165,7 +119,6 @@ void ReadStream::close() {
// QMutexLocker locker(&m_mutex);
m_start = false;
m_end = true;
emit closeUDPConnectionSignal();
// if (m_streamDecoder) {
// m_streamDecoder->close();
// }
@ -177,72 +130,13 @@ void ReadStream::close() {
// }
}
void ReadStream::setUDPParms(QString ip, int port) {
m_UDPIP = ip;
m_UDPPort = port;
}
bool ReadStream::initSocket(QString ip, int port) {
qDebug() << "initSocket:" << QThread::currentThreadId();
if (udpSocket == nullptr) {
udpSocket = new QUdpSocket();
}
if (ip.isEmpty()) {
return udpSocket->bind(QHostAddress::Any, port);
} else {
if (!isMulticastAddress(ip)) { // 单播
return udpSocket->bind(QHostAddress(ip), port);
} else { // 组播
if (udpSocket->bind(QHostAddress::AnyIPv4, port,
QUdpSocket::ShareAddress)) {
return udpSocket->joinMulticastGroup(QHostAddress(ip));
}
}
}
}
bool ReadStream::initSavedRawFile(QString fileDir, QString uavName) {
QDir dir;
if (!dir.exists(fileDir)) {
dir.mkdir(fileDir);
}
QString strName = QString("%1.dat").arg(
QDateTime::currentDateTime().toString("yyyyMMddHHmmss"));
QString filename = fileDir + "/" + uavName + "_" + strName;
m_saveFile.setFileName(filename);
bool bOopen = m_saveFile.open(QIODevice::WriteOnly | QIODevice::Append);
return bOopen;
}
double ReadStream::getVideoDuration() {
return m_videoDuration;
}
void ReadStream::seekToVideo(int64_t targetTimestamp) {
qDebug() << "Receive targetTimeStamp!**************";
if (m_formatContext) {
// double starttime = m_startTime / static_cast<double>(AV_TIME_BASE);
int64_t aaa =
targetTimestamp * static_cast<double>(AV_TIME_BASE) + m_startTime;
int64_t bbb = av_rescale_q(aaa, AV_TIME_BASE_Q, m_inStreamTimeBase);
// double tmp = (targetTimestamp + starttime) /
// av_q2d(m_inStreamTimeBase);
qDebug() << "tmp:" << bbb;
m_queueManager.enqueueSeekTime(bbb);
};
}
void ReadStream::startPullStream() {
// 如果没有打开则返回
if (!m_formatContext) {
return;
}
qDebug() << "readStreamThreadID:" << QThread::currentThreadId();
if (m_streamSaver) {
emit m_streamSaver->startSaveStreamSignal();
}
m_start = true;
int readRet;
// 读取数据包
@ -275,9 +169,8 @@ void ReadStream::startPullStream() {
break;
}
}
if (m_inputPacket->stream_index == m_videoIndex) {
if (isValidAVPacket(m_inputPacket)) {
if (m_inputPacket->stream_index == m_videoIndex) {
if (m_decodeStreamFlag) {
m_queueManager.enqueueDecodePacket(m_inputPacket);
}
@ -299,133 +192,6 @@ void ReadStream::startPullStream() {
qDebug() << "read Stream End!";
}
void ReadStream::startReadFileStream() {
// 如果没有打开则返回
if (!m_formatContext) {
return;
}
qDebug() << "readStreamThreadID:" << QThread::currentThreadId();
m_start = true;
int readRet;
// 读取数据包
while (m_start) {
// 检查跳转请求
if (!m_queueManager.isEmptySeekQueue()) {
int64_t targetTimestamp = m_queueManager.dequeueSeekTime();
// 设置跳转状态
m_queueManager.m_isSeeking = true;
// 尝试跳转
// ;
// av_seek_frame(m_formatContext, -1, targetTimestamp,
// AVSEEK_FLAG_ANY);
if (avformat_seek_file(m_formatContext, m_videoIndex, INT64_MIN,
targetTimestamp, INT64_MAX,
AVSEEK_FLAG_ANY) >= 0) {
m_queueManager.clearDecodeQueue();
m_queueManager.m_isReadEnd = false;
} else {
}
// 恢复读取
m_queueManager.m_isSeeking = false;
}
readRet = av_read_frame(m_formatContext, m_inputPacket);
if (readRet == AVERROR(EAGAIN)) { // 暂时没有数据流
qDebug() << "No Stream Data";
av_packet_unref(m_inputPacket);
av_usleep(30000); // 等待 30 毫秒
continue;
} else if (readRet == AVERROR_EOF) { // 流文件结束
av_packet_unref(m_inputPacket);
m_queueManager.m_isReadEnd = true;
if (m_queueManager.m_isDecodeEnd) {
qDebug() << "Stream End";
close();
break;
} else {
av_usleep(2000);
continue;
}
} else if (readRet < 0) { // 发生错误
qDebug() << "Stream Error" << readRet;
if (m_streamDecoder) {
m_streamDecoder->close();
}
if (m_streamPusher) {
m_streamPusher->close();
}
m_queueManager.m_isReadEnd = true;
break;
}
if (m_inputPacket->stream_index == m_videoIndex &&
readRet != AVERROR_EOF) {
if (isValidAVPacket(m_inputPacket)) {
// if (test) {
// qDebug() << m_inputPacket->pts;
// int i = 0;
// }
if (m_decodeStreamFlag) {
m_queueManager.enqueueDecodePacket(m_inputPacket);
}
if (m_pushStreamFlag) {
m_queueManager.enqueuePushPacket(m_inputPacket);
}
}
}
av_packet_unref(m_inputPacket);
// QThread::usleep(2000); // 等待 2 毫秒
av_usleep(1000);
}
clear();
free();
qDebug() << "read Stream End!";
}
void ReadStream::startPullUDPStream() {
initObject();
// parser = av_parser_init(AV_CODEC_ID_H264);
// codec_ctx = avcodec_alloc_context3(NULL);
if (!initSocket(m_UDPIP, m_UDPPort)) {
emit sendErrorMessageSignal("UDP绑定失败!", 2);
return;
}
initSavedRawFile();
const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
codec_ctx = avcodec_alloc_context3(codec);
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
codec_ctx->width = 1920;
codec_ctx->height = 1080;
avcodec_open2(codec_ctx, codec, NULL);
parser = av_parser_init(AV_CODEC_ID_H264);
connect(udpSocket, &QUdpSocket::readyRead, this,
&ReadStream::udpDataReceivedSlot);
if (m_streamSaver) {
emit m_streamSaver->startSaveStreamSignal();
}
}
void ReadStream::closeUDPConnectionSLot() {
qDebug() << "closeUDPConnectionSLot";
if (udpSocket) {
udpSocket->abort();
delete udpSocket;
udpSocket = nullptr;
}
if (m_saveFile.isOpen()) {
m_saveFile.close();
}
}
void ReadStream::initFFmpeg() {
avformat_network_init();
// m_formatContext = avformat_alloc_context();
@ -522,15 +288,10 @@ bool ReadStream::isValidAVPacket(AVPacket *pkt) {
}
// 检查时间戳
if (pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE) {
qDebug() << "Invalid AVPacket 0: pts or dts is AV_NOPTS_VALUE.\n";
return false;
}
if (pkt->pts < 0 || pkt->dts < 0) {
qDebug() << "Invalid AVPacket 0: pts or dts < 0.\n";
return false;
}
// if (pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE) {
// qDebug() << "Invalid AVPacket 0: pts or dts is AV_NOPTS_VALUE.\n";
// return false;
// }
// 检查流索引(如果是多流)
if (pkt->stream_index < 0) {
@ -546,108 +307,3 @@ bool ReadStream::isValidAVPacket(AVPacket *pkt) {
return true;
}
bool ReadStream::isMulticastAddress(const QString &ip) {
QHostAddress address;
if (!address.setAddress(ip)) {
return false; // 如果不是有效的IP地址直接返回false
}
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
quint32 ip4 = address.toIPv4Address();
return ip4 >= QHostAddress("224.0.0.0").toIPv4Address() &&
ip4 <= QHostAddress("239.255.255.255").toIPv4Address();
} else if (address.protocol() == QAbstractSocket::IPv6Protocol) {
QString ipv6 = address.toString();
return ipv6.startsWith("ff",
Qt::CaseInsensitive); // IPv6组播地址以"ff"开头
}
return false;
}
void ReadStream::udpDataReceivedSlot() {
// qDebug() << "udpreceive:" << QThread::currentThreadId();
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
// 保存原始数据
if (m_saveFile.isOpen()) {
m_saveFile.write(datagram.toHex());
}
if (static_cast<uint8_t>(datagram.at(0)) == 0xEB &&
static_cast<uint8_t>(datagram[1]) == 0x90 &&
static_cast<uint8_t>(datagram[4]) == 0xD5) {
// QByteArray tmp = datagram.sliced(2, 4);
// uint16_t crc =
// getCRC16Sum(reinterpret_cast<uint8_t*>(tmp.data()),
// tmp.size());
// uint16_t rawcrc = (static_cast<uint8_t>(datagram.at(7)) << 8) |
// static_cast<uint8_t>(datagram.at(6));
// if (crc != rawcrc) continue;
// int videoDataLen = static_cast<int>(datagram.at(5) & 0xFF);
int videoDataLen = 248;
QByteArray videoData = datagram.sliced(8, videoDataLen);
uint8_t *inBuf = (uint8_t *)(videoData.data());
// int videoDataLen = datagram.size();
// QByteArray videoData = datagram.data();
// uint8_t *inBuf = (uint8_t *)(videoData.data());
// if (videoDataLen > 0) {
// AVPacket packet;
// av_init_packet(&packet);
// packet.data = (uint8_t *)inBuf;
// packet.size = videoDataLen;
// if (m_decodeStreamFlag) {
// m_queueManager.enqueueDecodePacket(&packet);
// }
// av_packet_unref(&packet);
// }
if (!m_decodeStreamFlag) continue;
int outbuf_size = 0; // 输出缓冲区的大小
uint8_t *outbuf = nullptr; // 输出缓冲区
int len = 0;
while (videoDataLen) {
len = av_parser_parse2(parser, codec_ctx, &outbuf, &outbuf_size,
inBuf, videoDataLen, AV_NOPTS_VALUE,
AV_NOPTS_VALUE, 0);
// if (ret < 0) continue;
inBuf += len;
videoDataLen -= len;
if (outbuf_size) {
AVPacket packet;
av_init_packet(&packet);
packet.data = (uint8_t *)outbuf;
packet.size = outbuf_size;
// int ret = avcodec_send_packet(codec_ctx, &packet);
// if (ret >= 0) qDebug() << "decode success!";
// qDebug() << "packet!";
if (m_decodeStreamFlag) {
m_queueManager.enqueueDecodePacket(&packet);
}
if (m_saveStreamFlag) {
m_queueManager.enqueueSavePacket(&packet);
}
if (m_pushStreamFlag) {
m_queueManager.enqueuePushPacket(&packet);
}
av_packet_unref(&packet);
// av_free(outbuf);
}
// qDebug() << "one packet end";
}
}
}
// qDebug() << "read UDP Stream End!";
}

@ -2,13 +2,11 @@
#define READSTREAM_H
#include <QDebug>
#include <QFile>
#include <QMutex>
#include <QObject>
#include <QQueue>
#include <QSize>
#include <QThread>
#include <QUdpSocket>
#include "avpacketqueuemanager.h"
#include "decodestream.h"
@ -23,30 +21,16 @@ public:
~ReadStream();
bool openFile(const QString &url);
bool setStreamDecoder(DecodeStream *decodeStreamer);
bool setUDPStreamDecoder(DecodeStream *decodeStreamer);
bool setStreamSaver(SaveStream *streamSaver, bool isUDP = false);
bool setStreamSaver(SaveStream *streamSaver);
bool setStreamPusher(PushStream *streamPusher); // 开启推流
void close();
void setUDPParms(QString ip, int port);
bool initSocket(QString ip, int port);
bool initSavedRawFile(QString fileDir = "./dat", QString uavName = "fp98");
double getVideoDuration();
void seekToVideo(int64_t targetTimestamp);
public slots:
void startPullStream();
void startReadFileStream();
void startPullUDPStream();
void closeUDPConnectionSLot();
signals:
// void startDecodeSignal();
void startPullStreamSignal();
void startPullUDPStreamSignal();
void sendErrorMessageSignal(QString message, int type);
void closeUDPConnectionSignal();
private:
void initFFmpeg(); // 初始化ffmpeg库整个程序中只需加载一次
@ -65,12 +49,7 @@ private:
bool isValidAVPacket(AVPacket *pkt);
bool isMulticastAddress(const QString &ip);
void udpDataReceivedSlot();
private:
double m_videoDuration;
bool m_pushStreamFlag = false; // 推流开始标识
bool m_decodeStreamFlag = false;
bool m_saveStreamFlag = false;
@ -79,15 +58,19 @@ private:
qreal m_frameRate = 0; // 视频帧率
QSize m_size; // 视频分辨率大小
uchar *m_buffer = nullptr;
std::atomic<bool> m_start{true};
std::atomic<bool> m_end{false};
// int64_t m_startTime;
bool m_start = true;
bool m_end = false;
int64_t m_startTime;
AVFormatContext *m_formatContext = nullptr; // 解封装上下文
AVCodecContext *m_codecContext = nullptr; // 解码器上下文
// SwsContext* m_swsContext = nullptr; // 图像转换上下文
AVPacket *m_inputPacket = nullptr; // 数据包
int m_videoIndex = 0; // 视频流索引
int QUEUECAPACITY = 100;
// QQueue<AVPacket *> m_packetsQueue;
// QQueue<AVPacket *> m_saverQueue;
// QQueue<AVPacket *> m_pusherQueue;
DecodeStream *m_streamDecoder = nullptr;
SaveStream *m_streamSaver = nullptr;
@ -95,19 +78,6 @@ private:
// QMutex m_mutex;
AVPacketQueueManager m_queueManager;
AVRational m_inStreamTimeBase;
int64_t m_startTime;
bool test = false;
private:
QFile m_saveFile;
QUdpSocket *udpSocket = nullptr;
QString m_UDPIP;
int m_UDPPort;
AVCodecParserContext *parser = nullptr;
AVCodecContext *codec_ctx = nullptr;
};
#endif // READSTREAM_H

@ -16,15 +16,6 @@ bool SaveStream::init(AVFormatContext *formatContext,
return m_start;
}
bool SaveStream::initUDP(AVPacketQueueManager *queueManager) {
m_queueManager = queueManager;
m_start = openFile(true);
if (!m_start) {
free();
}
return m_start;
}
void SaveStream::setSaveFileDirPath(QString fileDirPath) {
m_outputDirPath = fileDirPath;
}
@ -39,163 +30,41 @@ void SaveStream::startSaveStream() {
if (!m_start) {
return;
}
int frameIndex = 0;
int64_t dts = 0;
int64_t dts_last = 0;
int64_t first_pts = 0;
int64_t last_pts = 0;
while (m_start || !m_queueManager->isEmptySaveQueue()) {
if (m_queueManager->isEmptySaveQueue()) {
QThread::usleep(1000);
continue;
}
AVPacket *inputPacket = m_queueManager->dequeueSavePacket();
if (isValidAVPacket(inputPacket)) {
AVStream *in_stream =
m_inputFormatContext->streams[inputPacket->stream_index];
AVStream *out_stream = m_formatContextSave->streams[0];
if (inputPacket->pts == AV_NOPTS_VALUE) {
// 两帧之间的时长us
int interval =
(double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate);
inputPacket->pts =
(double)(frameIndex * interval) /
(double)(av_q2d(in_stream->time_base) * AV_TIME_BASE);
inputPacket->dts = inputPacket->pts;
// 两帧之间的间隔时间
inputPacket->duration =
(double)interval /
(double)(av_q2d(in_stream->time_base) * AV_TIME_BASE);
}
av_packet_rescale_ts(inputPacket, in_stream->time_base,
out_stream->time_base);
// 由于保存的m_formatContextSave只创建了一个视频流而读取到的图像的流索引不一定为0可能会出现错误【Invalid
// packet stream index: 1】
// 所以这里需要将stream_index指定为和m_formatContextSave中视频流索引相同因为就一个流所以直接设置为0
inputPacket->stream_index = 0;
inputPacket->pos = -1;
dts = inputPacket->dts;
// if (dts < dts_last) {
// av_packet_unref(inputPacket);
// continue;
// }
// dts_last = dts;
if (first_pts == 0) first_pts = inputPacket->pts;
last_pts = inputPacket->pts;
int ret = av_interleaved_write_frame(
m_formatContextSave,
inputPacket); // 将数据包写入输出媒体文件
if (ret < 0) {
qDebug() << "save packet error!";
} else {
}
// av_packet_unref(inputPacket);
inputPacket = nullptr;
frameIndex++;
} else {
QThread::usleep(1000);
}
}
// AVStream *out_stream = m_formatContextSave->streams[0];
// out_stream->start_time = 0;
// m_formatContextSave->start_time = 0;
// int64_t duration_pts = last_pts - first_pts;
// // duration_pts = av_rescale(duration_pts, 1, AV_TIME_BASE);
// m_formatContextSave->duration = duration_pts;
// AVStream *stream = m_formatContextSave->streams[0];
// stream->duration = duration_pts;
// 写入文件尾
if (m_formatContextSave && m_writeHeader) {
av_write_trailer(m_formatContextSave);
// if (m_formatContextSave->duration == 0) {
// m_formatContextSave->duration =
// (m_lastPts - m_firstPts) *
// av_q2d(m_formatContextSave->streams[0]->time_base);
// }
m_writeHeader = false;
}
free();
qDebug() << "视频保存结束!";
emit sendErrorMessageSignal("视频保存结束!", 1);
}
void SaveStream::startSaveUDPStream() {
qDebug() << "SaveStreamThreadID:" << QThread::currentThreadId();
if (!m_start) {
return;
}
int frameIndex = 0;
int64_t pts = 0;
int64_t dts = 0;
int64_t dts_last = 0;
int64_t first_pts = 0;
int64_t last_pts = 0;
while (m_start || !m_queueManager->isEmptySaveQueue()) {
if (m_queueManager->isEmptySaveQueue()) {
QThread::usleep(1000);
continue;
}
AVPacket *inputPacket = m_queueManager->dequeueSavePacket();
if (inputPacket) {
// 由于保存的m_formatContextSave只创建了一个视频流而读取到的图像的流索引不一定为0可能会出现错误【Invalid
// packet stream index: 1】
// 所以这里需要将stream_index指定为和m_formatContextSave中视频流索引相同因为就一个流所以直接设置为0
inputPacket->stream_index = 0;
inputPacket->pos = -1;
inputPacket->pts = pts;
inputPacket->dts = dts;
// PTS & DTS 递增,假设帧率 30FPS
pts += 3000; // 90000 / 30 = 3000
dts += 3000;
int ret = av_interleaved_write_frame(
m_formatContextSave,
av_write_frame(m_formatContextSave,
inputPacket); // 将数据包写入输出媒体文件
if (ret < 0) {
qDebug() << "save packet error!";
} else {
}
// av_packet_unref(inputPacket);
av_packet_unref(inputPacket);
inputPacket = nullptr;
frameIndex++;
} else {
QThread::usleep(1000);
}
}
// 写入文件尾
if (m_formatContextSave && m_writeHeader) {
av_write_trailer(m_formatContextSave);
// if (m_formatContextSave->duration == 0) {
// m_formatContextSave->duration =
// (m_lastPts - m_firstPts) *
// av_q2d(m_formatContextSave->streams[0]->time_base);
// }
m_writeHeader = false;
}
free();
qDebug() << "视频保存结束!";
emit sendErrorMessageSignal("视频保存结束!", 1);
emit sendErrorMessageSignal("视频保存结束!",
NotificationType::NOTIFICATION_SUCCESS);
}
bool SaveStream::openFile(bool isUDP) {
bool SaveStream::openFile() {
// QMutexLocker locker(&m_mutex);
QDir dir;
if (!dir.exists(m_outputDirPath)) {
dir.mkdir(m_outputDirPath);
}
QString strName = QString("/%1.ts").arg(
QDateTime::currentDateTime().toString("yyyy-MM-dd HH-mm-ss"));
QString strName =
QString("/%1.h264")
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH-mm-ss"));
strName = m_outputDirPath + strName;
// const AVOutputFormat *ofmt = av_guess_format("mp4", NULL, NULL);
int ret = avformat_alloc_output_context2(
@ -206,7 +75,21 @@ bool SaveStream::openFile(bool isUDP) {
free();
return false;
}
// m_videoStreamOut->codecpar->codec_tag = 0;
// if (m_formatContextSave->oformat->flags & AVFMT_GLOBALHEADER) {
// m_formatContextSave->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// // m_videoStreamOut->codecpar->extradata = (uint8_t *)av_malloc(1024);
// // m_videoStreamOut->codecpar->extradata_size = 0;
// }
// 创建并初始化AVIOContext以访问url所指示的资源。
ret = avio_open(&m_formatContextSave->pb, strName.toStdString().data(),
AVIO_FLAG_WRITE);
if (ret < 0) {
showError(ret);
qWarning() << "Open file Error";
free();
return false;
}
// 向媒体文件添加新流
m_videoStreamOut = avformat_new_stream(m_formatContextSave, nullptr);
if (!m_videoStreamOut) {
@ -214,15 +97,9 @@ bool SaveStream::openFile(bool isUDP) {
qWarning() << "Create New Stream Error";
return false;
}
if (isUDP) {
m_videoStreamOut->codecpar->codec_id = AV_CODEC_ID_H264;
m_videoStreamOut->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
m_videoStreamOut->codecpar->format = AV_PIX_FMT_YUV420P;
m_videoStreamOut->codecpar->width = 1920; // 确保设置正确的分辨率
m_videoStreamOut->codecpar->height = 1080;
m_videoStreamOut->time_base = {1, 90000}; // 设置时间基准
} else {
// 拷贝一些参数给codecpar赋值(这里使用编码器上下文进行赋值)
// ret = avcodec_parameters_from_context(m_videoStreamOut->codecpar,
// m_inputCodecContex);
ret = avcodec_parameters_copy(
m_videoStreamOut->codecpar,
m_inputFormatContext->streams[m_videoIndex]->codecpar);
@ -232,21 +109,6 @@ bool SaveStream::openFile(bool isUDP) {
qWarning() << "avcodec_parameters_from_context Failed";
return false;
}
}
m_videoStreamOut->codecpar->codec_tag = 0;
av_dump_format(m_formatContextSave, 0, strName.toStdString().data(), 1);
if (!(m_formatContextSave->flags & AVFMT_NOFILE)) {
// 创建并初始化AVIOContext以访问url所指示的资源。
ret = avio_open(&m_formatContextSave->pb, strName.toStdString().data(),
AVIO_FLAG_WRITE);
if (ret < 0) {
showError(ret);
qWarning() << "Open file Error";
free();
return false;
}
}
// 写入文件头
ret = avformat_write_header(m_formatContextSave, nullptr);
@ -276,43 +138,3 @@ void SaveStream::free() {
m_formatContextSave = nullptr;
}
}
bool SaveStream::isValidAVPacket(AVPacket *pkt) {
if (pkt == nullptr) {
qDebug() << "SaveStream: Invalid AVPacket 0: packet pointer is null.";
return false;
}
// 检查数据指针和大小
if (pkt->data == nullptr || pkt->size <= 0) {
qDebug() << "SaveStream: Invalid AVPacket 0: data is null or size is "
"non-positive.\n";
return false;
}
// 检查时间戳
// if (pkt->pts == AV_NOPTS_VALUE || pkt->dts == AV_NOPTS_VALUE) {
// qDebug() << "SaveStream: Invalid AVPacket 0: pts or dts is "
// "AV_NOPTS_VALUE.\n";
// return false;
// }
if (pkt->pts < 0 || pkt->dts < 0) {
qDebug() << "SaveStream: Invalid AVPacket 0: pts or dts <0.\n";
return false;
}
// 检查流索引(如果是多流)
if (pkt->stream_index < 0) {
qDebug()
<< "SaveStream: Invalid AVPacket 0: stream_index is invalid.\n";
return false;
}
// 检查是否是有效的关键帧(可选)
if (pkt->flags & AV_PKT_FLAG_KEY) {
// 是关键帧
// qDebug() << "This is a keyframe.\n";
}
return true;
}

@ -17,7 +17,6 @@ public:
explicit SaveStream(QObject *parent = nullptr);
bool init(AVFormatContext *formatContext,
AVPacketQueueManager *queueManager, int videoIndex);
bool initUDP(AVPacketQueueManager *queueManager);
/**
* @brief
* @param fileDirPath
@ -26,15 +25,13 @@ public:
void close();
public slots:
void startSaveStream();
void startSaveUDPStream();
signals:
void startSaveStreamSignal();
void sendErrorMessageSignal(QString message, int type);
private:
bool openFile(bool isUDP = false);
bool openFile();
void free();
bool isValidAVPacket(AVPacket *pkt);
private:
AVFormatContext *m_formatContextSave = nullptr; // 封装上下文

@ -14,7 +14,6 @@ VideoWidget::VideoWidget(QWidget *parent, Qt::WindowFlags f)
// 初始化视图大小由于Shader里面有YUV转RGB的代码会初始化显示为绿色这里通过将视图大小设置为0避免显示绿色背景
m_pos = QPointF(0, 0);
m_zoomSize = QSize(0, 0);
setVedioSaveFileDirPath("./video");
}
#endif
@ -51,15 +50,10 @@ VideoWidget::~VideoWidget() {
glDeleteVertexArrays(1, &VAO);
}
bool VideoWidget::play(const QString &url, bool bSave) {
if (this->getPlayStatus()) {
emit sendErrorMessageSignal("视频窗口已占用!", 2);
return false;
}
if (url.isEmpty()) return false;
bool VideoWidget::play(const QString &url) {
// if (url.isEmpty()) return;
if (!m_pullFlag) {
m_pullFlag = pullStream(url, bSave);
m_pullFlag = pullStream(url);
if (!m_pullFlag) {
return false;
}
@ -76,24 +70,14 @@ bool VideoWidget::play(const QString &url, bool bSave) {
&VideoWidget::repaint,
Qt::QueuedConnection); // Qt::BlockingQueuedConnection
if (!bSave) {
connect(decodeStreamer, &DecodeStream::updateVideoCurrentTime, this,
&VideoWidget::receiveVideoCurrentTime, Qt::UniqueConnection);
connect(this, &VideoWidget::changePlaySpeedSignal, decodeStreamer,
&DecodeStream::changePlaySpeedSlot, Qt::UniqueConnection);
connect(decodeStreamer, &DecodeStream::decodeEndSignal, this,
&VideoWidget::stopPlay, Qt::UniqueConnection);
}
decodeStreamer->moveToThread(&decodeStreamThread);
decodeStreamThread.start();
bool ss = readStreamer->setStreamDecoder(decodeStreamer);
if (!ss) {
qDebug() << "解码器初始化失败!\n";
emit sendErrorMessageSignal("解码器初始化失败!", 2);
emit sendErrorMessageSignal("解码器初始化失败!",
NotificationType::NOTIFICATION_ERROR);
stopPlay();
return false;
}
@ -102,45 +86,6 @@ bool VideoWidget::play(const QString &url, bool bSave) {
return true;
}
bool VideoWidget::udpPlay(QString ip, int port) {
if (this->getPlayStatus()) {
emit sendErrorMessageSignal("视频窗口已占用!", 2);
return false;
}
if (!m_pullFlag) {
m_pullFlag = pullUDPStream(ip, port);
if (!m_pullFlag) {
return false;
}
}
// 解码线程
if (!decodeStreamer) {
decodeStreamer = new DecodeStream;
connect(decodeStreamer, &DecodeStream::startDecodeSignal,
decodeStreamer, &DecodeStream::startDecode,
Qt::UniqueConnection);
}
connect(decodeStreamer, &DecodeStream::repaintSignal, this,
&VideoWidget::repaint,
Qt::QueuedConnection); // Qt::BlockingQueuedConnection
decodeStreamer->moveToThread(&decodeStreamThread);
decodeStreamThread.start();
bool ss = readStreamer->setUDPStreamDecoder(decodeStreamer);
if (!ss) {
qDebug() << "解码器初始化失败!\n";
emit sendErrorMessageSignal("解码器初始化失败!", 2);
// stopPlay();
return false;
}
m_playFlag = true;
return true;
}
void VideoWidget::stopPlay() {
m_playFlag = false;
if (decodeStreamer) {
@ -153,11 +98,9 @@ void VideoWidget::stopPlay() {
if (!m_pushFlag) {
if (readStreamer) {
readStreamer->close();
QThread::msleep(100);
}
readStreamThread.quit();
readStreamThread.wait();
m_pullFlag = false;
if (saveStreamer) {
@ -236,29 +179,6 @@ void VideoWidget::setVedioSaveFileDirPath(const QString &dirPath) {
m_videoSaveDirPath = dirPath;
}
bool VideoWidget::getPlayStatus() {
return this->m_playFlag;
}
double VideoWidget::getVideoDuration() {
if (m_videoDuration > 0) return m_videoDuration;
return -1;
}
bool VideoWidget::seekToVideo(int64_t targetTime) {
if (readStreamer) {
readStreamer->seekToVideo(targetTime);
}
return true;
}
void VideoWidget::setPlaySpeed(double speed) {
if (decodeStreamer) {
decodeStreamer->changePlaySpeedSlot(speed);
}
emit changePlaySpeedSignal(speed);
}
void VideoWidget::repaint(AVFrame *frame) {
try {
QMutexLocker locker(&m_mutex);
@ -483,9 +403,10 @@ void VideoWidget::initializeGL() {
// 加载shader脚本程序
m_program = new QOpenGLShaderProgram(this);
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.vsh");
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex,
":/gl/vertex.vsh");
m_program->addShaderFromSourceFile(QOpenGLShader::Fragment,
":/fragment.fsh");
":/gl/fragment.fsh");
m_program->link();
// 绑定YUV 变量值
@ -611,28 +532,18 @@ void VideoWidget::paintGL() {
m_program->release();
}
bool VideoWidget::pullStream(const QString &url, bool bSave) {
bool VideoWidget::pullStream(const QString &url) {
if (url.isEmpty()) return false;
if (!readStreamer) {
readStreamer = new ReadStream;
if (bSave) {
connect(readStreamer, &ReadStream::startPullStreamSignal,
readStreamer, &ReadStream::startPullStream,
Qt::UniqueConnection);
} else {
connect(readStreamer, &ReadStream::startPullStreamSignal,
readStreamer, &ReadStream::startReadFileStream,
Qt::UniqueConnection);
}
connect(readStreamer, &ReadStream::startPullStreamSignal, readStreamer,
&ReadStream::startPullStream, Qt::UniqueConnection);
connect(readStreamer, &ReadStream::sendErrorMessageSignal, this,
&VideoWidget::receiveErrorMessage, Qt::UniqueConnection);
// connect(this, &VideoWidget::startPullSignal, readStreamer,
// &ReadStream::startPullStream, Qt::UniqueConnection);
}
if (readStreamer->openFile(url)) {
m_videoDuration = readStreamer->getVideoDuration();
if (bSave) {
// 保存线程
if (!saveStreamer) {
saveStreamer = new SaveStream;
@ -645,7 +556,6 @@ bool VideoWidget::pullStream(const QString &url, bool bSave) {
saveStreamThread.start();
readStreamer->setStreamSaver(saveStreamer);
}
qDebug() << "UIThreadID:" << QThread::currentThreadId();
readStreamer->moveToThread(&readStreamThread);
@ -658,53 +568,12 @@ bool VideoWidget::pullStream(const QString &url, bool bSave) {
return false;
}
bool VideoWidget::pullUDPStream(QString ip, int port) {
if (port <= 0) return false;
if (!readStreamer) {
readStreamer = new ReadStream;
connect(readStreamer, &ReadStream::startPullUDPStreamSignal,
readStreamer, &ReadStream::startPullUDPStream,
Qt::UniqueConnection);
connect(readStreamer, &ReadStream::sendErrorMessageSignal, this,
&VideoWidget::receiveErrorMessage, Qt::UniqueConnection);
}
connect(readStreamer, &ReadStream::closeUDPConnectionSignal, readStreamer,
&ReadStream::closeUDPConnectionSLot, Qt::UniqueConnection);
// if (readStreamer->initSocket(ip, port)) {
// 保存线程
if (!saveStreamer) {
saveStreamer = new SaveStream;
connect(saveStreamer, &SaveStream::startSaveStreamSignal, saveStreamer,
&SaveStream::startSaveUDPStream, Qt::UniqueConnection);
}
saveStreamer->setSaveFileDirPath(m_videoSaveDirPath);
saveStreamer->moveToThread(&saveStreamThread);
saveStreamThread.start();
readStreamer->setStreamSaver(saveStreamer, true);
readStreamer->setUDPParms(ip, port);
qDebug() << "UIThreadID:" << QThread::currentThreadId();
readStreamer->moveToThread(&readStreamThread);
readStreamThread.start();
emit readStreamer->startPullUDPStreamSignal();
return true;
// }
// return false;
}
void VideoWidget::receiveErrorMessage(QString message, int type) {
// qDebug() << "receive message:" << message;
emit sendErrorMessageSignal(message, type);
}
void VideoWidget::receiveVideoCurrentTime(int64_t currentTime,
int64_t duration) {
emit updateVideoCurrentTimeSignal(currentTime, duration);
}
QSizeF VideoWidget::getCurImgSize() {
QSizeF VideoWidget::getCurImgSize()
{
return m_zoomSize;
}

@ -43,19 +43,13 @@ public:
#endif
~VideoWidget() override;
bool play(const QString &url, bool bSave = true);
bool udpPlay(QString ip, int port);
bool play(const QString &url);
void stopPlay();
bool pushStream(const QString &url);
void stopPushStream();
void setPullURL(const QString &url);
void setPushURL(const QString &url);
void setVedioSaveFileDirPath(const QString &dirPath);
bool getPlayStatus();
double getVideoDuration();
bool seekToVideo(int64_t targetTime);
void setPlaySpeed(double speed);
protected:
void initializeGL() override; // 初始化gl
@ -91,10 +85,8 @@ private: // opengl
int m_format; // 像素格式
private:
bool pullStream(const QString &url, bool bSave = true);
bool pullUDPStream(QString ip, int port);
bool pullStream(const QString &url);
void receiveErrorMessage(QString message, int type);
void receiveVideoCurrentTime(int64_t currentTime, int64_t duration);
private:
QString m_pullURL;
@ -118,15 +110,9 @@ private:
QMutex m_mutex;
int m_videoDuration;
signals:
void startPullSignal();
void sendErrorMessageSignal(QString message, int type);
void closeUDPConnectionSignal();
void updateVideoCurrentTimeSignal(int64_t currentTime, int64_t duration);
void changePlaySpeedSignal(double speed);
public:
QSizeF getCurImgSize();
};

@ -2,7 +2,7 @@
global::global() {}
QString g_SoftwareVersion = "版本号V1.1.0.6_20250215";
QString g_SoftwareVersion = "版本号V1.1.0.7_20250218";
NotifyManager *g_notifyManager = nullptr;

@ -19,7 +19,6 @@
#include "global.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
@ -47,7 +46,6 @@ MainWindow::MainWindow(QWidget *parent)
initUAVIDMap();
initNotifyManager();
initUserLoginDlg();
}
MainWindow::~MainWindow() {
@ -94,26 +92,36 @@ void MainWindow::initWindow() {
// 使用类中的get方法获取配置文件中的IP
m_allSetMap = m_HomePagedlg->settingWidget->getAllParam();
//m_GDDCdlg->setGlobalSetMap(m_allSetMap);
m_GDDCdlg->setGlobalSetMap(m_allSetMap);
/*qDebug() << "=============设备配置================";
qDebug() << "光电吊舱------";
qDebug() << "远端ip" << m_allSetMap["Pod"].net.remoteIp;
qDebug() << "远端ip" << m_allSetMap["光电吊舱"].net.remoteIp;
qDebug() << "L链----------";
qDebug() << "ULR:" << m_allSetMap["L-Link"].url;
qDebug() << "ULR:" << m_allSetMap["L"].url;
qDebug() << "宽带自组网-----";
qDebug() << "URL:" << m_allSetMap["HocNetwork"].url;
qDebug() << "URL:" << m_allSetMap["宽带自组网"].url;
qDebug() << "机载卫通------";
qDebug() << "URL:" << m_allSetMap["SatelliteComm"].url;
qDebug() << "URL:" << m_allSetMap["机载卫通"].url;
qDebug() << "三维建模------";
qDebug() << "远端ip:" << m_allSetMap["ModelCamera"].net.remoteIp;
qDebug() << "远端端口:" << m_allSetMap["ModelCamera"].net.remotePort;
qDebug() << "本地ip:" << m_allSetMap["ModelCamera"].net.localIp;
qDebug() << "本地端口:" << m_allSetMap["ModelCamera"].net.localPort;*/
qDebug() << "远端ip:" << m_allSetMap["三维建模"].net.remoteIp;
qDebug() << "远端端口:" << m_allSetMap["三维建模"].net.remotePort;
qDebug() << "本地ip:" << m_allSetMap["三维建模"].net.localIp;
qDebug() << "本地端口:" << m_allSetMap["三维建模"].net.localPort;*/
// mWeb = new CWebEngineView();
// mWeb->setPage(new CustomWebEnginePage());
// mWeb->load(QUrl("http://192.168.150.1"));
lLinkWeb = new CWebEngineView();
lLinkWeb->setPage(new CustomWebEnginePage());
lLinkWeb->load(QUrl(m_allSetMap["L-Link"].url));
connect(lLinkWeb->page(), &QWebEnginePage::loadFinished, this, [=]() {
// QString jsScript = R"(
// var usernameField =
// document.querySelector('input[name="username"]'); if
// (usernameField) {
// usernameField.value = 'admin'; // 填充用户名
// }
// )";
QString jsScript = R"(
var button = document.getElementById('clickButt');
if (button) {
@ -145,6 +153,7 @@ void MainWindow::initWindow() {
[&](unsigned char urlIndex, settingStruct settings) {
switch (urlIndex) {
case HomePageSetingWidget::GDDC:
// dosomething
m_GDDCdlg->m_DlgGDDCSet->initPullURL(settings.net.remoteIp);
break;
case HomePageSetingWidget::L_Link:
@ -168,6 +177,7 @@ void MainWindow::initWindow() {
ui->stackedWidget->addWidget(m_SDFPDlg);
ui->stackedWidget->addWidget(m_HomePagedlg);
ui->stackedWidget->addWidget(m_GDDCdlg);
// ui->stackedWidget->addWidget(mWeb);
ui->stackedWidget->addWidget(lLinkWeb);
ui->stackedWidget->addWidget(adHocNetworkWeb);
ui->stackedWidget->addWidget(satelliteCommWeb);
@ -175,7 +185,6 @@ void MainWindow::initWindow() {
ui->stackedWidget->addWidget(m_ModelCameraDlg);
// 初始栈窗口显示主页
ui->stackedWidget->setCurrentWidget(m_SDFPDlg);
ui->senceContrlWidget->hide();
}
void MainWindow::initButton() {
@ -191,8 +200,6 @@ void MainWindow::initButton() {
ui->toolButton_7->setIcon(QIcon(":/res/research.png"));
ui->toolButton_8->setIcon(QIcon(":/res/3D.png"));
ui->toolButton_9->setIcon(QIcon(":/res/SDFP3.png"));
ui->toolButton_10->setIcon(QIcon(":/res/SDFP3.png"));
ui->toolButton_21->setIcon(QIcon(":/res/GDDC.png"));
ui->toolButton->setIconSize(QSize(sizeX, sizeY));
ui->toolButton_2->setIconSize(QSize(sizeX, sizeY));
ui->toolButton_3->setIconSize(QSize(sizeX, sizeY));
@ -202,8 +209,6 @@ void MainWindow::initButton() {
ui->toolButton_7->setIconSize(QSize(sizeX, sizeY));
ui->toolButton_8->setIconSize(QSize(sizeX, sizeY));
ui->toolButton_9->setIconSize(QSize(sizeX * 1.2, sizeY * 1.2));
ui->toolButton_10->setIconSize(QSize(sizeX * 1.2, sizeY * 1.2));
ui->toolButton_21->setIconSize(QSize(sizeX, sizeY));
ui->toolButton->setText("主页");
ui->toolButton_2->setText("光电吊舱");
ui->toolButton_3->setText("L链");
@ -213,8 +218,6 @@ void MainWindow::initButton() {
ui->toolButton_7->setText("搜救载荷");
ui->toolButton_8->setText("三维建模");
ui->toolButton_9->setText("时代飞鹏");
ui->toolButton_10->setText("时代飞鹏");
ui->toolButton_21->setText("光电吊舱");
ui->toolButton->setFixedWidth(FixedWidth);
ui->toolButton_2->setFixedWidth(FixedWidth);
ui->toolButton_3->setFixedWidth(FixedWidth);
@ -224,8 +227,6 @@ void MainWindow::initButton() {
ui->toolButton_7->setFixedWidth(FixedWidth);
ui->toolButton_8->setFixedWidth(FixedWidth);
ui->toolButton_9->setFixedWidth(FixedWidth);
ui->toolButton_10->setFixedWidth(FixedWidth);
ui->toolButton_21->setFixedWidth(FixedWidth);
ui->toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->toolButton_2->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->toolButton_3->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
@ -235,8 +236,6 @@ void MainWindow::initButton() {
ui->toolButton_7->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->toolButton_8->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->toolButton_9->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->toolButton_10->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->toolButton_21->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
ui->toolButton->setStyleSheet(g_ToolBtnStyle);
ui->toolButton_2->setStyleSheet(g_ToolBtnStyle);
ui->toolButton_3->setStyleSheet(g_ToolBtnStyle);
@ -246,8 +245,6 @@ void MainWindow::initButton() {
ui->toolButton_7->setStyleSheet(g_ToolBtnStyle);
ui->toolButton_8->setStyleSheet(g_ToolBtnStyle);
ui->toolButton_9->setStyleSheet(g_ToolBtnStyle);
ui->toolButton_10->setStyleSheet(g_ToolBtnStyle);
ui->toolButton_21->setStyleSheet(g_ToolBtnStyle);
// ui->pushButton->setStyleSheet(g_PushBtnStyle);
}
@ -362,28 +359,6 @@ void MainWindow::toolButton_9_clicked() {
ui->stackedWidget->setCurrentWidget(m_SDFPDlg);
}
void MainWindow::getUserSence(UserLogin::use_sence sence)
{
_currentScene = sence;
switch(sence)
{
case UserLogin::Emergency:
{
// QMessageBox::information(NULL, "提示", "进入switch emergency");
emergencySceneShow();
break;
}
case UserLogin::Sea_Rescue:
{
// QMessageBox::information(NULL, "提示", "进入switch Sea_Rescue!");
seaRescueSceneShow();
break;
}
default:
break;
}
}
// 更新主界面按钮颜色
void MainWindow::changeBtnColor(int num) {
initButton();
@ -415,12 +390,6 @@ void MainWindow::changeBtnColor(int num) {
case 9:
ui->toolButton_9->setStyleSheet(g_ToolBtnSelStyle);
break;
case 10:
ui->toolButton_10->setStyleSheet(g_ToolBtnSelStyle);
break;
case 11:
ui->toolButton_21->setStyleSheet(g_ToolBtnSelStyle);
break;
}
}
@ -455,22 +424,6 @@ void MainWindow::initNotifyManager() {
g_notifyManager->setNotifyWndSize(300, 60);
}
void MainWindow::initUserLoginDlg()
{
m_userLoginDlg = new UserLogin(this);
// m_userLoginDlg->setWindowFlags(Qt::Dialog);
// m_userLoginDlg->show();
ui->stackedWidget->addWidget(m_userLoginDlg);
_currentScene = 0;
//初始化槽函数
connect(m_userLoginDlg,&UserLogin::sendSenceData,this,&MainWindow::getUserSence);
connect(m_userLoginDlg,&UserLogin::loginDlgClick,this,&MainWindow::getloginDlgBtnClicked);
connect(m_SDFPDlg,&SDFPDlg::clickLoginBtn,this,&MainWindow::receptLoginBtnClicked);
}
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message,
qintptr *result) {
#ifdef Q_OS_WIN
@ -486,78 +439,3 @@ bool MainWindow::nativeEvent(const QByteArray &eventType, void *message,
#endif
return QMainWindow::nativeEvent(eventType, message, result);
}
// 海上 主页面
void MainWindow::on_toolButton_10_clicked()
{
changeBtnColor(10);
ui->stackedWidget->setCurrentWidget(m_SDFPDlg);
}
// 海上 光电吊舱
void MainWindow::on_toolButton_21_clicked()
{
changeBtnColor(11);
ui->stackedWidget->setCurrentWidget(m_GDDCdlg);
}
void MainWindow::receptLoginBtnClicked()
{
ui->senceContrlWidget->hide();
ui->stackedWidget->setCurrentWidget(m_userLoginDlg);
}
void MainWindow::getloginDlgBtnClicked(int clickType)
{
switch(clickType)
{
case UserLogin::click_type::HomePageClick:
{
if(_currentScene == 0)
{
ui->senceContrlWidget->hide();
ui->stackedWidget->setCurrentWidget(m_SDFPDlg);
}
else if(_currentScene == 1)
{
emergencySceneShow();
}
else if(_currentScene == 2)
{
seaRescueSceneShow();
}
break;
}
case UserLogin::click_type::ExitLogin: //退出登录
{
_currentScene = 0;
ui->stackedWidget->setCurrentWidget(m_SDFPDlg);
ui->senceContrlWidget->hide();
}
default:
break;
}
}
//应急场景显示
void MainWindow::emergencySceneShow()
{
toolButton_9_clicked();
ui->senceContrlWidget->setCurrentIndex(0);
if(!ui->senceContrlWidget->isVisible())
{
ui->senceContrlWidget->show();
}
}
//海上就捞场景显示
void MainWindow::seaRescueSceneShow()
{
on_toolButton_10_clicked();
ui->senceContrlWidget->setCurrentIndex(1);
if(!ui->senceContrlWidget->isVisible())
{
ui->senceContrlWidget->show();
}
}

@ -18,7 +18,6 @@
#include "Src/HomePage/homepagedlg.h"
#include "Src/ModelCamera/modelcameradlg.h"
#include "Src/RescueLoad/rescueloadwidget.h"
#include "userlogin.h"
#ifdef Q_OS_WIN
#include "windows.h"
@ -62,12 +61,6 @@ private slots:
void toolButton_8_clicked();
void toolButton_9_clicked();
void getUserSence(UserLogin::use_sence sence);
void on_toolButton_10_clicked();
void on_toolButton_21_clicked();
void receptLoginBtnClicked();//sdfp页面登录按钮点击
void getloginDlgBtnClicked(int clickType);//登录页面按钮点击
public:
GDDCdlg *m_GDDCdlg;
HomePageDlg *m_HomePagedlg;
@ -79,15 +72,11 @@ public:
QWebEngineView *lLinkWeb; // L链
QWebEngineView *adHocNetworkWeb; // 自组网
QWebEngineView *satelliteCommWeb; // 卫通
UserLogin *m_userLoginDlg; //用户登陆页面
private:
QProcess *processPDT;
QString exeDirPathName = "";
std::unordered_map<QString, settingStruct> m_allSetMap;
int _currentScene;
void emergencySceneShow();
void seaRescueSceneShow();
public:
void changeBtnColor(int num);
@ -98,8 +87,5 @@ private:
void initUAVIDMap();
void initNotifyManager();
//初始化用户登陆页面
void initUserLoginDlg();
};
#endif // MAINWINDOW_H

@ -38,11 +38,5 @@
<file>res/switch/switch_close3.png</file>
<file>res/switch/switch_open3.png</file>
<file>res/SDFP3.png</file>
<file>res/eyesOpen1.png</file>
<file>res/eyesOpen.png</file>
<file>res/eye1.png</file>
<file>res/eye2.png</file>
<file>res/eye3.png</file>
<file>res/eyec1.png</file>
</qresource>
</RCC>

@ -57,25 +57,8 @@
<property name="spacing">
<number>0</number>
</property>
<item row="1" column="1">
<widget class="QStackedWidget" name="stackedWidget">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<widget class="QWidget" name="Page1">
<layout class="QVBoxLayout" name="SubPage">
<property name="bottomMargin">
<number>2</number>
</property>
</layout>
</widget>
</widget>
</item>
<item row="0" column="0" rowspan="2">
<widget class="QStackedWidget" name="senceContrlWidget">
<item row="0" column="0">
<widget class="QFrame" name="frame">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -85,10 +68,6 @@
<property name="styleSheet">
<string notr="true">background-color: rgb(40, 40, 40);</string>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="stackedWidgetPage1">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget_2" native="true"/>
@ -213,45 +192,14 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="page">
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QWidget" name="widget_9" native="true"/>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QToolButton" name="toolButton_10">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="toolButton_21">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>48</height>
</size>
<item row="0" column="1">
<widget class="QStackedWidget" name="stackedWidget">
<widget class="QWidget" name="Page1">
<layout class="QVBoxLayout" name="SubPage">
<property name="bottomMargin">
<number>2</number>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
@ -313,7 +261,7 @@
</action>
<action name="toolbar_action2">
<property name="icon">
<iconset resource="mainwindow.qrc">
<iconset>
<normaloff>:/res/GDDC.png</normaloff>:/res/GDDC.png</iconset>
</property>
<property name="text">
@ -325,7 +273,7 @@
</action>
<action name="toolbar_action3">
<property name="icon">
<iconset resource="mainwindow.qrc">
<iconset>
<normaloff>:/res/LChain.png</normaloff>:/res/LChain.png</iconset>
</property>
<property name="text">
@ -399,8 +347,6 @@
</property>
</action>
</widget>
<resources>
<include location="mainwindow.qrc"/>
</resources>
<resources/>
<connections/>
</ui>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Loading…
Cancel
Save