diff --git a/3rdparty/QNotify/bin/QNotify.dll b/3rdparty/QNotify/bin/QNotify.dll new file mode 100644 index 0000000..6f6f296 Binary files /dev/null and b/3rdparty/QNotify/bin/QNotify.dll differ diff --git a/3rdparty/QNotify/bin/QNotifyd.dll b/3rdparty/QNotify/bin/QNotifyd.dll new file mode 100644 index 0000000..bd7e9b8 Binary files /dev/null and b/3rdparty/QNotify/bin/QNotifyd.dll differ diff --git a/3rdparty/QNotify/include/ArrangedWidget.cpp b/3rdparty/QNotify/include/ArrangedWidget.cpp new file mode 100644 index 0000000..460b77a --- /dev/null +++ b/3rdparty/QNotify/include/ArrangedWidget.cpp @@ -0,0 +1,88 @@ +#include "ArrangedWidget.h" + +// 动画 +static QPropertyAnimation *propertyAnimationOnTarget( + QObject *target, const QByteArray &propertyName, const QVariant &endValue, + int duration) { + QPropertyAnimation *animation = + new QPropertyAnimation(target, propertyName, target); + animation->setStartValue(target->property(propertyName)); + animation->setEndValue(endValue); + animation->setDuration(duration); + animation->start(QAbstractAnimation::DeleteWhenStopped); + return animation; +} + +// 动画模板 +template +static inline void propertyAnimationOnTarget(QObject *target, + const QByteArray &propertyName, + const QVariant &endValue, + int duration, func onFinished) { + QPropertyAnimation *animation = + propertyAnimationOnTarget(target, propertyName, endValue, duration); + QObject::connect(animation, &QPropertyAnimation::finished, target, + onFinished); +} + +ArrangedWidget::ArrangedWidget(NotifyManager *manager, QWidget *parent) + : QWidget(parent) { + // 初始化界面 + this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | + Qt::WindowStaysOnTopHint); // 必须设置为Qt::Tools + this->setAttribute(Qt::WA_NoSystemBackground, true); + this->setAttribute(Qt::WA_TranslucentBackground, true); + this->setFixedSize(manager->notifyWndSize()); + + // 初始化成员变量 + m_manager = manager; // NotifyWidget创建的时候传入 + m_posIndex = 0; + + // manager销毁,界面也跟着销毁 + connect(manager, &QObject::destroyed, this, &QObject::deleteLater); +} + +// 根据通知在队列中的索引,来设置其的位置,相当于更新排序 +void ArrangedWidget::showArranged(int posIndex) { + if (m_posIndex == posIndex) return; + + m_posIndex = posIndex; + + // 索引小于等于0,则隐藏 + if (posIndex <= 0) { + // 如果已经隐藏,则返回 + if (!isVisible()) return; + + // 隐藏动画 + propertyAnimationOnTarget(this, "windowOpacity", 0, + m_manager->animateTime(), [this]() { + this->hide(); + emit visibleChanged(false); // 隐藏信号 + }); + + return; + } + + // 计算提醒框的位置 + QSize wndsize = m_manager->notifyWndSize(); + QSize offset = + QSize(wndsize.width(), wndsize.height() * posIndex + + m_manager->spacing() * (posIndex - 1)); + + QPoint pos = + m_manager->cornerPos() - QPoint(offset.width() / 2, -offset.height()); + + // 如果原先是隐藏的,现在显示 + if (!isVisible()) { + this->show(); + this->move(pos); + this->setWindowOpacity(0); + propertyAnimationOnTarget(this, "windowOpacity", 1, + m_manager->animateTime(), [this]() { + emit visibleChanged(true); + }); + } else // 否则,移动位置 + { + propertyAnimationOnTarget(this, "pos", pos, m_manager->animateTime()); + } +} diff --git a/3rdparty/QNotify/include/ArrangedWidget.h b/3rdparty/QNotify/include/ArrangedWidget.h new file mode 100644 index 0000000..aecc9fd --- /dev/null +++ b/3rdparty/QNotify/include/ArrangedWidget.h @@ -0,0 +1,28 @@ +#ifndef ARRANGEWND_H +#define ARRANGEWND_H + +#include +#include +#include +#include "NotifyManager.h" + +class NotifyManager; + +// 排列父界面,为什么要定义这个类,就是要同时作为NotifyWidget和NotifyCountWidget的父类,好让NotifyCountWidget始终在NotifyWidget的上方 +class ArrangedWidget : public QWidget +{ + Q_OBJECT + +public: + explicit ArrangedWidget(NotifyManager *manager, QWidget *parent = 0); + void showArranged(int posIndex); // 根据通知在队列中的索引,来设置其的位置,相当于更新排序 + +signals: + void visibleChanged(bool visible); // 界面可见状态改变的信号 + +protected: + NotifyManager *m_manager; + int m_posIndex; +}; + +#endif // ARRANGEWND_H diff --git a/3rdparty/QNotify/include/NotifyManager.cpp b/3rdparty/QNotify/include/NotifyManager.cpp new file mode 100644 index 0000000..2fc1f50 --- /dev/null +++ b/3rdparty/QNotify/include/NotifyManager.cpp @@ -0,0 +1,304 @@ +#include "NotifyManager.h" + +#include "NotifyWidget.h" // NotifyWidget.h没有放到NotifyManager.h文件,是因为NotifyWidget.cpp也include了NotifyManager.h,为了能互相include才这么做 + +NotifyManager::NotifyManager(QWidget *widget, QObject *parent) + : m_parentWidget(widget), QObject(parent) { + m_maxCount = 5; // 可见的最大通知数目设置为5 + m_displayTime = + 3000; // 显示时间默认设置为3秒,通知显示出来过了10秒之后隐藏并自动销毁 + m_animateTime = 300; // 动画时间设置为300ms + m_spacing = 10; // 通知框之间的间距设置为10 + m_notifyWndSize = QSize(300, 40); // 通知框大小 + m_defaultIcon = ":/message1.png"; // 默认图标 + initStyleSheet(); + m_isShowQueueCount = true; // 默认显示队列的通知数目 + + // 传入边距以设置最下面的通知的右下角坐标 + this->setCornerMargins(10, 10); + + // 初始化队列的剩余通知数目界面 + m_notifyCount = new NotifyCountWidget(this, m_parentWidget); +} + +// 弹出通知框 +void NotifyManager::notify(const QString &title, const QString &body, int type, + int displayTime, const QVariantMap &data) { + // 将标题栏和内容数据添加到队列中 + QVariantMap tmp = data; + tmp.insert("title", title); + tmp.insert("body", body); + // tmp.insert("type", type); + switch (type) { + case NotificationType::SUCCESS: + m_defaultIcon = ":/success.png"; + tmp.insert("theme", "success"); + break; + case NotificationType::WARNING: + m_defaultIcon = ":/warning.png"; + tmp.insert("theme", "warn"); + break; + case NotificationType::ERROR: + m_defaultIcon = ":/error.png"; + tmp.insert("theme", "error"); + break; + default: + break; + } + setDisplayTime(displayTime); + m_dataQueue.enqueue(tmp); + + // 显示下一条通知 + showNext(); +} + +// 设置通知框的最大数目 +void NotifyManager::setMaxCount(int count) { + m_maxCount = count; +} + +// 获取通知框显示时间 +int NotifyManager::displayTime() const { + return m_displayTime; +} + +// 设置通知框显示时间 +void NotifyManager::setDisplayTime(int displayTime) { + m_displayTime = displayTime; +} + +// 获取动画时间 +int NotifyManager::animateTime() const { + return m_animateTime; +} + +// 设置动画时间 +void NotifyManager::setAnimateTime(int animateTime) { + m_animateTime = animateTime; +} + +// 获取通知栏之间的间距 +int NotifyManager::spacing() const { + return m_spacing; +} + +// 设置通知栏之间的间距 +void NotifyManager::setSpacing(int spacing) { + m_spacing = spacing; +} + +// 获取最下面的通知的右下角坐标 +QPoint NotifyManager::cornerPos() { + QScreen *screen = QGuiApplication::primaryScreen(); + QRect screenGeometry = screen->availableGeometry(); + qreal dpiScale = screen->devicePixelRatio(); + QRect widgetGeometry = m_parentWidget->geometry(); + QPoint pt = widgetGeometry.topLeft(); + m_cornerPos.setX((pt.x() + m_parentWidget->width() / 2)); + m_cornerPos.setY(widgetGeometry.top() - m_notifyWndSize.height()); + return m_cornerPos; +} + +// 传入边距以设置最下面的通知的右下角坐标 +void NotifyManager::setCornerMargins(int right, int bottom) { + // QRect desktopRect = QApplication::primaryScreen()->availableGeometry(); + // QPoint bottomRignt = desktopRect.bottomRight(); + // m_cornerPos = QPoint(bottomRignt.x() - right, bottomRignt.y() - bottom); + // 获取当前屏幕的DPI和缩放比例 + QScreen *screen = QGuiApplication::primaryScreen(); + QRect screenGeometry = screen->availableGeometry(); + qreal dpiScale = screen->devicePixelRatio(); + + QPoint bottomRignt; + QPoint pt; + QRect widgetGeometry = m_parentWidget->geometry(); + int y = widgetGeometry.top(); + QPoint lpt = widgetGeometry.topLeft(); + pt = m_parentWidget->mapToGlobal(lpt); + bottomRignt.setX((screenGeometry.width() - m_parentWidget->width()) / 2); + bottomRignt.setY((screenGeometry.height()) / 2); + m_cornerPos = + QPoint(bottomRignt.x() * dpiScale, bottomRignt.y() * dpiScale); +} + +// 获取通知框的尺寸 +QSize NotifyManager::notifyWndSize() const { + return m_notifyWndSize; +} + +// 设置通知框的尺寸 +void NotifyManager::setNotifyWndSize(int width, int height) { + m_notifyWndSize = QSize(width, height); +} + +// 获取默认图标的路径 +QString NotifyManager::defaultIcon() const { + return m_defaultIcon; +} + +// 设置默认图标 +void NotifyManager::setDefaultIcon(const QString &defaultIcon) { + m_defaultIcon = defaultIcon; +} + +// 获取指定theme的样式 +QString NotifyManager::styleSheet(const QString &theme) const { + if (!m_styleSheets.contains(theme)) return m_styleSheets.value("default"); + + return m_styleSheets.value(theme); +} + +// 设置指定theme的样式 +void NotifyManager::setStyleSheet(const QString &styleSheet, + const QString &theme) { + m_styleSheets[theme] = styleSheet; +} + +// 设置是否显示队列的通知数目 +void NotifyManager::setShowQueueCount(bool isShowQueueCount) { + m_isShowQueueCount = isShowQueueCount; + + if (!m_isShowQueueCount) m_notifyCount->showArranged(0); +} + +// 显示下一条通知 +void NotifyManager::showNext() { + // 如果通知数目超出限制,则显示"通知当前数目界面" + if (m_notifyList.size() >= m_maxCount || m_dataQueue.isEmpty()) { + showQueueCount(); + return; + } + + // 创建并显示新的通知框 + NotifyWidget *notifyWidget = + new NotifyWidget(this); // 将管理员自身传给notifyWidget的m_manager + m_notifyList.append(notifyWidget); // 添加到通知框列表 + notifyWidget->showArranged(m_notifyList.size()); // 设置新通知的显示位置 + notifyWidget->setData( + m_dataQueue + .dequeue()); // 设置数据队列的第一个数据(dequeue,删除队列第一个元素,并返回这个元素) + showQueueCount(); // 显示队列的剩余通知数目 + + // 通知过了displayTime时间之后隐藏之后销毁,然后触发下面槽函数 + connect(notifyWidget, &QObject::destroyed, this, [notifyWidget, this]() { + // 找到被销毁的通知在队列中的索引,然后移除该通知 + int index = m_notifyList.indexOf(notifyWidget); + m_notifyList.removeAt(index); + + // 旧消息被移出后,就要显示通知队列中的下一个新消息,并排序 + for (; index < m_notifyList.size(); index++) + m_notifyList[index]->showArranged(index + 1); + + // 这里是为了实现周期提示功能,一般不用到,可以注释 + QTimer::singleShot(m_animateTime, this, [this]() { + showNext(); + }); + }); +} + +// 显示队列的剩余通知数目 +void NotifyManager::showQueueCount() { + // 判断是否允许显示队列的剩余通知数目 + if (!m_isShowQueueCount) return; + + // 数据队列大于0,说明还有未显示的剩余通知,则显示数目;否则隐藏"剩余通知数目" + if (!m_dataQueue.isEmpty()) { + m_notifyCount->showArranged(m_maxCount + 1); + m_notifyCount->setCount(m_dataQueue.size()); + } else { + m_notifyCount->showArranged(0); + } +} + +void NotifyManager::initStyleSheet() { + m_styleSheets["default"] = + "#notify-background {" + "background: white;" + "border-radius: 6px;" + "}" + "#notify-title{" + "font-weight: bold;" + "font-size: 14px;" + "color: #333333;" + "}" + "#notify-body{" + "font-size: 12px;" + "color: #444444;" + "}" + "#notify-close-btn{ " + "border: 0;" + "color: #999999;" + "}" + "#notify-close-btn:hover{ " + "background: #cccccc;" + "}"; + + m_styleSheets["success"] = + "#notify-background {" + "background: rgba(236, 253, 245, 0.95);" + "border-radius: 6px;" + "border: 1px solid #A7F3D0;" + "}" + "#notify-title{" + "font-weight: bold;" + "font-size: 14px;" + "color: #059669;" + "}" + "#notify-body{" + "font-size: 12px;" + "color: #059669;" + "}" + "#notify-close-btn{ " + "border: 0;" + "color: #059669;" + "}" + "#notify-close-btn:hover{ " + "background: #D1FAE5;" + "}"; + + m_styleSheets["warn"] = + "#notify-background {" + "background: rgba(254, 252, 232, 0.95);" + "border-radius: 6px;" + "border: 1px solid #FEF08A;" + "}" + "#notify-title{" + "font-weight: bold;" + "font-size: 14px;" + "color: #D97706;" + "}" + "#notify-body{" + "font-size: 12px;" + "color: #D97706;" + "}" + "#notify-close-btn{ " + "border: 0;" + "color: #D97706;" + "}" + "#notify-close-btn:hover{ " + "background: #FEF9C3;" + "}"; + + m_styleSheets["error"] = + "#notify-background {" + "background: rgba(254, 242, 242, 0.95);" + "border-radius: 6px;" + "border: 1px solid #FECACA;" + "}" + "#notify-title{" + "font-weight: bold;" + "font-size: 14px;" + "color: #DC2626;" + "}" + "#notify-body{" + "font-size: 12px;" + "color: #DC2626;" + "}" + "#notify-close-btn{ " + "border: 0;" + "color: #DC2626;" + "}" + "#notify-close-btn:hover{ " + "background: #FEE2E2;" + "}"; +} diff --git a/3rdparty/QNotify/include/NotifyManager.h b/3rdparty/QNotify/include/NotifyManager.h new file mode 100644 index 0000000..4f4bd00 --- /dev/null +++ b/3rdparty/QNotify/include/NotifyManager.h @@ -0,0 +1,78 @@ +#ifndef NOTIFYMANAGER_H +#define NOTIFYMANAGER_H + +#include +#include +#include +// #include + +#include "QNotify_global.h" + +class NotifyWidget; +class NotifyCountWidget; + +QNOTIFY_EXPORT enum NotificationType { + NOTIFICATION_INFORMATION = 0, + NOTIFICATION_SUCCESS = 1, + NOTIFICATION_ERROR = 2, + NOTIFICATION_WARNING = 3 +}; + +class QNOTIFY_EXPORT NotifyManager : public QObject { + Q_OBJECT + +public: + explicit NotifyManager(QWidget *widget, QObject *parent = 0); + void notify(const QString &title, const QString &body, int type = 0, + int displayTime = 3000, + const QVariantMap &data = QVariantMap()); // 弹出通知框 + void setMaxCount(int count); // 设置通知框的最大数目 + int displayTime() const; // 获取通知框显示时间 + void setDisplayTime(int displayTime); // 设置通知框显示时间 + int animateTime() const; // 获取动画时间 + void setAnimateTime(int animateTime); // 设置动画时间 + int spacing() const; // 获取通知框之间的间距 + void setSpacing(int spacing); // 设置通知框之间的间距 + QPoint cornerPos(); // 获取最下面的通知框的右下角坐标 + void setCornerMargins( + int right, int bottom); // 传入边距以设置最下面的通知的右下角坐标 + QSize notifyWndSize() const; // 获取通知框的尺寸 + void setNotifyWndSize(int width, int height); // 设置通知框的尺寸 + QString defaultIcon() const; // 获取默认图标的路径 + void setDefaultIcon(const QString &defaultIcon); // 设置默认图标 + QString styleSheet( + const QString &theme = "default") const; // 获取指定theme的样式 + void setStyleSheet( + const QString &styleSheet, + const QString &theme = "default"); // 设置指定theme的样式 + + void setShowQueueCount( + bool isShowQueueCount); // 设置是否显示队列的通知数目 + +public: +signals: + void notifyDetail(const QVariantMap &data); + +private: + void showNext(); // 显示下一条通知 + void showQueueCount(); // 显示队列的通知数目 + void initStyleSheet(); + + QWidget *m_parentWidget; + + QQueue m_dataQueue; // 存放标题栏和内容数据的队列 + QList m_notifyList; // 通知框列表 + NotifyCountWidget *m_notifyCount; // 队列的剩余通知数目界面 + + int m_maxCount; // 通知框的最大数目 + bool m_isShowQueueCount; // 是否显示队列的剩余通知数目 + int m_displayTime; // 通知框显示时间 + int m_animateTime; // 动画时间 + int m_spacing; // 通知框之间的间距 + QPoint m_cornerPos; // 最下面的通知框的右下角坐标 + QSize m_notifyWndSize; // 通知框的尺寸 + QString m_defaultIcon; // 默认图标 + QMap m_styleSheets; // 存放多个theme的样式的map +}; + +#endif // NOTIFYMANAGER_H diff --git a/3rdparty/QNotify/include/NotifyWidget.cpp b/3rdparty/QNotify/include/NotifyWidget.cpp new file mode 100644 index 0000000..b130879 --- /dev/null +++ b/3rdparty/QNotify/include/NotifyWidget.cpp @@ -0,0 +1,181 @@ +#include "NotifyWidget.h" + +#include "NotifyManager.h" + +NotifyWidget::NotifyWidget(NotifyManager *manager, QWidget *parent) + : ArrangedWidget( + manager, + parent) // 这里将manager传入到父类ArrangedWidget中的m_manager了,同时继承了,可以使用父类manager来进行管理 +{ + // 初始化背景界面 + m_pFrameBack = new QFrame(this); + m_pFrameBack->setGeometry(3, 3, width() - 6, height() - 6); + m_pFrameBack->setObjectName("notify-background"); + // 初始化图标标签 + m_pLabIcon = new QLabel(m_pFrameBack); + m_pLabIcon->setFixedSize(40, 40); + m_pLabIcon->setAlignment(Qt::AlignCenter); + m_pLabIcon->setWordWrap(true); + // 初始化标题栏标签 + m_pLabTitle = new QLabel(m_pFrameBack); + m_pLabTitle->setObjectName("notify-title"); + // 初始化内容标签 + m_pLabBody = new QLabel(m_pFrameBack); + m_pLabBody->setObjectName("notify-body"); + m_pLabBody->setAlignment(Qt::AlignLeft | Qt::AlignTop); + m_pLabBody->setWordWrap(true); + + // 内容布局 + QVBoxLayout *pLayoutContent = new QVBoxLayout; + pLayoutContent->addWidget(m_pLabTitle); + pLayoutContent->addWidget(m_pLabBody); + pLayoutContent->setStretch(1, 1); + // 主布局 + QHBoxLayout *pLayoutMain = new QHBoxLayout(m_pFrameBack); + pLayoutMain->addWidget(m_pLabIcon); + pLayoutMain->addLayout(pLayoutContent); + pLayoutMain->setAlignment(m_pLabIcon, Qt::AlignTop); + + // 初始化关闭按钮 + m_pBtnClose = new QPushButton("×", m_pFrameBack); + m_pBtnClose->setObjectName("notify-close-btn"); + m_pBtnClose->setFixedSize(24, 24); + m_pBtnClose->move(m_pFrameBack->width() - m_pBtnClose->width(), 0); + connect(m_pBtnClose, &QPushButton::clicked, this, &QObject::deleteLater); + + // 设置样式 + this->setStyleSheet(m_manager->styleSheet()); + +#ifdef Q_OS_WIN // linuxFb下,设置边框阴影有问题,故屏蔽 + // 设置边框阴影 + QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this); + shadow->setOffset(0, 0); + shadow->setBlurRadius(5); + m_pFrameBack->setGraphicsEffect(shadow); +#endif + + // 可见状态改变信号槽 + connect(this, &ArrangedWidget::visibleChanged, [this](bool visible) { + if (visible) { + // 通知显示出来过了displayTime之后隐藏并自动销毁 + int displayTime = + m_data.value("displayTime", m_manager->displayTime()).toInt(); + QTimer::singleShot(displayTime, this, [this]() { + showArranged(0); // 隐藏 + }); + } else { + // 不可见,即隐藏了,则自动销毁 + this->deleteLater(); + } + }); +} + +// 获取数据 +QVariantMap NotifyWidget::data() const { + return m_data; +} + +// 设置数据 +void NotifyWidget::setData(const QVariantMap &data) { + m_data = data; + + // 设置默认图标 + QPixmap icon; + QVariant iconv = data.value("icon"); + if (iconv.type() == QVariant::Pixmap) icon = iconv.value(); + if (iconv.type() == QVariant::String) + icon = QPixmap(iconv.toString()); + else + icon = QPixmap(m_manager->defaultIcon()); + icon = icon.scaled(QSize(32, 32), Qt::KeepAspectRatio, + Qt::SmoothTransformation); + m_pLabIcon->setPixmap(icon); + + // 设置内容 + QString title = data.value("title").toString(); + m_pLabTitle->setText(title); + + // 计算可显示行数及长度 + QString body = m_data.value("body").toString(); + if (!body.isEmpty()) { + QSize s1 = m_pLabBody->size(); + QSize s2 = m_pLabBody->fontMetrics().size(Qt::TextSingleLine, body); + int linecount = s1.height() / s2.height(); + int charcount = + qFloor(1.0 * body.size() * s1.width() / s2.width()) * linecount; + QString bodyElid = + charcount > body.size() ? body : (body.left(charcount - 1) + "…"); + m_pLabBody->setText(bodyElid); + } else { + m_pLabBody->setVisible(false); + } + + // 设置样式 + if (data.contains("styleSheet")) + setStyleSheet(data.value("styleSheet").toString()); + else if (data.contains("theme")) + setStyleSheet(m_manager->styleSheet(data.value("theme").toString())); +} + +// 队列中的剩余通知数目 +NotifyCountWidget::NotifyCountWidget(NotifyManager *manager, QWidget *parent) + : ArrangedWidget(manager, parent) { + // 初始化界面 + this->setAttribute(Qt::WA_TransparentForMouseEvents, true); + + // 初始化图标标签 + m_pLabIcon = new QLabel(this); + m_pLabIcon->setFixedSize(32, 32); + m_pLabIcon->setAlignment(Qt::AlignCenter); + // 初始化剩余数目标签 + m_pLabCount = new QLabel(this); + m_pLabCount->setObjectName("notify-count"); + m_pLabCount->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + + m_parentWidget = parent; + // 主布局 + QHBoxLayout *pLayoutMain = new QHBoxLayout(this); + pLayoutMain->addWidget(m_pLabIcon); + pLayoutMain->addWidget(m_pLabCount); + + // 文字阴影 + QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this); + shadow->setOffset(2, 2); + shadow->setBlurRadius(5); + setGraphicsEffect(shadow); + + setStyleSheet( + "#notify-count {" + "font: 20px Verdana;" + "color: #dd424d;" + "}"); + + // 设置图标 + // QPixmap icon = QPixmap(m_manager->defaultIcon()); + QPixmap icon = QPixmap(":/message.png"); + icon = icon.scaled(QSize(32, 32), Qt::KeepAspectRatio, + Qt::SmoothTransformation); + m_pLabIcon->setPixmap(icon); + + // 闪烁动画 + flickerAnim = new QPropertyAnimation(this, "windowOpacity", this); + flickerAnim->setStartValue(1); + flickerAnim->setKeyValueAt(0.25, 0.1); + flickerAnim->setKeyValueAt(0.5, 1); + flickerAnim->setEndValue(1); + flickerAnim->setDuration(2000); + flickerAnim->setLoopCount(-1); + + // 显示或隐藏的时候,显示动画 + connect(this, &ArrangedWidget::visibleChanged, [this](bool visible) { + if (visible) + flickerAnim->start(); + else + flickerAnim->stop(); + }); +} + +// 设置剩余通知数目 +void NotifyCountWidget::setCount(int count) { + m_pLabCount->setNum(count); +} diff --git a/3rdparty/QNotify/include/NotifyWidget.h b/3rdparty/QNotify/include/NotifyWidget.h new file mode 100644 index 0000000..735af61 --- /dev/null +++ b/3rdparty/QNotify/include/NotifyWidget.h @@ -0,0 +1,45 @@ +#ifndef NOTIFYWND_H +#define NOTIFYWND_H + +#include +#include +#include +#include + +#include "ArrangedWidget.h" + +// 通知框 +class NotifyWidget : public ArrangedWidget { + Q_OBJECT + +public: + explicit NotifyWidget(NotifyManager *manager, QWidget *parent = 0); + + QVariantMap data() const; // 获取数据 + void setData(const QVariantMap &data); // 设置数据 + +private: + QVariantMap m_data; // 存放数据的map + QFrame *m_pFrameBack; // 背景界面 + QLabel *m_pLabIcon; // 图标标签 + QLabel *m_pLabTitle; // 标题标签 + QLabel *m_pLabBody; // 内容标签 + QPushButton *m_pBtnClose; // 关闭按钮 +}; + +// 队列中的剩余通知数目 +class NotifyCountWidget : public ArrangedWidget { + Q_OBJECT + +public: + explicit NotifyCountWidget(NotifyManager *manager, QWidget *parent = 0); + void setCount(int count); // 设置剩余通知数目 + +private: + QLabel *m_pLabIcon; + QLabel *m_pLabCount; + QPropertyAnimation *flickerAnim; + QWidget *m_parentWidget; +}; + +#endif // NOTIFYWND_H diff --git a/3rdparty/QNotify/include/QNotify_global.h b/3rdparty/QNotify/include/QNotify_global.h new file mode 100644 index 0000000..df5c7b7 --- /dev/null +++ b/3rdparty/QNotify/include/QNotify_global.h @@ -0,0 +1,12 @@ +#ifndef QNOTIFY_GLOBAL_H +#define QNOTIFY_GLOBAL_H + +#include + +#if defined(QNOTIFY_LIBRARY) +#define QNOTIFY_EXPORT Q_DECL_EXPORT +#else +#define QNOTIFY_EXPORT Q_DECL_IMPORT +#endif + +#endif // QNOTIFY_GLOBAL_H diff --git a/3rdparty/QNotify/lib/QNotify.lib b/3rdparty/QNotify/lib/QNotify.lib new file mode 100644 index 0000000..8cbb4e7 Binary files /dev/null and b/3rdparty/QNotify/lib/QNotify.lib differ diff --git a/3rdparty/QNotify/lib/QNotifyd.lib b/3rdparty/QNotify/lib/QNotifyd.lib new file mode 100644 index 0000000..24de8f8 Binary files /dev/null and b/3rdparty/QNotify/lib/QNotifyd.lib differ diff --git a/ffmpeg/LICENSE b/3rdparty/ffmpeg/LICENSE similarity index 100% rename from ffmpeg/LICENSE rename to 3rdparty/ffmpeg/LICENSE diff --git a/ffmpeg/README.txt b/3rdparty/ffmpeg/README.txt similarity index 100% rename from ffmpeg/README.txt rename to 3rdparty/ffmpeg/README.txt diff --git a/ffmpeg/bin/avcodec-60.dll b/3rdparty/ffmpeg/bin/avcodec-60.dll similarity index 100% rename from ffmpeg/bin/avcodec-60.dll rename to 3rdparty/ffmpeg/bin/avcodec-60.dll diff --git a/ffmpeg/bin/avdevice-60.dll b/3rdparty/ffmpeg/bin/avdevice-60.dll similarity index 100% rename from ffmpeg/bin/avdevice-60.dll rename to 3rdparty/ffmpeg/bin/avdevice-60.dll diff --git a/ffmpeg/bin/avfilter-9.dll b/3rdparty/ffmpeg/bin/avfilter-9.dll similarity index 100% rename from ffmpeg/bin/avfilter-9.dll rename to 3rdparty/ffmpeg/bin/avfilter-9.dll diff --git a/ffmpeg/bin/avformat-60.dll b/3rdparty/ffmpeg/bin/avformat-60.dll similarity index 100% rename from ffmpeg/bin/avformat-60.dll rename to 3rdparty/ffmpeg/bin/avformat-60.dll diff --git a/ffmpeg/bin/avutil-58.dll b/3rdparty/ffmpeg/bin/avutil-58.dll similarity index 100% rename from ffmpeg/bin/avutil-58.dll rename to 3rdparty/ffmpeg/bin/avutil-58.dll diff --git a/ffmpeg/bin/postproc-57.dll b/3rdparty/ffmpeg/bin/postproc-57.dll similarity index 100% rename from ffmpeg/bin/postproc-57.dll rename to 3rdparty/ffmpeg/bin/postproc-57.dll diff --git a/ffmpeg/bin/swresample-4.dll b/3rdparty/ffmpeg/bin/swresample-4.dll similarity index 100% rename from ffmpeg/bin/swresample-4.dll rename to 3rdparty/ffmpeg/bin/swresample-4.dll diff --git a/ffmpeg/bin/swscale-7.dll b/3rdparty/ffmpeg/bin/swscale-7.dll similarity index 100% rename from ffmpeg/bin/swscale-7.dll rename to 3rdparty/ffmpeg/bin/swscale-7.dll diff --git a/ffmpeg/doc/bootstrap.min.css b/3rdparty/ffmpeg/doc/bootstrap.min.css similarity index 100% rename from ffmpeg/doc/bootstrap.min.css rename to 3rdparty/ffmpeg/doc/bootstrap.min.css diff --git a/ffmpeg/doc/community.html b/3rdparty/ffmpeg/doc/community.html similarity index 100% rename from ffmpeg/doc/community.html rename to 3rdparty/ffmpeg/doc/community.html diff --git a/ffmpeg/doc/default.css b/3rdparty/ffmpeg/doc/default.css similarity index 100% rename from ffmpeg/doc/default.css rename to 3rdparty/ffmpeg/doc/default.css diff --git a/ffmpeg/doc/developer.html b/3rdparty/ffmpeg/doc/developer.html similarity index 100% rename from ffmpeg/doc/developer.html rename to 3rdparty/ffmpeg/doc/developer.html diff --git a/ffmpeg/doc/faq.html b/3rdparty/ffmpeg/doc/faq.html similarity index 100% rename from ffmpeg/doc/faq.html rename to 3rdparty/ffmpeg/doc/faq.html diff --git a/ffmpeg/doc/fate.html b/3rdparty/ffmpeg/doc/fate.html similarity index 100% rename from ffmpeg/doc/fate.html rename to 3rdparty/ffmpeg/doc/fate.html diff --git a/ffmpeg/doc/ffmpeg-all.html b/3rdparty/ffmpeg/doc/ffmpeg-all.html similarity index 100% rename from ffmpeg/doc/ffmpeg-all.html rename to 3rdparty/ffmpeg/doc/ffmpeg-all.html diff --git a/ffmpeg/doc/ffmpeg-bitstream-filters.html b/3rdparty/ffmpeg/doc/ffmpeg-bitstream-filters.html similarity index 100% rename from ffmpeg/doc/ffmpeg-bitstream-filters.html rename to 3rdparty/ffmpeg/doc/ffmpeg-bitstream-filters.html diff --git a/ffmpeg/doc/ffmpeg-codecs.html b/3rdparty/ffmpeg/doc/ffmpeg-codecs.html similarity index 100% rename from ffmpeg/doc/ffmpeg-codecs.html rename to 3rdparty/ffmpeg/doc/ffmpeg-codecs.html diff --git a/ffmpeg/doc/ffmpeg-devices.html b/3rdparty/ffmpeg/doc/ffmpeg-devices.html similarity index 100% rename from ffmpeg/doc/ffmpeg-devices.html rename to 3rdparty/ffmpeg/doc/ffmpeg-devices.html diff --git a/ffmpeg/doc/ffmpeg-filters.html b/3rdparty/ffmpeg/doc/ffmpeg-filters.html similarity index 100% rename from ffmpeg/doc/ffmpeg-filters.html rename to 3rdparty/ffmpeg/doc/ffmpeg-filters.html diff --git a/ffmpeg/doc/ffmpeg-formats.html b/3rdparty/ffmpeg/doc/ffmpeg-formats.html similarity index 100% rename from ffmpeg/doc/ffmpeg-formats.html rename to 3rdparty/ffmpeg/doc/ffmpeg-formats.html diff --git a/ffmpeg/doc/ffmpeg-protocols.html b/3rdparty/ffmpeg/doc/ffmpeg-protocols.html similarity index 100% rename from ffmpeg/doc/ffmpeg-protocols.html rename to 3rdparty/ffmpeg/doc/ffmpeg-protocols.html diff --git a/ffmpeg/doc/ffmpeg-resampler.html b/3rdparty/ffmpeg/doc/ffmpeg-resampler.html similarity index 100% rename from ffmpeg/doc/ffmpeg-resampler.html rename to 3rdparty/ffmpeg/doc/ffmpeg-resampler.html diff --git a/ffmpeg/doc/ffmpeg-scaler.html b/3rdparty/ffmpeg/doc/ffmpeg-scaler.html similarity index 100% rename from ffmpeg/doc/ffmpeg-scaler.html rename to 3rdparty/ffmpeg/doc/ffmpeg-scaler.html diff --git a/ffmpeg/doc/ffmpeg-utils.html b/3rdparty/ffmpeg/doc/ffmpeg-utils.html similarity index 100% rename from ffmpeg/doc/ffmpeg-utils.html rename to 3rdparty/ffmpeg/doc/ffmpeg-utils.html diff --git a/ffmpeg/doc/ffmpeg.html b/3rdparty/ffmpeg/doc/ffmpeg.html similarity index 100% rename from ffmpeg/doc/ffmpeg.html rename to 3rdparty/ffmpeg/doc/ffmpeg.html diff --git a/ffmpeg/doc/ffplay-all.html b/3rdparty/ffmpeg/doc/ffplay-all.html similarity index 100% rename from ffmpeg/doc/ffplay-all.html rename to 3rdparty/ffmpeg/doc/ffplay-all.html diff --git a/ffmpeg/doc/ffplay.html b/3rdparty/ffmpeg/doc/ffplay.html similarity index 100% rename from ffmpeg/doc/ffplay.html rename to 3rdparty/ffmpeg/doc/ffplay.html diff --git a/ffmpeg/doc/ffprobe-all.html b/3rdparty/ffmpeg/doc/ffprobe-all.html similarity index 100% rename from ffmpeg/doc/ffprobe-all.html rename to 3rdparty/ffmpeg/doc/ffprobe-all.html diff --git a/ffmpeg/doc/ffprobe.html b/3rdparty/ffmpeg/doc/ffprobe.html similarity index 100% rename from ffmpeg/doc/ffprobe.html rename to 3rdparty/ffmpeg/doc/ffprobe.html diff --git a/ffmpeg/doc/general.html b/3rdparty/ffmpeg/doc/general.html similarity index 100% rename from ffmpeg/doc/general.html rename to 3rdparty/ffmpeg/doc/general.html diff --git a/ffmpeg/doc/git-howto.html b/3rdparty/ffmpeg/doc/git-howto.html similarity index 100% rename from ffmpeg/doc/git-howto.html rename to 3rdparty/ffmpeg/doc/git-howto.html diff --git a/ffmpeg/doc/libavcodec.html b/3rdparty/ffmpeg/doc/libavcodec.html similarity index 100% rename from ffmpeg/doc/libavcodec.html rename to 3rdparty/ffmpeg/doc/libavcodec.html diff --git a/ffmpeg/doc/libavdevice.html b/3rdparty/ffmpeg/doc/libavdevice.html similarity index 100% rename from ffmpeg/doc/libavdevice.html rename to 3rdparty/ffmpeg/doc/libavdevice.html diff --git a/ffmpeg/doc/libavfilter.html b/3rdparty/ffmpeg/doc/libavfilter.html similarity index 100% rename from ffmpeg/doc/libavfilter.html rename to 3rdparty/ffmpeg/doc/libavfilter.html diff --git a/ffmpeg/doc/libavformat.html b/3rdparty/ffmpeg/doc/libavformat.html similarity index 100% rename from ffmpeg/doc/libavformat.html rename to 3rdparty/ffmpeg/doc/libavformat.html diff --git a/ffmpeg/doc/libavutil.html b/3rdparty/ffmpeg/doc/libavutil.html similarity index 100% rename from ffmpeg/doc/libavutil.html rename to 3rdparty/ffmpeg/doc/libavutil.html diff --git a/ffmpeg/doc/libswresample.html b/3rdparty/ffmpeg/doc/libswresample.html similarity index 100% rename from ffmpeg/doc/libswresample.html rename to 3rdparty/ffmpeg/doc/libswresample.html diff --git a/ffmpeg/doc/libswscale.html b/3rdparty/ffmpeg/doc/libswscale.html similarity index 100% rename from ffmpeg/doc/libswscale.html rename to 3rdparty/ffmpeg/doc/libswscale.html diff --git a/ffmpeg/doc/mailing-list-faq.html b/3rdparty/ffmpeg/doc/mailing-list-faq.html similarity index 100% rename from ffmpeg/doc/mailing-list-faq.html rename to 3rdparty/ffmpeg/doc/mailing-list-faq.html diff --git a/ffmpeg/doc/nut.html b/3rdparty/ffmpeg/doc/nut.html similarity index 100% rename from ffmpeg/doc/nut.html rename to 3rdparty/ffmpeg/doc/nut.html diff --git a/ffmpeg/doc/platform.html b/3rdparty/ffmpeg/doc/platform.html similarity index 100% rename from ffmpeg/doc/platform.html rename to 3rdparty/ffmpeg/doc/platform.html diff --git a/ffmpeg/doc/style.min.css b/3rdparty/ffmpeg/doc/style.min.css similarity index 100% rename from ffmpeg/doc/style.min.css rename to 3rdparty/ffmpeg/doc/style.min.css diff --git a/ffmpeg/include/libavcodec/ac3_parser.h b/3rdparty/ffmpeg/include/libavcodec/ac3_parser.h similarity index 100% rename from ffmpeg/include/libavcodec/ac3_parser.h rename to 3rdparty/ffmpeg/include/libavcodec/ac3_parser.h diff --git a/ffmpeg/include/libavcodec/adts_parser.h b/3rdparty/ffmpeg/include/libavcodec/adts_parser.h similarity index 100% rename from ffmpeg/include/libavcodec/adts_parser.h rename to 3rdparty/ffmpeg/include/libavcodec/adts_parser.h diff --git a/ffmpeg/include/libavcodec/avcodec.h b/3rdparty/ffmpeg/include/libavcodec/avcodec.h similarity index 100% rename from ffmpeg/include/libavcodec/avcodec.h rename to 3rdparty/ffmpeg/include/libavcodec/avcodec.h diff --git a/ffmpeg/include/libavcodec/avdct.h b/3rdparty/ffmpeg/include/libavcodec/avdct.h similarity index 100% rename from ffmpeg/include/libavcodec/avdct.h rename to 3rdparty/ffmpeg/include/libavcodec/avdct.h diff --git a/ffmpeg/include/libavcodec/avfft.h b/3rdparty/ffmpeg/include/libavcodec/avfft.h similarity index 100% rename from ffmpeg/include/libavcodec/avfft.h rename to 3rdparty/ffmpeg/include/libavcodec/avfft.h diff --git a/ffmpeg/include/libavcodec/bsf.h b/3rdparty/ffmpeg/include/libavcodec/bsf.h similarity index 100% rename from ffmpeg/include/libavcodec/bsf.h rename to 3rdparty/ffmpeg/include/libavcodec/bsf.h diff --git a/ffmpeg/include/libavcodec/codec.h b/3rdparty/ffmpeg/include/libavcodec/codec.h similarity index 100% rename from ffmpeg/include/libavcodec/codec.h rename to 3rdparty/ffmpeg/include/libavcodec/codec.h diff --git a/ffmpeg/include/libavcodec/codec_desc.h b/3rdparty/ffmpeg/include/libavcodec/codec_desc.h similarity index 100% rename from ffmpeg/include/libavcodec/codec_desc.h rename to 3rdparty/ffmpeg/include/libavcodec/codec_desc.h diff --git a/ffmpeg/include/libavcodec/codec_id.h b/3rdparty/ffmpeg/include/libavcodec/codec_id.h similarity index 100% rename from ffmpeg/include/libavcodec/codec_id.h rename to 3rdparty/ffmpeg/include/libavcodec/codec_id.h diff --git a/ffmpeg/include/libavcodec/codec_par.h b/3rdparty/ffmpeg/include/libavcodec/codec_par.h similarity index 100% rename from ffmpeg/include/libavcodec/codec_par.h rename to 3rdparty/ffmpeg/include/libavcodec/codec_par.h diff --git a/ffmpeg/include/libavcodec/d3d11va.h b/3rdparty/ffmpeg/include/libavcodec/d3d11va.h similarity index 100% rename from ffmpeg/include/libavcodec/d3d11va.h rename to 3rdparty/ffmpeg/include/libavcodec/d3d11va.h diff --git a/ffmpeg/include/libavcodec/defs.h b/3rdparty/ffmpeg/include/libavcodec/defs.h similarity index 100% rename from ffmpeg/include/libavcodec/defs.h rename to 3rdparty/ffmpeg/include/libavcodec/defs.h diff --git a/ffmpeg/include/libavcodec/dirac.h b/3rdparty/ffmpeg/include/libavcodec/dirac.h similarity index 100% rename from ffmpeg/include/libavcodec/dirac.h rename to 3rdparty/ffmpeg/include/libavcodec/dirac.h diff --git a/ffmpeg/include/libavcodec/dv_profile.h b/3rdparty/ffmpeg/include/libavcodec/dv_profile.h similarity index 100% rename from ffmpeg/include/libavcodec/dv_profile.h rename to 3rdparty/ffmpeg/include/libavcodec/dv_profile.h diff --git a/ffmpeg/include/libavcodec/dxva2.h b/3rdparty/ffmpeg/include/libavcodec/dxva2.h similarity index 100% rename from ffmpeg/include/libavcodec/dxva2.h rename to 3rdparty/ffmpeg/include/libavcodec/dxva2.h diff --git a/ffmpeg/include/libavcodec/jni.h b/3rdparty/ffmpeg/include/libavcodec/jni.h similarity index 100% rename from ffmpeg/include/libavcodec/jni.h rename to 3rdparty/ffmpeg/include/libavcodec/jni.h diff --git a/ffmpeg/include/libavcodec/mediacodec.h b/3rdparty/ffmpeg/include/libavcodec/mediacodec.h similarity index 100% rename from ffmpeg/include/libavcodec/mediacodec.h rename to 3rdparty/ffmpeg/include/libavcodec/mediacodec.h diff --git a/ffmpeg/include/libavcodec/packet.h b/3rdparty/ffmpeg/include/libavcodec/packet.h similarity index 100% rename from ffmpeg/include/libavcodec/packet.h rename to 3rdparty/ffmpeg/include/libavcodec/packet.h diff --git a/ffmpeg/include/libavcodec/qsv.h b/3rdparty/ffmpeg/include/libavcodec/qsv.h similarity index 100% rename from ffmpeg/include/libavcodec/qsv.h rename to 3rdparty/ffmpeg/include/libavcodec/qsv.h diff --git a/ffmpeg/include/libavcodec/vdpau.h b/3rdparty/ffmpeg/include/libavcodec/vdpau.h similarity index 100% rename from ffmpeg/include/libavcodec/vdpau.h rename to 3rdparty/ffmpeg/include/libavcodec/vdpau.h diff --git a/ffmpeg/include/libavcodec/version.h b/3rdparty/ffmpeg/include/libavcodec/version.h similarity index 100% rename from ffmpeg/include/libavcodec/version.h rename to 3rdparty/ffmpeg/include/libavcodec/version.h diff --git a/ffmpeg/include/libavcodec/version_major.h b/3rdparty/ffmpeg/include/libavcodec/version_major.h similarity index 100% rename from ffmpeg/include/libavcodec/version_major.h rename to 3rdparty/ffmpeg/include/libavcodec/version_major.h diff --git a/ffmpeg/include/libavcodec/videotoolbox.h b/3rdparty/ffmpeg/include/libavcodec/videotoolbox.h similarity index 100% rename from ffmpeg/include/libavcodec/videotoolbox.h rename to 3rdparty/ffmpeg/include/libavcodec/videotoolbox.h diff --git a/ffmpeg/include/libavcodec/vorbis_parser.h b/3rdparty/ffmpeg/include/libavcodec/vorbis_parser.h similarity index 100% rename from ffmpeg/include/libavcodec/vorbis_parser.h rename to 3rdparty/ffmpeg/include/libavcodec/vorbis_parser.h diff --git a/ffmpeg/include/libavcodec/xvmc.h b/3rdparty/ffmpeg/include/libavcodec/xvmc.h similarity index 100% rename from ffmpeg/include/libavcodec/xvmc.h rename to 3rdparty/ffmpeg/include/libavcodec/xvmc.h diff --git a/ffmpeg/include/libavdevice/avdevice.h b/3rdparty/ffmpeg/include/libavdevice/avdevice.h similarity index 100% rename from ffmpeg/include/libavdevice/avdevice.h rename to 3rdparty/ffmpeg/include/libavdevice/avdevice.h diff --git a/ffmpeg/include/libavdevice/version.h b/3rdparty/ffmpeg/include/libavdevice/version.h similarity index 100% rename from ffmpeg/include/libavdevice/version.h rename to 3rdparty/ffmpeg/include/libavdevice/version.h diff --git a/ffmpeg/include/libavdevice/version_major.h b/3rdparty/ffmpeg/include/libavdevice/version_major.h similarity index 100% rename from ffmpeg/include/libavdevice/version_major.h rename to 3rdparty/ffmpeg/include/libavdevice/version_major.h diff --git a/ffmpeg/include/libavfilter/avfilter.h b/3rdparty/ffmpeg/include/libavfilter/avfilter.h similarity index 100% rename from ffmpeg/include/libavfilter/avfilter.h rename to 3rdparty/ffmpeg/include/libavfilter/avfilter.h diff --git a/ffmpeg/include/libavfilter/buffersink.h b/3rdparty/ffmpeg/include/libavfilter/buffersink.h similarity index 100% rename from ffmpeg/include/libavfilter/buffersink.h rename to 3rdparty/ffmpeg/include/libavfilter/buffersink.h diff --git a/ffmpeg/include/libavfilter/buffersrc.h b/3rdparty/ffmpeg/include/libavfilter/buffersrc.h similarity index 100% rename from ffmpeg/include/libavfilter/buffersrc.h rename to 3rdparty/ffmpeg/include/libavfilter/buffersrc.h diff --git a/ffmpeg/include/libavfilter/version.h b/3rdparty/ffmpeg/include/libavfilter/version.h similarity index 100% rename from ffmpeg/include/libavfilter/version.h rename to 3rdparty/ffmpeg/include/libavfilter/version.h diff --git a/ffmpeg/include/libavfilter/version_major.h b/3rdparty/ffmpeg/include/libavfilter/version_major.h similarity index 100% rename from ffmpeg/include/libavfilter/version_major.h rename to 3rdparty/ffmpeg/include/libavfilter/version_major.h diff --git a/ffmpeg/include/libavformat/avformat.h b/3rdparty/ffmpeg/include/libavformat/avformat.h similarity index 100% rename from ffmpeg/include/libavformat/avformat.h rename to 3rdparty/ffmpeg/include/libavformat/avformat.h diff --git a/ffmpeg/include/libavformat/avio.h b/3rdparty/ffmpeg/include/libavformat/avio.h similarity index 100% rename from ffmpeg/include/libavformat/avio.h rename to 3rdparty/ffmpeg/include/libavformat/avio.h diff --git a/ffmpeg/include/libavformat/version.h b/3rdparty/ffmpeg/include/libavformat/version.h similarity index 100% rename from ffmpeg/include/libavformat/version.h rename to 3rdparty/ffmpeg/include/libavformat/version.h diff --git a/ffmpeg/include/libavformat/version_major.h b/3rdparty/ffmpeg/include/libavformat/version_major.h similarity index 100% rename from ffmpeg/include/libavformat/version_major.h rename to 3rdparty/ffmpeg/include/libavformat/version_major.h diff --git a/ffmpeg/include/libavutil/adler32.h b/3rdparty/ffmpeg/include/libavutil/adler32.h similarity index 100% rename from ffmpeg/include/libavutil/adler32.h rename to 3rdparty/ffmpeg/include/libavutil/adler32.h diff --git a/ffmpeg/include/libavutil/aes.h b/3rdparty/ffmpeg/include/libavutil/aes.h similarity index 100% rename from ffmpeg/include/libavutil/aes.h rename to 3rdparty/ffmpeg/include/libavutil/aes.h diff --git a/ffmpeg/include/libavutil/aes_ctr.h b/3rdparty/ffmpeg/include/libavutil/aes_ctr.h similarity index 100% rename from ffmpeg/include/libavutil/aes_ctr.h rename to 3rdparty/ffmpeg/include/libavutil/aes_ctr.h diff --git a/ffmpeg/include/libavutil/ambient_viewing_environment.h b/3rdparty/ffmpeg/include/libavutil/ambient_viewing_environment.h similarity index 100% rename from ffmpeg/include/libavutil/ambient_viewing_environment.h rename to 3rdparty/ffmpeg/include/libavutil/ambient_viewing_environment.h diff --git a/ffmpeg/include/libavutil/attributes.h b/3rdparty/ffmpeg/include/libavutil/attributes.h similarity index 100% rename from ffmpeg/include/libavutil/attributes.h rename to 3rdparty/ffmpeg/include/libavutil/attributes.h diff --git a/ffmpeg/include/libavutil/audio_fifo.h b/3rdparty/ffmpeg/include/libavutil/audio_fifo.h similarity index 100% rename from ffmpeg/include/libavutil/audio_fifo.h rename to 3rdparty/ffmpeg/include/libavutil/audio_fifo.h diff --git a/ffmpeg/include/libavutil/avassert.h b/3rdparty/ffmpeg/include/libavutil/avassert.h similarity index 100% rename from ffmpeg/include/libavutil/avassert.h rename to 3rdparty/ffmpeg/include/libavutil/avassert.h diff --git a/ffmpeg/include/libavutil/avconfig.h b/3rdparty/ffmpeg/include/libavutil/avconfig.h similarity index 100% rename from ffmpeg/include/libavutil/avconfig.h rename to 3rdparty/ffmpeg/include/libavutil/avconfig.h diff --git a/ffmpeg/include/libavutil/avstring.h b/3rdparty/ffmpeg/include/libavutil/avstring.h similarity index 100% rename from ffmpeg/include/libavutil/avstring.h rename to 3rdparty/ffmpeg/include/libavutil/avstring.h diff --git a/ffmpeg/include/libavutil/avutil.h b/3rdparty/ffmpeg/include/libavutil/avutil.h similarity index 100% rename from ffmpeg/include/libavutil/avutil.h rename to 3rdparty/ffmpeg/include/libavutil/avutil.h diff --git a/ffmpeg/include/libavutil/base64.h b/3rdparty/ffmpeg/include/libavutil/base64.h similarity index 100% rename from ffmpeg/include/libavutil/base64.h rename to 3rdparty/ffmpeg/include/libavutil/base64.h diff --git a/ffmpeg/include/libavutil/blowfish.h b/3rdparty/ffmpeg/include/libavutil/blowfish.h similarity index 100% rename from ffmpeg/include/libavutil/blowfish.h rename to 3rdparty/ffmpeg/include/libavutil/blowfish.h diff --git a/ffmpeg/include/libavutil/bprint.h b/3rdparty/ffmpeg/include/libavutil/bprint.h similarity index 100% rename from ffmpeg/include/libavutil/bprint.h rename to 3rdparty/ffmpeg/include/libavutil/bprint.h diff --git a/ffmpeg/include/libavutil/bswap.h b/3rdparty/ffmpeg/include/libavutil/bswap.h similarity index 100% rename from ffmpeg/include/libavutil/bswap.h rename to 3rdparty/ffmpeg/include/libavutil/bswap.h diff --git a/ffmpeg/include/libavutil/buffer.h b/3rdparty/ffmpeg/include/libavutil/buffer.h similarity index 100% rename from ffmpeg/include/libavutil/buffer.h rename to 3rdparty/ffmpeg/include/libavutil/buffer.h diff --git a/ffmpeg/include/libavutil/camellia.h b/3rdparty/ffmpeg/include/libavutil/camellia.h similarity index 100% rename from ffmpeg/include/libavutil/camellia.h rename to 3rdparty/ffmpeg/include/libavutil/camellia.h diff --git a/ffmpeg/include/libavutil/cast5.h b/3rdparty/ffmpeg/include/libavutil/cast5.h similarity index 100% rename from ffmpeg/include/libavutil/cast5.h rename to 3rdparty/ffmpeg/include/libavutil/cast5.h diff --git a/ffmpeg/include/libavutil/channel_layout.h b/3rdparty/ffmpeg/include/libavutil/channel_layout.h similarity index 100% rename from ffmpeg/include/libavutil/channel_layout.h rename to 3rdparty/ffmpeg/include/libavutil/channel_layout.h diff --git a/ffmpeg/include/libavutil/common.h b/3rdparty/ffmpeg/include/libavutil/common.h similarity index 100% rename from ffmpeg/include/libavutil/common.h rename to 3rdparty/ffmpeg/include/libavutil/common.h diff --git a/ffmpeg/include/libavutil/cpu.h b/3rdparty/ffmpeg/include/libavutil/cpu.h similarity index 100% rename from ffmpeg/include/libavutil/cpu.h rename to 3rdparty/ffmpeg/include/libavutil/cpu.h diff --git a/ffmpeg/include/libavutil/crc.h b/3rdparty/ffmpeg/include/libavutil/crc.h similarity index 100% rename from ffmpeg/include/libavutil/crc.h rename to 3rdparty/ffmpeg/include/libavutil/crc.h diff --git a/ffmpeg/include/libavutil/csp.h b/3rdparty/ffmpeg/include/libavutil/csp.h similarity index 100% rename from ffmpeg/include/libavutil/csp.h rename to 3rdparty/ffmpeg/include/libavutil/csp.h diff --git a/ffmpeg/include/libavutil/des.h b/3rdparty/ffmpeg/include/libavutil/des.h similarity index 100% rename from ffmpeg/include/libavutil/des.h rename to 3rdparty/ffmpeg/include/libavutil/des.h diff --git a/ffmpeg/include/libavutil/detection_bbox.h b/3rdparty/ffmpeg/include/libavutil/detection_bbox.h similarity index 100% rename from ffmpeg/include/libavutil/detection_bbox.h rename to 3rdparty/ffmpeg/include/libavutil/detection_bbox.h diff --git a/ffmpeg/include/libavutil/dict.h b/3rdparty/ffmpeg/include/libavutil/dict.h similarity index 100% rename from ffmpeg/include/libavutil/dict.h rename to 3rdparty/ffmpeg/include/libavutil/dict.h diff --git a/ffmpeg/include/libavutil/display.h b/3rdparty/ffmpeg/include/libavutil/display.h similarity index 100% rename from ffmpeg/include/libavutil/display.h rename to 3rdparty/ffmpeg/include/libavutil/display.h diff --git a/ffmpeg/include/libavutil/dovi_meta.h b/3rdparty/ffmpeg/include/libavutil/dovi_meta.h similarity index 100% rename from ffmpeg/include/libavutil/dovi_meta.h rename to 3rdparty/ffmpeg/include/libavutil/dovi_meta.h diff --git a/ffmpeg/include/libavutil/downmix_info.h b/3rdparty/ffmpeg/include/libavutil/downmix_info.h similarity index 100% rename from ffmpeg/include/libavutil/downmix_info.h rename to 3rdparty/ffmpeg/include/libavutil/downmix_info.h diff --git a/ffmpeg/include/libavutil/encryption_info.h b/3rdparty/ffmpeg/include/libavutil/encryption_info.h similarity index 100% rename from ffmpeg/include/libavutil/encryption_info.h rename to 3rdparty/ffmpeg/include/libavutil/encryption_info.h diff --git a/ffmpeg/include/libavutil/error.h b/3rdparty/ffmpeg/include/libavutil/error.h similarity index 100% rename from ffmpeg/include/libavutil/error.h rename to 3rdparty/ffmpeg/include/libavutil/error.h diff --git a/ffmpeg/include/libavutil/eval.h b/3rdparty/ffmpeg/include/libavutil/eval.h similarity index 100% rename from ffmpeg/include/libavutil/eval.h rename to 3rdparty/ffmpeg/include/libavutil/eval.h diff --git a/ffmpeg/include/libavutil/executor.h b/3rdparty/ffmpeg/include/libavutil/executor.h similarity index 100% rename from ffmpeg/include/libavutil/executor.h rename to 3rdparty/ffmpeg/include/libavutil/executor.h diff --git a/ffmpeg/include/libavutil/ffversion.h b/3rdparty/ffmpeg/include/libavutil/ffversion.h similarity index 100% rename from ffmpeg/include/libavutil/ffversion.h rename to 3rdparty/ffmpeg/include/libavutil/ffversion.h diff --git a/ffmpeg/include/libavutil/fifo.h b/3rdparty/ffmpeg/include/libavutil/fifo.h similarity index 100% rename from ffmpeg/include/libavutil/fifo.h rename to 3rdparty/ffmpeg/include/libavutil/fifo.h diff --git a/ffmpeg/include/libavutil/file.h b/3rdparty/ffmpeg/include/libavutil/file.h similarity index 100% rename from ffmpeg/include/libavutil/file.h rename to 3rdparty/ffmpeg/include/libavutil/file.h diff --git a/ffmpeg/include/libavutil/film_grain_params.h b/3rdparty/ffmpeg/include/libavutil/film_grain_params.h similarity index 100% rename from ffmpeg/include/libavutil/film_grain_params.h rename to 3rdparty/ffmpeg/include/libavutil/film_grain_params.h diff --git a/ffmpeg/include/libavutil/frame.h b/3rdparty/ffmpeg/include/libavutil/frame.h similarity index 100% rename from ffmpeg/include/libavutil/frame.h rename to 3rdparty/ffmpeg/include/libavutil/frame.h diff --git a/ffmpeg/include/libavutil/hash.h b/3rdparty/ffmpeg/include/libavutil/hash.h similarity index 100% rename from ffmpeg/include/libavutil/hash.h rename to 3rdparty/ffmpeg/include/libavutil/hash.h diff --git a/ffmpeg/include/libavutil/hdr_dynamic_metadata.h b/3rdparty/ffmpeg/include/libavutil/hdr_dynamic_metadata.h similarity index 100% rename from ffmpeg/include/libavutil/hdr_dynamic_metadata.h rename to 3rdparty/ffmpeg/include/libavutil/hdr_dynamic_metadata.h diff --git a/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h b/3rdparty/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h similarity index 100% rename from ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h rename to 3rdparty/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h diff --git a/ffmpeg/include/libavutil/hmac.h b/3rdparty/ffmpeg/include/libavutil/hmac.h similarity index 100% rename from ffmpeg/include/libavutil/hmac.h rename to 3rdparty/ffmpeg/include/libavutil/hmac.h diff --git a/ffmpeg/include/libavutil/hwcontext.h b/3rdparty/ffmpeg/include/libavutil/hwcontext.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext.h diff --git a/ffmpeg/include/libavutil/hwcontext_cuda.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_cuda.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_cuda.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_cuda.h diff --git a/ffmpeg/include/libavutil/hwcontext_d3d11va.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_d3d11va.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_d3d11va.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_d3d11va.h diff --git a/ffmpeg/include/libavutil/hwcontext_drm.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_drm.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_drm.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_drm.h diff --git a/ffmpeg/include/libavutil/hwcontext_dxva2.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_dxva2.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_dxva2.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_dxva2.h diff --git a/ffmpeg/include/libavutil/hwcontext_mediacodec.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_mediacodec.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_mediacodec.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_mediacodec.h diff --git a/ffmpeg/include/libavutil/hwcontext_opencl.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_opencl.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_opencl.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_opencl.h diff --git a/ffmpeg/include/libavutil/hwcontext_qsv.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_qsv.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_qsv.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_qsv.h diff --git a/ffmpeg/include/libavutil/hwcontext_vaapi.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_vaapi.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_vaapi.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_vaapi.h diff --git a/ffmpeg/include/libavutil/hwcontext_vdpau.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_vdpau.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_vdpau.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_vdpau.h diff --git a/ffmpeg/include/libavutil/hwcontext_videotoolbox.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_videotoolbox.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_videotoolbox.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_videotoolbox.h diff --git a/ffmpeg/include/libavutil/hwcontext_vulkan.h b/3rdparty/ffmpeg/include/libavutil/hwcontext_vulkan.h similarity index 100% rename from ffmpeg/include/libavutil/hwcontext_vulkan.h rename to 3rdparty/ffmpeg/include/libavutil/hwcontext_vulkan.h diff --git a/ffmpeg/include/libavutil/imgutils.h b/3rdparty/ffmpeg/include/libavutil/imgutils.h similarity index 100% rename from ffmpeg/include/libavutil/imgutils.h rename to 3rdparty/ffmpeg/include/libavutil/imgutils.h diff --git a/ffmpeg/include/libavutil/intfloat.h b/3rdparty/ffmpeg/include/libavutil/intfloat.h similarity index 100% rename from ffmpeg/include/libavutil/intfloat.h rename to 3rdparty/ffmpeg/include/libavutil/intfloat.h diff --git a/ffmpeg/include/libavutil/intreadwrite.h b/3rdparty/ffmpeg/include/libavutil/intreadwrite.h similarity index 100% rename from ffmpeg/include/libavutil/intreadwrite.h rename to 3rdparty/ffmpeg/include/libavutil/intreadwrite.h diff --git a/ffmpeg/include/libavutil/lfg.h b/3rdparty/ffmpeg/include/libavutil/lfg.h similarity index 100% rename from ffmpeg/include/libavutil/lfg.h rename to 3rdparty/ffmpeg/include/libavutil/lfg.h diff --git a/ffmpeg/include/libavutil/log.h b/3rdparty/ffmpeg/include/libavutil/log.h similarity index 100% rename from ffmpeg/include/libavutil/log.h rename to 3rdparty/ffmpeg/include/libavutil/log.h diff --git a/ffmpeg/include/libavutil/lzo.h b/3rdparty/ffmpeg/include/libavutil/lzo.h similarity index 100% rename from ffmpeg/include/libavutil/lzo.h rename to 3rdparty/ffmpeg/include/libavutil/lzo.h diff --git a/ffmpeg/include/libavutil/macros.h b/3rdparty/ffmpeg/include/libavutil/macros.h similarity index 100% rename from ffmpeg/include/libavutil/macros.h rename to 3rdparty/ffmpeg/include/libavutil/macros.h diff --git a/ffmpeg/include/libavutil/mastering_display_metadata.h b/3rdparty/ffmpeg/include/libavutil/mastering_display_metadata.h similarity index 100% rename from ffmpeg/include/libavutil/mastering_display_metadata.h rename to 3rdparty/ffmpeg/include/libavutil/mastering_display_metadata.h diff --git a/ffmpeg/include/libavutil/mathematics.h b/3rdparty/ffmpeg/include/libavutil/mathematics.h similarity index 100% rename from ffmpeg/include/libavutil/mathematics.h rename to 3rdparty/ffmpeg/include/libavutil/mathematics.h diff --git a/ffmpeg/include/libavutil/md5.h b/3rdparty/ffmpeg/include/libavutil/md5.h similarity index 100% rename from ffmpeg/include/libavutil/md5.h rename to 3rdparty/ffmpeg/include/libavutil/md5.h diff --git a/ffmpeg/include/libavutil/mem.h b/3rdparty/ffmpeg/include/libavutil/mem.h similarity index 100% rename from ffmpeg/include/libavutil/mem.h rename to 3rdparty/ffmpeg/include/libavutil/mem.h diff --git a/ffmpeg/include/libavutil/motion_vector.h b/3rdparty/ffmpeg/include/libavutil/motion_vector.h similarity index 100% rename from ffmpeg/include/libavutil/motion_vector.h rename to 3rdparty/ffmpeg/include/libavutil/motion_vector.h diff --git a/ffmpeg/include/libavutil/murmur3.h b/3rdparty/ffmpeg/include/libavutil/murmur3.h similarity index 100% rename from ffmpeg/include/libavutil/murmur3.h rename to 3rdparty/ffmpeg/include/libavutil/murmur3.h diff --git a/ffmpeg/include/libavutil/opt.h b/3rdparty/ffmpeg/include/libavutil/opt.h similarity index 100% rename from ffmpeg/include/libavutil/opt.h rename to 3rdparty/ffmpeg/include/libavutil/opt.h diff --git a/ffmpeg/include/libavutil/parseutils.h b/3rdparty/ffmpeg/include/libavutil/parseutils.h similarity index 100% rename from ffmpeg/include/libavutil/parseutils.h rename to 3rdparty/ffmpeg/include/libavutil/parseutils.h diff --git a/ffmpeg/include/libavutil/pixdesc.h b/3rdparty/ffmpeg/include/libavutil/pixdesc.h similarity index 100% rename from ffmpeg/include/libavutil/pixdesc.h rename to 3rdparty/ffmpeg/include/libavutil/pixdesc.h diff --git a/ffmpeg/include/libavutil/pixelutils.h b/3rdparty/ffmpeg/include/libavutil/pixelutils.h similarity index 100% rename from ffmpeg/include/libavutil/pixelutils.h rename to 3rdparty/ffmpeg/include/libavutil/pixelutils.h diff --git a/ffmpeg/include/libavutil/pixfmt.h b/3rdparty/ffmpeg/include/libavutil/pixfmt.h similarity index 100% rename from ffmpeg/include/libavutil/pixfmt.h rename to 3rdparty/ffmpeg/include/libavutil/pixfmt.h diff --git a/ffmpeg/include/libavutil/random_seed.h b/3rdparty/ffmpeg/include/libavutil/random_seed.h similarity index 100% rename from ffmpeg/include/libavutil/random_seed.h rename to 3rdparty/ffmpeg/include/libavutil/random_seed.h diff --git a/ffmpeg/include/libavutil/rational.h b/3rdparty/ffmpeg/include/libavutil/rational.h similarity index 100% rename from ffmpeg/include/libavutil/rational.h rename to 3rdparty/ffmpeg/include/libavutil/rational.h diff --git a/ffmpeg/include/libavutil/rc4.h b/3rdparty/ffmpeg/include/libavutil/rc4.h similarity index 100% rename from ffmpeg/include/libavutil/rc4.h rename to 3rdparty/ffmpeg/include/libavutil/rc4.h diff --git a/ffmpeg/include/libavutil/replaygain.h b/3rdparty/ffmpeg/include/libavutil/replaygain.h similarity index 100% rename from ffmpeg/include/libavutil/replaygain.h rename to 3rdparty/ffmpeg/include/libavutil/replaygain.h diff --git a/ffmpeg/include/libavutil/ripemd.h b/3rdparty/ffmpeg/include/libavutil/ripemd.h similarity index 100% rename from ffmpeg/include/libavutil/ripemd.h rename to 3rdparty/ffmpeg/include/libavutil/ripemd.h diff --git a/ffmpeg/include/libavutil/samplefmt.h b/3rdparty/ffmpeg/include/libavutil/samplefmt.h similarity index 100% rename from ffmpeg/include/libavutil/samplefmt.h rename to 3rdparty/ffmpeg/include/libavutil/samplefmt.h diff --git a/ffmpeg/include/libavutil/sha.h b/3rdparty/ffmpeg/include/libavutil/sha.h similarity index 100% rename from ffmpeg/include/libavutil/sha.h rename to 3rdparty/ffmpeg/include/libavutil/sha.h diff --git a/ffmpeg/include/libavutil/sha512.h b/3rdparty/ffmpeg/include/libavutil/sha512.h similarity index 100% rename from ffmpeg/include/libavutil/sha512.h rename to 3rdparty/ffmpeg/include/libavutil/sha512.h diff --git a/ffmpeg/include/libavutil/spherical.h b/3rdparty/ffmpeg/include/libavutil/spherical.h similarity index 100% rename from ffmpeg/include/libavutil/spherical.h rename to 3rdparty/ffmpeg/include/libavutil/spherical.h diff --git a/ffmpeg/include/libavutil/stereo3d.h b/3rdparty/ffmpeg/include/libavutil/stereo3d.h similarity index 100% rename from ffmpeg/include/libavutil/stereo3d.h rename to 3rdparty/ffmpeg/include/libavutil/stereo3d.h diff --git a/ffmpeg/include/libavutil/tea.h b/3rdparty/ffmpeg/include/libavutil/tea.h similarity index 100% rename from ffmpeg/include/libavutil/tea.h rename to 3rdparty/ffmpeg/include/libavutil/tea.h diff --git a/ffmpeg/include/libavutil/threadmessage.h b/3rdparty/ffmpeg/include/libavutil/threadmessage.h similarity index 100% rename from ffmpeg/include/libavutil/threadmessage.h rename to 3rdparty/ffmpeg/include/libavutil/threadmessage.h diff --git a/ffmpeg/include/libavutil/time.h b/3rdparty/ffmpeg/include/libavutil/time.h similarity index 100% rename from ffmpeg/include/libavutil/time.h rename to 3rdparty/ffmpeg/include/libavutil/time.h diff --git a/ffmpeg/include/libavutil/timecode.h b/3rdparty/ffmpeg/include/libavutil/timecode.h similarity index 100% rename from ffmpeg/include/libavutil/timecode.h rename to 3rdparty/ffmpeg/include/libavutil/timecode.h diff --git a/ffmpeg/include/libavutil/timestamp.h b/3rdparty/ffmpeg/include/libavutil/timestamp.h similarity index 100% rename from ffmpeg/include/libavutil/timestamp.h rename to 3rdparty/ffmpeg/include/libavutil/timestamp.h diff --git a/ffmpeg/include/libavutil/tree.h b/3rdparty/ffmpeg/include/libavutil/tree.h similarity index 100% rename from ffmpeg/include/libavutil/tree.h rename to 3rdparty/ffmpeg/include/libavutil/tree.h diff --git a/ffmpeg/include/libavutil/twofish.h b/3rdparty/ffmpeg/include/libavutil/twofish.h similarity index 100% rename from ffmpeg/include/libavutil/twofish.h rename to 3rdparty/ffmpeg/include/libavutil/twofish.h diff --git a/ffmpeg/include/libavutil/tx.h b/3rdparty/ffmpeg/include/libavutil/tx.h similarity index 100% rename from ffmpeg/include/libavutil/tx.h rename to 3rdparty/ffmpeg/include/libavutil/tx.h diff --git a/ffmpeg/include/libavutil/uuid.h b/3rdparty/ffmpeg/include/libavutil/uuid.h similarity index 100% rename from ffmpeg/include/libavutil/uuid.h rename to 3rdparty/ffmpeg/include/libavutil/uuid.h diff --git a/ffmpeg/include/libavutil/version.h b/3rdparty/ffmpeg/include/libavutil/version.h similarity index 100% rename from ffmpeg/include/libavutil/version.h rename to 3rdparty/ffmpeg/include/libavutil/version.h diff --git a/ffmpeg/include/libavutil/video_enc_params.h b/3rdparty/ffmpeg/include/libavutil/video_enc_params.h similarity index 100% rename from ffmpeg/include/libavutil/video_enc_params.h rename to 3rdparty/ffmpeg/include/libavutil/video_enc_params.h diff --git a/ffmpeg/include/libavutil/video_hint.h b/3rdparty/ffmpeg/include/libavutil/video_hint.h similarity index 100% rename from ffmpeg/include/libavutil/video_hint.h rename to 3rdparty/ffmpeg/include/libavutil/video_hint.h diff --git a/ffmpeg/include/libavutil/xtea.h b/3rdparty/ffmpeg/include/libavutil/xtea.h similarity index 100% rename from ffmpeg/include/libavutil/xtea.h rename to 3rdparty/ffmpeg/include/libavutil/xtea.h diff --git a/ffmpeg/include/libpostproc/postprocess.h b/3rdparty/ffmpeg/include/libpostproc/postprocess.h similarity index 100% rename from ffmpeg/include/libpostproc/postprocess.h rename to 3rdparty/ffmpeg/include/libpostproc/postprocess.h diff --git a/ffmpeg/include/libpostproc/version.h b/3rdparty/ffmpeg/include/libpostproc/version.h similarity index 100% rename from ffmpeg/include/libpostproc/version.h rename to 3rdparty/ffmpeg/include/libpostproc/version.h diff --git a/ffmpeg/include/libpostproc/version_major.h b/3rdparty/ffmpeg/include/libpostproc/version_major.h similarity index 100% rename from ffmpeg/include/libpostproc/version_major.h rename to 3rdparty/ffmpeg/include/libpostproc/version_major.h diff --git a/ffmpeg/include/libswresample/swresample.h b/3rdparty/ffmpeg/include/libswresample/swresample.h similarity index 100% rename from ffmpeg/include/libswresample/swresample.h rename to 3rdparty/ffmpeg/include/libswresample/swresample.h diff --git a/ffmpeg/include/libswresample/version.h b/3rdparty/ffmpeg/include/libswresample/version.h similarity index 100% rename from ffmpeg/include/libswresample/version.h rename to 3rdparty/ffmpeg/include/libswresample/version.h diff --git a/ffmpeg/include/libswresample/version_major.h b/3rdparty/ffmpeg/include/libswresample/version_major.h similarity index 100% rename from ffmpeg/include/libswresample/version_major.h rename to 3rdparty/ffmpeg/include/libswresample/version_major.h diff --git a/ffmpeg/include/libswscale/swscale.h b/3rdparty/ffmpeg/include/libswscale/swscale.h similarity index 100% rename from ffmpeg/include/libswscale/swscale.h rename to 3rdparty/ffmpeg/include/libswscale/swscale.h diff --git a/ffmpeg/include/libswscale/version.h b/3rdparty/ffmpeg/include/libswscale/version.h similarity index 100% rename from ffmpeg/include/libswscale/version.h rename to 3rdparty/ffmpeg/include/libswscale/version.h diff --git a/ffmpeg/include/libswscale/version_major.h b/3rdparty/ffmpeg/include/libswscale/version_major.h similarity index 100% rename from ffmpeg/include/libswscale/version_major.h rename to 3rdparty/ffmpeg/include/libswscale/version_major.h diff --git a/ffmpeg/lib/avcodec-60.def b/3rdparty/ffmpeg/lib/avcodec-60.def similarity index 100% rename from ffmpeg/lib/avcodec-60.def rename to 3rdparty/ffmpeg/lib/avcodec-60.def diff --git a/ffmpeg/lib/avcodec.lib b/3rdparty/ffmpeg/lib/avcodec.lib similarity index 100% rename from ffmpeg/lib/avcodec.lib rename to 3rdparty/ffmpeg/lib/avcodec.lib diff --git a/ffmpeg/lib/avdevice-60.def b/3rdparty/ffmpeg/lib/avdevice-60.def similarity index 100% rename from ffmpeg/lib/avdevice-60.def rename to 3rdparty/ffmpeg/lib/avdevice-60.def diff --git a/ffmpeg/lib/avdevice.lib b/3rdparty/ffmpeg/lib/avdevice.lib similarity index 100% rename from ffmpeg/lib/avdevice.lib rename to 3rdparty/ffmpeg/lib/avdevice.lib diff --git a/ffmpeg/lib/avfilter-9.def b/3rdparty/ffmpeg/lib/avfilter-9.def similarity index 100% rename from ffmpeg/lib/avfilter-9.def rename to 3rdparty/ffmpeg/lib/avfilter-9.def diff --git a/ffmpeg/lib/avfilter.lib b/3rdparty/ffmpeg/lib/avfilter.lib similarity index 100% rename from ffmpeg/lib/avfilter.lib rename to 3rdparty/ffmpeg/lib/avfilter.lib diff --git a/ffmpeg/lib/avformat-60.def b/3rdparty/ffmpeg/lib/avformat-60.def similarity index 100% rename from ffmpeg/lib/avformat-60.def rename to 3rdparty/ffmpeg/lib/avformat-60.def diff --git a/ffmpeg/lib/avformat.lib b/3rdparty/ffmpeg/lib/avformat.lib similarity index 100% rename from ffmpeg/lib/avformat.lib rename to 3rdparty/ffmpeg/lib/avformat.lib diff --git a/ffmpeg/lib/avutil-58.def b/3rdparty/ffmpeg/lib/avutil-58.def similarity index 100% rename from ffmpeg/lib/avutil-58.def rename to 3rdparty/ffmpeg/lib/avutil-58.def diff --git a/ffmpeg/lib/avutil.lib b/3rdparty/ffmpeg/lib/avutil.lib similarity index 100% rename from ffmpeg/lib/avutil.lib rename to 3rdparty/ffmpeg/lib/avutil.lib diff --git a/ffmpeg/lib/libavcodec.dll.a b/3rdparty/ffmpeg/lib/libavcodec.dll.a similarity index 100% rename from ffmpeg/lib/libavcodec.dll.a rename to 3rdparty/ffmpeg/lib/libavcodec.dll.a diff --git a/ffmpeg/lib/libavdevice.dll.a b/3rdparty/ffmpeg/lib/libavdevice.dll.a similarity index 100% rename from ffmpeg/lib/libavdevice.dll.a rename to 3rdparty/ffmpeg/lib/libavdevice.dll.a diff --git a/ffmpeg/lib/libavfilter.dll.a b/3rdparty/ffmpeg/lib/libavfilter.dll.a similarity index 100% rename from ffmpeg/lib/libavfilter.dll.a rename to 3rdparty/ffmpeg/lib/libavfilter.dll.a diff --git a/ffmpeg/lib/libavformat.dll.a b/3rdparty/ffmpeg/lib/libavformat.dll.a similarity index 100% rename from ffmpeg/lib/libavformat.dll.a rename to 3rdparty/ffmpeg/lib/libavformat.dll.a diff --git a/ffmpeg/lib/libavutil.dll.a b/3rdparty/ffmpeg/lib/libavutil.dll.a similarity index 100% rename from ffmpeg/lib/libavutil.dll.a rename to 3rdparty/ffmpeg/lib/libavutil.dll.a diff --git a/ffmpeg/lib/libpostproc.dll.a b/3rdparty/ffmpeg/lib/libpostproc.dll.a similarity index 100% rename from ffmpeg/lib/libpostproc.dll.a rename to 3rdparty/ffmpeg/lib/libpostproc.dll.a diff --git a/ffmpeg/lib/libswresample.dll.a b/3rdparty/ffmpeg/lib/libswresample.dll.a similarity index 100% rename from ffmpeg/lib/libswresample.dll.a rename to 3rdparty/ffmpeg/lib/libswresample.dll.a diff --git a/ffmpeg/lib/libswscale.dll.a b/3rdparty/ffmpeg/lib/libswscale.dll.a similarity index 100% rename from ffmpeg/lib/libswscale.dll.a rename to 3rdparty/ffmpeg/lib/libswscale.dll.a diff --git a/ffmpeg/lib/postproc-57.def b/3rdparty/ffmpeg/lib/postproc-57.def similarity index 100% rename from ffmpeg/lib/postproc-57.def rename to 3rdparty/ffmpeg/lib/postproc-57.def diff --git a/ffmpeg/lib/postproc.lib b/3rdparty/ffmpeg/lib/postproc.lib similarity index 100% rename from ffmpeg/lib/postproc.lib rename to 3rdparty/ffmpeg/lib/postproc.lib diff --git a/ffmpeg/lib/swresample-4.def b/3rdparty/ffmpeg/lib/swresample-4.def similarity index 100% rename from ffmpeg/lib/swresample-4.def rename to 3rdparty/ffmpeg/lib/swresample-4.def diff --git a/ffmpeg/lib/swresample.lib b/3rdparty/ffmpeg/lib/swresample.lib similarity index 100% rename from ffmpeg/lib/swresample.lib rename to 3rdparty/ffmpeg/lib/swresample.lib diff --git a/ffmpeg/lib/swscale-7.def b/3rdparty/ffmpeg/lib/swscale-7.def similarity index 100% rename from ffmpeg/lib/swscale-7.def rename to 3rdparty/ffmpeg/lib/swscale-7.def diff --git a/ffmpeg/lib/swscale.lib b/3rdparty/ffmpeg/lib/swscale.lib similarity index 100% rename from ffmpeg/lib/swscale.lib rename to 3rdparty/ffmpeg/lib/swscale.lib diff --git a/ffmpeg/presets/libvpx-1080p.ffpreset b/3rdparty/ffmpeg/presets/libvpx-1080p.ffpreset similarity index 100% rename from ffmpeg/presets/libvpx-1080p.ffpreset rename to 3rdparty/ffmpeg/presets/libvpx-1080p.ffpreset diff --git a/ffmpeg/presets/libvpx-1080p50_60.ffpreset b/3rdparty/ffmpeg/presets/libvpx-1080p50_60.ffpreset similarity index 100% rename from ffmpeg/presets/libvpx-1080p50_60.ffpreset rename to 3rdparty/ffmpeg/presets/libvpx-1080p50_60.ffpreset diff --git a/ffmpeg/presets/libvpx-360p.ffpreset b/3rdparty/ffmpeg/presets/libvpx-360p.ffpreset similarity index 100% rename from ffmpeg/presets/libvpx-360p.ffpreset rename to 3rdparty/ffmpeg/presets/libvpx-360p.ffpreset diff --git a/ffmpeg/presets/libvpx-720p.ffpreset b/3rdparty/ffmpeg/presets/libvpx-720p.ffpreset similarity index 100% rename from ffmpeg/presets/libvpx-720p.ffpreset rename to 3rdparty/ffmpeg/presets/libvpx-720p.ffpreset diff --git a/ffmpeg/presets/libvpx-720p50_60.ffpreset b/3rdparty/ffmpeg/presets/libvpx-720p50_60.ffpreset similarity index 100% rename from ffmpeg/presets/libvpx-720p50_60.ffpreset rename to 3rdparty/ffmpeg/presets/libvpx-720p50_60.ffpreset diff --git a/PayloadAPP.pro b/PayloadAPP.pro index 65a0fd4..959c331 100644 --- a/PayloadAPP.pro +++ b/PayloadAPP.pro @@ -14,7 +14,7 @@ QMAKE_PROJECT_DEPTH = 0 # QMAKE_LFLAGS += /MANIFESTUAC:\"level=\'requireAdministrator\' uiAccess=\'false\'\" #程序版本 -VERSION = 1.0.2.3 +VERSION = 1.1.0.0 #程序版本 QMAKE_TARGET_COMPANY = "HTSDFP" @@ -55,13 +55,17 @@ DISTFILES += \ RC_ICONS = SDFP3.ico -INCLUDEPATH += $$PWD/ffmpeg/include \ - $$PWD/Src/Video/ +INCLUDEPATH += $$PWD/3rdparty/ffmpeg/include \ + $$PWD/Src/VideoGL/ \ + $$PWD/Src/Video/ \ + $$PWD/3rdparty/QNotify/include \ -LIBS += -L$$PWD/ffmpeg/lib \ +LIBS += -L$$PWD/3rdparty/ffmpeg/lib \ -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc \ -lswresample -lswscale +LIBS += -L$$PWD/3rdparty/QNotify/lib \ + -lQNotifyd # win32 { # LIBS += -luser32 # } @@ -72,3 +76,4 @@ include($$PWD/Src/ModelCamera/ModelCamera.pri) include($$PWD/Src/RescueLoad/RescueLoad.pri) include($$PWD/Src/GDDC/GDDC.pri) include($$PWD/Src/Video/Video.pri) +include($$PWD/Src/VideoGL/VideoGL.pri) diff --git a/Src/GDDC/gddcSet.cpp b/Src/GDDC/gddcSet.cpp index c70f50e..1d0047e 100644 --- a/Src/GDDC/gddcSet.cpp +++ b/Src/GDDC/gddcSet.cpp @@ -1,261 +1,272 @@ #include "gddcSet.h" -#include "ui_gddcSet.h" + #include +#include "ui_gddcSet.h" + // #pragma execution_character_set(“utf-8”) GDDCSet::GDDCSet(QWidget *parent) : QWidget(parent), ui(new Ui::GDDCSet) { - ui->setupUi(this); - initWindow(); - initParam(); - initUDPSocket(); + ui->setupUi(this); + initWindow(); + initParam(); + initUDPSocket(); - ui->label_3->setVisible(false); - ui->comboBox_streamType->setVisible(false); + ui->label_3->setVisible(false); + ui->comboBox_streamType->setVisible(false); } -GDDCSet::~GDDCSet() { delete ui; } +GDDCSet::~GDDCSet() { + delete ui; +} void GDDCSet::initWindow() { - setWindowTitle("通信设置"); - setAttribute(Qt::WA_QuitOnClose, false); - - // 交付时隐藏部分未开发接口 - ui->label_5->hide(); - ui->label_6->hide(); - ui->lineEdit_playURL2->hide(); - ui->pushButton_ConnectURL2->hide(); - ui->groupBox_2->hide(); - ui->radioButton_NetCtrlTCP->hide(); + setWindowTitle("通信设置"); + setAttribute(Qt::WA_QuitOnClose, false); + + // 交付时隐藏部分未开发接口 + ui->label_5->hide(); + ui->label_6->hide(); + ui->lineEdit_playURL2->hide(); + ui->pushButton_ConnectURL2->hide(); + ui->groupBox_2->hide(); + ui->radioButton_NetCtrlTCP->hide(); } void GDDCSet::initUDPSocket() {} void GDDCSet::initParam() { - m_FlowType = ""; - - // m_myPairNetwork("",0,"",0); - // QSettings setting("./sentence.ini",QSettings::IniFormat); - // setting.setIniCodec(QTextCodec::codecForName("UTF-8")); //重点 - - ui->comboBox_streamType->addItem("RTSP"); - ui->comboBox_streamType->addItem("RTMP"); - // ui->comboBox_streamType->addItem("UDP Raw"); - // ui->comboBox_streamType->addItem("UDP 422"); - // ui->comboBox_streamType->addItem("UDP TS"); - ui->comboBox_playURL1->addItem( - QStringLiteral("rtsp://10.90.10.132:554/live/track0")); - ui->comboBox_playURL1->setCurrentIndex(0); - // ui->comboBox_playURL1->addItem( - // "rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid"); - ui->comboBox_playURL1->setEditable(true); - 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->radioButton_NetCtrlUDP->setChecked(true); - ui->radioButton_NetCtrlTCP->setChecked(false); - - // 读取本机网络设备 - QString urlFile = QCoreApplication::applicationDirPath() + "/config.ini"; - // QString urlFile = QDir::currentPath() + "./config.ini"; - m_configIniPath = urlFile.toLatin1(); - char *strSysIniName = m_configIniPath.data(); // 系统配置文件路径 - char inBuf[100]; - - ::GetPrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "流类型", "-1", - inBuf, 100, strSysIniName); - m_FlowType = streamTypeToflowType(QString::fromUtf8(inBuf)); - ui->comboBox_streamType->setCurrentText(flowTypeTostreamType(m_FlowType)); - - // ::GetPrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "播放URL", "-1", - // inBuf, 100, strSysIniName); - // m_playURL1 = QString::fromUtf8(inBuf); - // ui->comboBox_playURL1->setCurrentText(m_playURL1); - - // ::GetPrivateProfileStringA("光电吊舱-视频连接-显示窗口2", "播放URL", "-1", - // inBuf, 100, strSysIniName); - // m_playURL2 = QString::fromUtf8(inBuf); - // ui->lineEdit_playURL2->setText(m_playURL2); - - ::GetPrivateProfileStringA("光电吊舱-推流", "推流URL", "-1", inBuf, 100, - strSysIniName); - m_pushURL = QString::fromUtf8(inBuf); - // ui->lineEdit_pushURL->setText(m_pushURL); - - ::GetPrivateProfileStringA("光电吊舱-网络控制", "远端IP", "-1", inBuf, 100, - strSysIniName); - m_myPairNetwork.setRemoteIP(QString::fromUtf8(inBuf)); - ::GetPrivateProfileStringA("光电吊舱-网络控制", "远端Port", "-1", inBuf, 100, - strSysIniName); - m_myPairNetwork.setRemotePort(atoi(inBuf)); - ::GetPrivateProfileStringA("光电吊舱-网络控制", "本地IP", "-1", inBuf, 100, - strSysIniName); - m_myPairNetwork.setLocalIP(QString::fromUtf8(inBuf)); - ::GetPrivateProfileStringA("光电吊舱-网络控制", "本地Port", "-1", inBuf, 100, - strSysIniName); - m_myPairNetwork.setLocalPort(atoi(inBuf)); - ui->lineEdit_NetCtrlRemoteIp->setText(m_myPairNetwork.getRemoteIP()); - ui->lineEdit_NetCtrlRemotePort->setText( - QString::number(m_myPairNetwork.getRemotePort())); - ui->lineEdit_NetCtrlLocalIp->setText(m_myPairNetwork.getLocalIP()); - ui->lineEdit_NetCtrlLocalPort->setText( - QString::number(m_myPairNetwork.getLocalPort())); + m_FlowType = ""; + + // m_myPairNetwork("",0,"",0); + // QSettings setting("./sentence.ini",QSettings::IniFormat); + // setting.setIniCodec(QTextCodec::codecForName("UTF-8")); //重点 + + ui->comboBox_streamType->addItem("RTSP"); + ui->comboBox_streamType->addItem("RTMP"); + // ui->comboBox_streamType->addItem("UDP Raw"); + // ui->comboBox_streamType->addItem("UDP 422"); + // ui->comboBox_streamType->addItem("UDP TS"); + ui->comboBox_playURL1->addItem( + QStringLiteral("rtsp://10.90.10.132:554/live/track0")); + ui->comboBox_playURL1->setCurrentIndex(0); + // ui->comboBox_playURL1->addItem( + // "rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid"); + ui->comboBox_playURL1->setEditable(true); + 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->radioButton_NetCtrlUDP->setChecked(true); + ui->radioButton_NetCtrlTCP->setChecked(false); + + // 读取本机网络设备 + QString urlFile = QCoreApplication::applicationDirPath() + "/config.ini"; + // QString urlFile = QDir::currentPath() + "./config.ini"; + m_configIniPath = urlFile.toLatin1(); + char *strSysIniName = m_configIniPath.data(); // 系统配置文件路径 + char inBuf[100]; + + ::GetPrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "流类型", "-1", + inBuf, 100, strSysIniName); + m_FlowType = streamTypeToflowType(QString::fromUtf8(inBuf)); + ui->comboBox_streamType->setCurrentText(flowTypeTostreamType(m_FlowType)); + + // ::GetPrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "播放URL", + // "-1", + // inBuf, 100, strSysIniName); + // m_playURL1 = QString::fromUtf8(inBuf); + // ui->comboBox_playURL1->setCurrentText(m_playURL1); + + // ::GetPrivateProfileStringA("光电吊舱-视频连接-显示窗口2", "播放URL", + // "-1", + // inBuf, 100, strSysIniName); + // m_playURL2 = QString::fromUtf8(inBuf); + // ui->lineEdit_playURL2->setText(m_playURL2); + + ::GetPrivateProfileStringA("光电吊舱-推流", "推流URL", "-1", inBuf, 100, + strSysIniName); + m_pushURL = QString::fromUtf8(inBuf); + // ui->lineEdit_pushURL->setText(m_pushURL); + + ::GetPrivateProfileStringA("光电吊舱-网络控制", "远端IP", "-1", inBuf, 100, + strSysIniName); + m_myPairNetwork.setRemoteIP(QString::fromUtf8(inBuf)); + ::GetPrivateProfileStringA("光电吊舱-网络控制", "远端Port", "-1", inBuf, + 100, strSysIniName); + m_myPairNetwork.setRemotePort(atoi(inBuf)); + ::GetPrivateProfileStringA("光电吊舱-网络控制", "本地IP", "-1", inBuf, 100, + strSysIniName); + m_myPairNetwork.setLocalIP(QString::fromUtf8(inBuf)); + ::GetPrivateProfileStringA("光电吊舱-网络控制", "本地Port", "-1", inBuf, + 100, strSysIniName); + m_myPairNetwork.setLocalPort(atoi(inBuf)); + ui->lineEdit_NetCtrlRemoteIp->setText(m_myPairNetwork.getRemoteIP()); + ui->lineEdit_NetCtrlRemotePort->setText( + QString::number(m_myPairNetwork.getRemotePort())); + ui->lineEdit_NetCtrlLocalIp->setText(m_myPairNetwork.getLocalIP()); + ui->lineEdit_NetCtrlLocalPort->setText( + QString::number(m_myPairNetwork.getLocalPort())); } // 视频连接-显示窗口1-连接 void GDDCSet::on_pushButton_ConnectURL1_clicked() { - saveDataToLocalIni(); - if (ui->pushButton_ConnectURL1->text() == "连接") { - emit SignalStartConnect(1); - ui->pushButton_ConnectURL1->setText("断开"); - } else { - emit SignalStopConnect(1); - ui->pushButton_ConnectURL1->setText("连接"); - } - // this->on_pushButton_pushURL_clicked(); + ui->pushButton_ConnectURL1->setEnabled(false); + saveDataToLocalIni(); + if (ui->pushButton_ConnectURL1->text() == "连接") { + emit SignalStartConnect(1); + ui->pushButton_ConnectURL1->setText("断开"); + } else { + emit SignalStopConnect(1); + ui->pushButton_ConnectURL1->setText("连接"); + } + // this->on_pushButton_pushURL_clicked(); + ui->pushButton_ConnectURL1->setEnabled(true); } // 视频连接-显示窗口2-连接 void GDDCSet::on_pushButton_ConnectURL2_clicked() { - saveDataToLocalIni(); - if (ui->pushButton_ConnectURL2->text() == "连接") { - emit SignalStartConnect(2); - ui->pushButton_ConnectURL2->setText("断开"); - } else { - emit SignalStopConnect(2); - ui->pushButton_ConnectURL2->setText("连接"); - } + saveDataToLocalIni(); + if (ui->pushButton_ConnectURL2->text() == "连接") { + emit SignalStartConnect(2); + ui->pushButton_ConnectURL2->setText("断开"); + } else { + emit SignalStopConnect(2); + ui->pushButton_ConnectURL2->setText("连接"); + } } // 串口控制-刷新 void GDDCSet::on_pushButton_serialControlRefalsh_clicked() { - saveDataToLocalIni(); + saveDataToLocalIni(); } // 串口控制-连接 void GDDCSet::on_pushButton_serialControlConnect_clicked() { - saveDataToLocalIni(); - if (ui->pushButton_serialControlConnect->text() == "连接") { - emit SignalStartConnect(3); - ui->pushButton_serialControlConnect->setText("断开"); - } else { - emit SignalStopConnect(3); - ui->pushButton_serialControlConnect->setText("连接"); - } + saveDataToLocalIni(); + if (ui->pushButton_serialControlConnect->text() == "连接") { + emit SignalStartConnect(3); + ui->pushButton_serialControlConnect->setText("断开"); + } else { + emit SignalStopConnect(3); + ui->pushButton_serialControlConnect->setText("连接"); + } } // 网络控制-连接 void GDDCSet::on_pushButton_NetCtrlConnect_clicked() { - saveDataToLocalIni(); - if (ui->pushButton_NetCtrlConnect->text() == "连接") { - if (ui->radioButton_NetCtrlUDP->isChecked()) { - emit SignalStartConnect(4); + saveDataToLocalIni(); + if (ui->pushButton_NetCtrlConnect->text() == "连接") { + if (ui->radioButton_NetCtrlUDP->isChecked()) { + emit SignalStartConnect(4); + } else { + emit SignalStartConnect(5); + } + ui->pushButton_NetCtrlConnect->setText("断开"); } else { - emit SignalStartConnect(5); + emit SignalStopConnect(4); + emit SignalStopConnect(5); + ui->pushButton_NetCtrlConnect->setText("连接"); } - ui->pushButton_NetCtrlConnect->setText("断开"); - } else { - emit SignalStopConnect(4); - emit SignalStopConnect(5); - ui->pushButton_NetCtrlConnect->setText("连接"); - } } // 推流 void GDDCSet::on_pushButton_pushURL_clicked() { - saveDataToLocalIni(); - if (ui->pushButton_pushURL->text() == "推送") { - emit SignalStartConnect(6); - // ui->pushButton_pushURL->setText("停止推送"); - } else { - emit SignalStopConnect(6); - // ui->pushButton_pushURL->setText("推送"); - } + ui->pushButton_pushURL->setEnabled(false); + saveDataToLocalIni(); + if (ui->pushButton_pushURL->text() == "推送") { + emit SignalStartConnect(6); + // ui->pushButton_pushURL->setText("停止推送"); + } else { + emit SignalStopConnect(6); + // ui->pushButton_pushURL->setText("推送"); + } + ui->pushButton_pushURL->setEnabled(true); } // 保存数据至本地ini文件 void GDDCSet::saveDataToLocalIni() { - char *strSysIniName = m_configIniPath.data(); // 系统配置文件路径 - char *inBuf; - QByteArray ba; - - m_myPairNetwork.setLocalIP(ui->lineEdit_NetCtrlLocalIp->text()); - ba = m_myPairNetwork.getLocalIP().toLocal8Bit(); - inBuf = ba.data(); // toLatin1,toUtf8 - ::WritePrivateProfileStringA("光电吊舱-网络控制", "本地IP", inBuf, - strSysIniName); - - m_myPairNetwork.setLocalPort(ui->lineEdit_NetCtrlLocalPort->text().toInt()); - _itoa_s( - m_myPairNetwork.getLocalPort(), inBuf, 10, - 10); // 要转换的数字,存放转换结果的字符串,存放结果的字符数组长度,转化的进制数,2表示2进制,10表示10进制 - ::WritePrivateProfileStringA("光电吊舱-网络控制", "本地Port", inBuf, - strSysIniName); - - m_myPairNetwork.setRemoteIP(ui->lineEdit_NetCtrlRemoteIp->text()); - ba = m_myPairNetwork.getRemoteIP().toLocal8Bit(); - inBuf = ba.data(); - ::WritePrivateProfileStringA("光电吊舱-网络控制", "远端IP", inBuf, - strSysIniName); - - m_myPairNetwork.setRemotePort(ui->lineEdit_NetCtrlRemotePort->text().toInt()); - _itoa_s(m_myPairNetwork.getRemotePort(), inBuf, 10, 10); - ::WritePrivateProfileStringA("光电吊舱-网络控制", "远端Port", inBuf, - strSysIniName); - - QString streamType = ui->comboBox_streamType->currentText(); - m_FlowType = streamTypeToflowType(streamType); - ba = streamType.toLocal8Bit(); - inBuf = ba.data(); - ::WritePrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "流类型", inBuf, - strSysIniName); + char *strSysIniName = m_configIniPath.data(); // 系统配置文件路径 + char *inBuf; + QByteArray ba; + + m_myPairNetwork.setLocalIP(ui->lineEdit_NetCtrlLocalIp->text()); + ba = m_myPairNetwork.getLocalIP().toLocal8Bit(); + inBuf = ba.data(); // toLatin1,toUtf8 + ::WritePrivateProfileStringA("光电吊舱-网络控制", "本地IP", inBuf, + strSysIniName); + + m_myPairNetwork.setLocalPort(ui->lineEdit_NetCtrlLocalPort->text().toInt()); + _itoa_s( + m_myPairNetwork.getLocalPort(), inBuf, 10, + 10); // 要转换的数字,存放转换结果的字符串,存放结果的字符数组长度,转化的进制数,2表示2进制,10表示10进制 + ::WritePrivateProfileStringA("光电吊舱-网络控制", "本地Port", inBuf, + strSysIniName); + + m_myPairNetwork.setRemoteIP(ui->lineEdit_NetCtrlRemoteIp->text()); + ba = m_myPairNetwork.getRemoteIP().toLocal8Bit(); + inBuf = ba.data(); + ::WritePrivateProfileStringA("光电吊舱-网络控制", "远端IP", inBuf, + strSysIniName); + + m_myPairNetwork.setRemotePort( + ui->lineEdit_NetCtrlRemotePort->text().toInt()); + _itoa_s(m_myPairNetwork.getRemotePort(), inBuf, 10, 10); + ::WritePrivateProfileStringA("光电吊舱-网络控制", "远端Port", inBuf, + strSysIniName); + + QString streamType = ui->comboBox_streamType->currentText(); + m_FlowType = streamTypeToflowType(streamType); + ba = streamType.toLocal8Bit(); + inBuf = ba.data(); + ::WritePrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "流类型", inBuf, + strSysIniName); + + m_playURL1 = ui->comboBox_playURL1->currentText(); + ba = m_playURL1.toLocal8Bit(); + inBuf = ba.data(); + ::WritePrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "播放URL", + inBuf, strSysIniName); + + // m_playURL2 = ui->lineEdit_playURL2->text(); + // ba = m_playURL2.toLocal8Bit(); + // inBuf = ba.data(); + // ::WritePrivateProfileStringA("光电吊舱-视频连接-显示窗口2", "播放URL", + // inBuf, + // strSysIniName); - m_playURL1 = ui->comboBox_playURL1->currentText(); - ba = m_playURL1.toLocal8Bit(); - inBuf = ba.data(); - ::WritePrivateProfileStringA("光电吊舱-视频连接-显示窗口1", "播放URL", inBuf, - strSysIniName); - - // m_playURL2 = ui->lineEdit_playURL2->text(); - // ba = m_playURL2.toLocal8Bit(); - // inBuf = ba.data(); - // ::WritePrivateProfileStringA("光电吊舱-视频连接-显示窗口2", "播放URL", - // inBuf, - // strSysIniName); - - int uavID = ui->uavIDSpinBox->value(); - if (ui->radioButton->isChecked()) { - m_pushURL = ui->comboBox_pushURL->currentText(); - } else { - if (ui->comboBox_pushURL->currentIndex() == 0) { - auto iter = mapPushURL_yjzh.find(uavID); - if (iter != mapPushURL_yjzh.end()) { - m_pushURL = iter->second; - } - } else if (ui->comboBox_pushURL->currentIndex() == 1) { - auto iter = mapPushURL_yjtt.find(uavID); - if (iter != mapPushURL_yjtt.end()) { - m_pushURL = iter->second; - } + int uavID = ui->uavIDSpinBox->value(); + if (ui->radioButton->isChecked()) { + m_pushURL = ui->comboBox_pushURL->currentText(); + } else { + if (ui->comboBox_pushURL->currentIndex() == 0) { + auto iter = mapPushURL_yjzh.find(uavID); + if (iter != mapPushURL_yjzh.end()) { + m_pushURL = iter->second; + } + } else if (ui->comboBox_pushURL->currentIndex() == 1) { + auto iter = mapPushURL_yjtt.find(uavID); + if (iter != mapPushURL_yjtt.end()) { + m_pushURL = iter->second; + } + } } - } - qDebug() << "推流地址:" << m_pushURL; - // m_pushURL = ui->comboBox_pushURL->currentText(); - ba = m_pushURL.toLocal8Bit(); - inBuf = ba.data(); - ::WritePrivateProfileStringA("光电吊舱-推流", "推流URL", inBuf, - strSysIniName); - - m_playURL1 = ui->comboBox_playURL1->currentText(); + qDebug() << "推流地址:" << m_pushURL; + // m_pushURL = ui->comboBox_pushURL->currentText(); + ba = m_pushURL.toLocal8Bit(); + inBuf = ba.data(); + ::WritePrivateProfileStringA("光电吊舱-推流", "推流URL", inBuf, + strSysIniName); + + m_playURL1 = ui->comboBox_playURL1->currentText(); } void GDDCSet::initPullURL(QString remoteIP) { - if (!remoteIP.isEmpty()) { - m_playURL1 = "rtsp://" + remoteIP + ":554/live/track0"; - } - ui->comboBox_playURL1->setCurrentText(m_playURL1); + if (!remoteIP.isEmpty()) { + m_playURL1 = "rtsp://" + remoteIP + ":554/live/track0"; + } + ui->comboBox_playURL1->setCurrentText(m_playURL1); } // //流类型 @@ -274,108 +285,116 @@ void GDDCSet::initPullURL(QString remoteIP) { // } // } QString GDDCSet::streamTypeToflowType(QString type) { - if (type == "RTSP") { - return "UDP"; - } else if (type == "RTMP") { - return "TCP"; - } else - return "TCP"; + if (type == "RTSP") { + return "UDP"; + } else if (type == "RTMP") { + return "TCP"; + } else + return "TCP"; } QString GDDCSet::flowTypeTostreamType(QString type) { - if (type == "TCP") { - return "RTMP"; - } else if (type == "UDP") { - return "RTSP"; - } else - return "RTSP"; + if (type == "TCP") { + return "RTMP"; + } else if (type == "UDP") { + return "RTSP"; + } else + return "RTSP"; } void GDDCSet::setConnectURL1Text(QString param) { - ui->pushButton_ConnectURL1->setText(param); + ui->pushButton_ConnectURL1->setText(param); } void GDDCSet::setConnectURL2Text(QString param) { - ui->pushButton_ConnectURL1->setText(param); + ui->pushButton_ConnectURL1->setText(param); } void GDDCSet::setNetCtrlText(QString param) { - ui->pushButton_NetCtrlConnect->setText(param); + ui->pushButton_NetCtrlConnect->setText(param); } void GDDCSet::setPushStreamText(QString param) { - ui->pushButton_pushURL->setText(param); + ui->pushButton_pushURL->setText(param); +} + +void GDDCSet::setPullBtnText(bool flag) { + if (flag) { + ui->pushButton_ConnectURL1->setText("断开"); + } else { + ui->pushButton_ConnectURL1->setText("连接"); + } } // uavID值改变事件 void GDDCSet::on_uavIDSpinBox_valueChanged(int arg1) { - QString streamSource = ui->comboBox_streamSource->currentText(); - int uavID = arg1; - auto iter = g_mapAppName.find(uavID); - if (iter != g_mapAppName.end()) { - if ("地面端" == streamSource) { - QString pushURL = - generatePushURL(uavID, QString::fromStdString(iter->second)); - mapPushURL_yjzh[uavID] = pushURL; // 应急厅指挥平台 - qDebug() << pushURL; - - QString pushURL2 = - generatePushURL2(uavID, QString::fromStdString(iter->second)); - mapPushURL_yjtt[uavID] = pushURL2; // 应急厅铁塔平台 - qDebug() << pushURL2; - - // ui->comboBox_pushURL->setItemText(0, pushURL); - // ui->comboBox_pushURL->setItemText(1, pushURL2); - } else { - if (!ui->radioButton->isChecked()) { - if (ui->comboBox_pushURL->currentIndex() == 0) { - QString pullURL = - generatePullURL(uavID, QString::fromStdString(iter->second)); - ui->comboBox_playURL1->setItemText(0, pullURL); - } else if (ui->comboBox_pushURL->currentIndex() == 1) { - QString pullURL = - generatePullURL2(uavID, QString::fromStdString(iter->second)); - ui->comboBox_playURL1->setItemText(0, pullURL); + QString streamSource = ui->comboBox_streamSource->currentText(); + int uavID = arg1; + auto iter = g_mapAppName.find(uavID); + if (iter != g_mapAppName.end()) { + if ("地面端" == streamSource) { + QString pushURL = + generatePushURL(uavID, QString::fromStdString(iter->second)); + mapPushURL_yjzh[uavID] = pushURL; // 应急厅指挥平台 + qDebug() << pushURL; + + QString pushURL2 = + generatePushURL2(uavID, QString::fromStdString(iter->second)); + mapPushURL_yjtt[uavID] = pushURL2; // 应急厅铁塔平台 + qDebug() << pushURL2; + + // ui->comboBox_pushURL->setItemText(0, pushURL); + // ui->comboBox_pushURL->setItemText(1, pushURL2); + } else { + if (!ui->radioButton->isChecked()) { + if (ui->comboBox_pushURL->currentIndex() == 0) { + QString pullURL = generatePullURL( + uavID, QString::fromStdString(iter->second)); + ui->comboBox_playURL1->setItemText(0, pullURL); + } else if (ui->comboBox_pushURL->currentIndex() == 1) { + QString pullURL = generatePullURL2( + uavID, QString::fromStdString(iter->second)); + ui->comboBox_playURL1->setItemText(0, pullURL); + } + } } - } + } else { } - } else { - } } // 切换拉流来源 void GDDCSet::on_comboBox_streamSource_currentIndexChanged(int index) { - if (0 == index) { - ui->pushButton_pushURL->setEnabled(true); - ui->comboBox_playURL1->setItemText(0, m_playURL1); - } else if (1 == index) { - ui->pushButton_pushURL->setEnabled(false); - int uavID = ui->uavIDSpinBox->value(); - auto iter = g_mapAppName.find(uavID); - if (iter != g_mapAppName.end()) { - // QString pullURL = - // generatePullURL(uavID, QString::fromStdString(iter->second)); - // ui->comboBox_playURL1->setItemText(0, pullURL); - if (!ui->radioButton->isChecked()) { - if (ui->comboBox_pushURL->currentIndex() == 0) { - QString pullURL = - generatePullURL(uavID, QString::fromStdString(iter->second)); - ui->comboBox_playURL1->setItemText(0, pullURL); - } else if (ui->comboBox_pushURL->currentIndex() == 1) { - QString pullURL = - generatePullURL2(uavID, QString::fromStdString(iter->second)); - ui->comboBox_playURL1->setItemText(0, pullURL); + if (0 == index) { + ui->pushButton_pushURL->setEnabled(true); + ui->comboBox_playURL1->setItemText(0, m_playURL1); + } else if (1 == index) { + ui->pushButton_pushURL->setEnabled(false); + int uavID = ui->uavIDSpinBox->value(); + auto iter = g_mapAppName.find(uavID); + if (iter != g_mapAppName.end()) { + // QString pullURL = + // generatePullURL(uavID, QString::fromStdString(iter->second)); + // ui->comboBox_playURL1->setItemText(0, pullURL); + if (!ui->radioButton->isChecked()) { + if (ui->comboBox_pushURL->currentIndex() == 0) { + QString pullURL = generatePullURL( + uavID, QString::fromStdString(iter->second)); + ui->comboBox_playURL1->setItemText(0, pullURL); + } else if (ui->comboBox_pushURL->currentIndex() == 1) { + QString pullURL = generatePullURL2( + uavID, QString::fromStdString(iter->second)); + ui->comboBox_playURL1->setItemText(0, pullURL); + } + } } - } } - } } void GDDCSet::on_radioButton_clicked() { - if (ui->radioButton->isChecked()) { - ui->comboBox_pushURL->setEditable(true); - ui->uavIDSpinBox->setEnabled(false); - } else { - ui->comboBox_pushURL->setEditable(false); - ui->uavIDSpinBox->setEnabled(true); - } + if (ui->radioButton->isChecked()) { + ui->comboBox_pushURL->setEditable(true); + ui->uavIDSpinBox->setEnabled(false); + } else { + ui->comboBox_pushURL->setEditable(false); + ui->uavIDSpinBox->setEnabled(true); + } } diff --git a/Src/GDDC/gddcSet.h b/Src/GDDC/gddcSet.h index 5022e2a..f79edb4 100644 --- a/Src/GDDC/gddcSet.h +++ b/Src/GDDC/gddcSet.h @@ -1,73 +1,77 @@ #ifndef GDDCSET_H #define GDDCSET_H -#include "Src/GDDC/structDefineMyslef.h" -#include "global.h" +#include + #include #include #include #include -#include + +#include "Src/GDDC/structDefineMyslef.h" +#include "global.h" namespace Ui { class GDDCSet; } class GDDCSet : public QWidget { - Q_OBJECT + Q_OBJECT public: - explicit GDDCSet(QWidget *parent = nullptr); - ~GDDCSet(); + explicit GDDCSet(QWidget *parent = nullptr); + ~GDDCSet(); private: - Ui::GDDCSet *ui; + Ui::GDDCSet *ui; - std::map mapPushURL_yjzh; - std::map mapPushURL_yjtt; + std::map mapPushURL_yjzh; + std::map mapPushURL_yjtt; public: - void initUDPSocket(); // 初始化UDPSocket - void initWindow(); // 初始化窗口 - void initParam(); // 初始化参数 - void saveDataToLocalIni(); // 保存数据至本地ini文件 - void initPullURL(QString remoteIP); - QByteArray m_configIniPath; // ini配置文件路径 + void initUDPSocket(); // 初始化UDPSocket + void initWindow(); // 初始化窗口 + void initParam(); // 初始化参数 + void saveDataToLocalIni(); // 保存数据至本地ini文件 + void initPullURL(QString remoteIP); + QByteArray m_configIniPath; // ini配置文件路径 + + QString m_playURL1; // 光电吊舱-视频连接-显示窗口1-URL地址 + QString m_playURL2; // 光电吊舱-视频连接-显示窗口2-URL地址 + QString m_pushURL; // 光电吊舱-推流URL地址 + MyPairNetwork m_myPairNetwork; // 网络通信结构体 + QString m_FlowType; // 流类型 + QString streamTypeToflowType(QString); + QString flowTypeTostreamType(QString); - QString m_playURL1; // 光电吊舱-视频连接-显示窗口1-URL地址 - QString m_playURL2; // 光电吊舱-视频连接-显示窗口2-URL地址 - QString m_pushURL; // 光电吊舱-推流URL地址 - MyPairNetwork m_myPairNetwork; // 网络通信结构体 - QString m_FlowType; // 流类型 - QString streamTypeToflowType(QString); - QString flowTypeTostreamType(QString); + void setConnectURL1Text(QString); + void setConnectURL2Text(QString); + void setNetCtrlText(QString); + void setPushStreamText(QString); - void setConnectURL1Text(QString); - void setConnectURL2Text(QString); - void setNetCtrlText(QString); - void setPushStreamText(QString); + void setPullBtnText(bool flag); signals: - /* int a - * 1视频连接1 - * 2视频连接2 - * 3串口控制-刷新 - * 4串口控制-连接 - * 5网络控制-连接 - * 6视频(1)推流 - * */ - void SignalStartConnect(int a); // 信号开始连接 - void SignalStopConnect(int a); // 信号停止连接 + /* int a + * 1视频连接1 + * 2视频连接2 + * 3串口控制-刷新 + * 4串口控制-连接 + * 5网络控制-连接 + * 6视频(1)推流 + * */ + void SignalStartConnect(int a); // 信号开始连接 + void SignalStopConnect(int a); // 信号停止连接 private slots: - void on_pushButton_ConnectURL1_clicked(); // 视频连接-显示窗口1-连接 - void on_pushButton_ConnectURL2_clicked(); // 视频连接-显示窗口2-连接 - void on_pushButton_serialControlRefalsh_clicked(); // 串口控制-刷新 - void on_pushButton_serialControlConnect_clicked(); // 串口控制-连接 - void on_pushButton_NetCtrlConnect_clicked(); // 网络控制-连接 - void on_pushButton_pushURL_clicked(); // 推流 - // void on_comboBox_streamType_currentIndexChanged(int index); - void on_uavIDSpinBox_valueChanged(int arg1); - void on_comboBox_streamSource_currentIndexChanged(int index); - void on_radioButton_clicked(); + void on_pushButton_ConnectURL1_clicked(); // 视频连接-显示窗口1-连接 + void on_pushButton_ConnectURL2_clicked(); // 视频连接-显示窗口2-连接 + void on_pushButton_serialControlRefalsh_clicked(); // 串口控制-刷新 + void on_pushButton_serialControlConnect_clicked(); // 串口控制-连接 + void on_pushButton_NetCtrlConnect_clicked(); // 网络控制-连接 + void on_pushButton_pushURL_clicked(); // 推流 + // void on_comboBox_streamType_currentIndexChanged(int index); + void on_uavIDSpinBox_valueChanged(int arg1); + void on_comboBox_streamSource_currentIndexChanged(int index); + void on_radioButton_clicked(); }; -#endif // GDDCSET_H +#endif // GDDCSET_H diff --git a/Src/GDDC/gddcdlg.cpp b/Src/GDDC/gddcdlg.cpp index 0f6a960..d7f332f 100644 --- a/Src/GDDC/gddcdlg.cpp +++ b/Src/GDDC/gddcdlg.cpp @@ -1,40 +1,43 @@ #include "gddcdlg.h" -#include "ui_gddcdlg.h" + +#include +#include + #include #include #include #include #include #include -#include -#include + +#include "ui_gddcdlg.h" #pragma comment(lib, "Wtsapi32.lib") using namespace std; DWORD GetmPid(LPCWSTR ProcessName) { - PWTS_PROCESS_INFOW wts; - DWORD Count; - DWORD i = 0; - - BOOL result = - WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wts, &Count); - if (result == 0) { - cout << "WTSEnumerateProcessesW Error" << endl; - - return 1; - } - cout << "WTSEnumerateProcessesW Success" << endl; - for (i; i < Count; i++) { - if (lstrcmpiW(wts[i].pProcessName, ProcessName) == 0) { - DWORD pid = wts[i].ProcessId; - cout << "find pid:" << pid << endl; - - return pid; - break; + PWTS_PROCESS_INFOW wts; + DWORD Count; + DWORD i = 0; + + BOOL result = + WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wts, &Count); + if (result == 0) { + cout << "WTSEnumerateProcessesW Error" << endl; + + return 1; + } + cout << "WTSEnumerateProcessesW Success" << endl; + for (i; i < Count; i++) { + if (lstrcmpiW(wts[i].pProcessName, ProcessName) == 0) { + DWORD pid = wts[i].ProcessId; + cout << "find pid:" << pid << endl; + + return pid; + break; + } } - } - WTSFreeMemory(wts); + WTSFreeMemory(wts); } #define CONFIG_PATH "config.ini" @@ -42,137 +45,146 @@ DWORD GetmPid(LPCWSTR ProcessName) { #define STATEPAGEWIDTH 250 GDDCdlg::GDDCdlg(QWidget *parent) : QWidget(parent), ui(new Ui::GDDCdlg) { - ui->setupUi(this); + ui->setupUi(this); - initWindow(); - initParam(); - initSignalSlot(); + initWindow(); + initParam(); + initSignalSlot(); } GDDCdlg::~GDDCdlg() { - // 停止所有通信 - stopPushURL(); - stopConnectURL1(); - stopConnectURL2(); - stopConnectSerialCtrl(); - stopConnectUDPCtrl(); - stopConnectTCPCtrl(); - - delete m_DlgGDDCSet; - delete m_GDDCCmdDlg; - delete m_GDDCStateDlg; - delete ui; + // 停止所有通信 + stopPushURL(); + stopConnectURL1(); + stopConnectURL2(); + stopConnectSerialCtrl(); + stopConnectUDPCtrl(); + stopConnectTCPCtrl(); + + delete m_DlgGDDCSet; + delete m_GDDCCmdDlg; + delete m_GDDCStateDlg; + delete ui; } // 初始化window void GDDCdlg::initWindow() { - QPalette palette; - // 设置主窗口背景颜色 - palette.setColor(QPalette::Window, QColor(50, 50, 50)); - this->setPalette(palette); - // 嵌入到主窗口 - setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint); - hide(); - - m_DlgGDDCSet = new GDDCSet(this); - m_DlgGDDCSet->setWindowFlags(Qt::Dialog); - m_DlgGDDCSet->setWindowModality(Qt::WindowModal); // 设置为模态对话框 - m_GDDCCmdDlg = new GDDCCmdDlg(this); - m_GDDCStateDlg = new GDDCStateInfo(this); - ui->pushButShowStatePage->setIcon(QIcon(":/res/right.png")); - ui->pushButShowCmdPage->setIcon(QIcon(":/res/down.png")); - - ui->WgtffmpegVideo->setVedioSaveFileDirPath("./Video"); + QPalette palette; + // 设置主窗口背景颜色 + palette.setColor(QPalette::Window, QColor(50, 50, 50)); + this->setPalette(palette); + // 嵌入到主窗口 + setWindowFlags(Qt::CustomizeWindowHint | Qt::FramelessWindowHint); + hide(); + + m_DlgGDDCSet = new GDDCSet(this); + m_DlgGDDCSet->setWindowFlags(Qt::Dialog); + m_DlgGDDCSet->setWindowModality(Qt::WindowModal); // 设置为模态对话框 + m_GDDCCmdDlg = new GDDCCmdDlg(this); + m_GDDCStateDlg = new GDDCStateInfo(this); + ui->pushButShowStatePage->setIcon(QIcon(":/res/right.png")); + ui->pushButShowCmdPage->setIcon(QIcon(":/res/down.png")); + + // connect( + // ui->WgtffmpegVideo, &VideoWidget::sendErrorMessageSignal, this, + // [&](QString message, int type) { + // qDebug() << "GDDC receive message:" << message; + // g_notifyManager->notify(message, "", type); + // }, + // Qt::UniqueConnection); + connect(ui->WgtffmpegVideo, &VideoWidget::sendErrorMessageSignal, this, + &GDDCdlg::showErrorMessage, Qt::UniqueConnection); + ui->WgtffmpegVideo->setVedioSaveFileDirPath("./Video"); } // 初始化参数 void GDDCdlg::initParam() { - pointSelectionTracking = false; - Is_openVideo = false; - isCmdPageShow = true; - isStatePageShow = true; - detectionAreaSetting = false; - connectFlag.resize(12, false); + pointSelectionTracking = false; + Is_openVideo = false; + isCmdPageShow = true; + isStatePageShow = true; + detectionAreaSetting = false; + connectFlag.resize(12, false); } // 初始化信号与槽 void GDDCdlg::initSignalSlot() { - /*******有四种方式*******/ - // 方式一 - connect(ui->pushButtonSet, SIGNAL(clicked()), this, - SLOT(pushButtonSet_clicked())); - // 方式二 - // connect(ui->pushButtonSet,&QPushButton::clicked,this,&::GDDCdlg::pushButtonSet_clicked); - // 方式三 - // connect(ui->pushButtonSet, - // QOverload::of(&QPushButton::clicked),this,&::GDDCdlg::pushButtonSet_clicked); - // 方式四 - // connect(ui->pushButtonSet,&QPushButton::clicked,[=](bool - // check){pushButtonSet_clicked();}); - connect(ui->pushButShowCmdPage, SIGNAL(clicked()), this, - SLOT(pushButShowCmdPage_clicked())); // 控制页面隐藏显示按钮 - connect(ui->pushButShowStatePage, SIGNAL(clicked()), this, - SLOT(pushButShowStatePage_clicked())); // 状态页面隐藏显示按钮 - connect(m_DlgGDDCSet, SIGNAL(SignalStartConnect(int)), this, - SLOT(startConnect(int))); // 开始连接 - connect(m_DlgGDDCSet, SIGNAL(SignalStopConnect(int)), this, - SLOT(stopConnect(int))); // 停止连接 + /*******有四种方式*******/ + // 方式一 + connect(ui->pushButtonSet, SIGNAL(clicked()), this, + SLOT(pushButtonSet_clicked())); + // 方式二 + // connect(ui->pushButtonSet,&QPushButton::clicked,this,&::GDDCdlg::pushButtonSet_clicked); + // 方式三 + // connect(ui->pushButtonSet, + // QOverload::of(&QPushButton::clicked),this,&::GDDCdlg::pushButtonSet_clicked); + // 方式四 + // connect(ui->pushButtonSet,&QPushButton::clicked,[=](bool + // check){pushButtonSet_clicked();}); + connect(ui->pushButShowCmdPage, SIGNAL(clicked()), this, + SLOT(pushButShowCmdPage_clicked())); // 控制页面隐藏显示按钮 + connect(ui->pushButShowStatePage, SIGNAL(clicked()), this, + SLOT(pushButShowStatePage_clicked())); // 状态页面隐藏显示按钮 + connect(m_DlgGDDCSet, SIGNAL(SignalStartConnect(int)), this, + SLOT(startConnect(int))); // 开始连接 + connect(m_DlgGDDCSet, SIGNAL(SignalStopConnect(int)), this, + SLOT(stopConnect(int))); // 停止连接 } // 槽函数开始连接 void GDDCdlg::startConnect(int type) { - switch (type) { - case 1: // 播放视频1 - stopConnectURL2(); - startConnectURL1(); - break; - case 2: // 播放视频2 - stopConnectURL1(); - startConnectURL2(); - break; - case 3: // 串口控制 - startConnectSerialCtrl(); - break; - case 4: // UDP控制 - stopConnectTCPCtrl(); - startConnectUDPCtrl(); - break; - case 5: // TCP控制 - stopConnectUDPCtrl(); - startConnectTCPCtrl(); - break; - case 6: // 视频(1)推流 - startPushURL(); - break; - default: - break; - } + switch (type) { + case 1: // 播放视频1 + stopConnectURL2(); + startConnectURL1(); + break; + case 2: // 播放视频2 + stopConnectURL1(); + startConnectURL2(); + break; + case 3: // 串口控制 + startConnectSerialCtrl(); + break; + case 4: // UDP控制 + stopConnectTCPCtrl(); + startConnectUDPCtrl(); + break; + case 5: // TCP控制 + stopConnectUDPCtrl(); + startConnectTCPCtrl(); + break; + case 6: // 视频(1)推流 + startPushURL(); + break; + default: + break; + } } // 槽函数停止连接 void GDDCdlg::stopConnect(int type) { - switch (type) { - case 1: - stopConnectURL1(); - break; - case 2: - stopConnectURL2(); - break; - case 3: - stopConnectSerialCtrl(); - break; - case 4: - stopConnectUDPCtrl(); - break; - case 5: - stopConnectTCPCtrl(); - break; - case 6: - stopPushURL(); - break; - default: - break; - } + switch (type) { + case 1: + stopConnectURL1(); + break; + case 2: + stopConnectURL2(); + break; + case 3: + stopConnectSerialCtrl(); + break; + case 4: + stopConnectUDPCtrl(); + break; + case 5: + stopConnectTCPCtrl(); + break; + case 6: + stopPushURL(); + break; + default: + break; + } } // bool GDDCdlg::eventFilter(QObject *watched, QEvent *event) // { @@ -190,421 +202,447 @@ void GDDCdlg::stopConnect(int type) { // } // 鼠标左键 void GDDCdlg::mousePressEvent(QMouseEvent *event) { - // 如果鼠标左键按下 - if (event->type() == QEvent::MouseButtonPress) { - // AI检测区域设置 - if (m_GDDCCmdDlg->detectionAreaSetting == true) { - QPointF sPoint1 = event->globalPosition(); - sPoint1 = QCursor::pos(); - QPointF widgetPoint = ui->WgtffmpegVideo->mapFromGlobal(sPoint1); - double a = ui->WgtffmpegVideo->width(); - double b = ui->WgtffmpegVideo->height(); - double dir = 1920 / a * widgetPoint.rx() - 960; - double pitch = -(1080 / b * widgetPoint.ry() - 540); - m_GDDCCmdDlg->setAIDetcLineEditText(QString::number((int)dir), - QString::number((int)pitch)); - } - // 目标跟踪 - if (m_GDDCCmdDlg->pointSelectionTracking == true) { - QPointF sPoint1 = event->globalPosition(); - QPointF widgetPoint = ui->WgtffmpegVideo->mapFromGlobal(sPoint1); - double a = ui->WgtffmpegVideo->width(); - double b = ui->WgtffmpegVideo->height(); - double dir = 1920 / a * widgetPoint.rx() - 960; - double pitch = -(1080 / b * widgetPoint.ry() - 540); - std::byte buffer[10]; - buffer[0] = (std::byte)0x3A; - buffer[1] = (std::byte)(dir); - buffer[2] = (std::byte)((int)dir >> 8); - buffer[3] = (std::byte)pitch; - buffer[4] = (std::byte)((int)pitch >> 8); - buffer[5] = (std::byte)0x00; - buffer[6] = (std::byte)0x00; - buffer[7] = (std::byte)0x00; - buffer[8] = (std::byte)0x00; - buffer[9] = (std::byte)0x00; - - // 发送5次 - m_GDDCCmdDlg->sendCurDate(buffer, 3); + // 如果鼠标左键按下 + if (event->type() == QEvent::MouseButtonPress) { + // AI检测区域设置 + if (m_GDDCCmdDlg->detectionAreaSetting == true) { + QPointF sPoint1 = event->globalPosition(); + sPoint1 = QCursor::pos(); + QPointF widgetPoint = ui->WgtffmpegVideo->mapFromGlobal(sPoint1); + double a = ui->WgtffmpegVideo->width(); + double b = ui->WgtffmpegVideo->height(); + double dir = 1920 / a * widgetPoint.rx() - 960; + double pitch = -(1080 / b * widgetPoint.ry() - 540); + m_GDDCCmdDlg->setAIDetcLineEditText(QString::number((int)dir), + QString::number((int)pitch)); + } + // 目标跟踪 + if (m_GDDCCmdDlg->pointSelectionTracking == true) { + QPointF sPoint1 = event->globalPosition(); + QPointF widgetPoint = ui->WgtffmpegVideo->mapFromGlobal(sPoint1); + double a = ui->WgtffmpegVideo->width(); + double b = ui->WgtffmpegVideo->height(); + double dir = 1920 / a * widgetPoint.rx() - 960; + double pitch = -(1080 / b * widgetPoint.ry() - 540); + std::byte buffer[10]; + buffer[0] = (std::byte)0x3A; + buffer[1] = (std::byte)(dir); + buffer[2] = (std::byte)((int)dir >> 8); + buffer[3] = (std::byte)pitch; + buffer[4] = (std::byte)((int)pitch >> 8); + buffer[5] = (std::byte)0x00; + buffer[6] = (std::byte)0x00; + buffer[7] = (std::byte)0x00; + buffer[8] = (std::byte)0x00; + buffer[9] = (std::byte)0x00; + + // 发送5次 + m_GDDCCmdDlg->sendCurDate(buffer, 3); + } } - } } // 鼠标移动 void GDDCdlg::mouseMoveEvent(QMouseEvent *event) { - if (m_GDDCCmdDlg->detectionAreaSetting == true) { - // qDebug() << this->geometry().x(); - // qDebug() << this->geometry().y(); - QPointF sPoint1 = event->globalPosition(); - // qDebug()<<"相对于屏幕坐标1:"<<"("<mapFromGlobal(sPoint2); - // qDebug()<<"相对于窗口坐标:"<<"("<WgtffmpegVideo->mapFromGlobal(sPoint1); - // qDebug()<<"相对于控件坐标:"<<"("<WgtffmpegVideo->width(); - double b = ui->WgtffmpegVideo->height(); - double dir = 1920 / a * widgetPoint.rx() - 960; - double pitch = -(1080 / b * widgetPoint.ry() - 540); - m_GDDCCmdDlg->setAIDetcLineEditText(QString::number((int)dir), - QString::number((int)pitch)); - } + if (m_GDDCCmdDlg->detectionAreaSetting == true) { + // qDebug() << this->geometry().x(); + // qDebug() << this->geometry().y(); + QPointF sPoint1 = event->globalPosition(); + // qDebug()<<"相对于屏幕坐标1:"<<"("<mapFromGlobal(sPoint2); + // qDebug()<<"相对于窗口坐标:"<<"("<WgtffmpegVideo->mapFromGlobal(sPoint1); + // qDebug()<<"相对于控件坐标:"<<"("<WgtffmpegVideo->width(); + double b = ui->WgtffmpegVideo->height(); + double dir = 1920 / a * widgetPoint.rx() - 960; + double pitch = -(1080 / b * widgetPoint.ry() - 540); + m_GDDCCmdDlg->setAIDetcLineEditText(QString::number((int)dir), + QString::number((int)pitch)); + } } // 区域重绘 void GDDCdlg::resizeEvent(QResizeEvent *event) { - resizeUI(); // 重新设置布局 + resizeUI(); // 重新设置布局 } // 重新设置布局 void GDDCdlg::resizeUI() { - /* -------------->x - * | (0,0) - * | - * | - * | - * | - * ↓ y - */ - double GDDCPageHeight = (double)(this->height()); - double GDDCPageWidth = (double)(this->width()); - // qDebug()<<"宽度,高度:"<setGeometry(0, GDDCPageHeight - cmdAreaHeight, - (int)cmdAreaWidth, (int)cmdAreaHeight); - m_GDDCCmdDlg->setTabWidgetGeometry(0, 0, cmdAreaWidth, cmdAreaHeight); - - /*********状态区位置和大小设置***********/ - double stateAreaHeight = GDDCPageHeight; - double stateAreaWidth; - if (isStatePageShow) { - stateAreaWidth = STATEPAGEWIDTH; - } else { - stateAreaWidth = 0; - } - m_GDDCStateDlg->setGeometry(GDDCPageWidth - stateAreaWidth, 0, stateAreaWidth, - stateAreaHeight); - m_GDDCStateDlg->setTableViewGeometry(0, 0, stateAreaWidth, stateAreaHeight); - - /*******视频区位置和大小设置********/ - double VideoAreaHeight = GDDCPageHeight - cmdAreaHeight; // 视频区高度 - double VideoAreaWidth = GDDCPageWidth - stateAreaWidth; // 视频区宽度 - // //高度值相对比较大 - // if(VideoAreaHeight*16>VideoAreaWidth*9) - // { - // double setVideoAreaWidth = VideoAreaWidth;//等于吊舱页面宽度-状态区高度 - // double setVideoAreaHeight = VideoAreaWidth*9/16; - // ui->WgtffmpegVideo->setGeometry(0,0.5*(VideoAreaHeight-setVideoAreaHeight),(int)setVideoAreaWidth,(int)setVideoAreaHeight); - // } - // //宽度值相对比较大 - // else - // { - // double setVideoAreaHeight = - // VideoAreaHeight;//等于吊舱页面高度-控制区高度 double setVideoAreaWidth - // = VideoAreaHeight*16/9; - // ui->WgtffmpegVideo->setGeometry(0.5*(VideoAreaWidth-setVideoAreaWidth),0,(int)setVideoAreaWidth,(int)setVideoAreaHeight); - // } - ui->WgtffmpegVideo->setGeometry(20, 20, (int)VideoAreaWidth, - (int)VideoAreaHeight); - - /**************设置按钮****************/ - ui->pushButtonSet->setGeometry(GDDCPageWidth - stateAreaWidth - 45, 0, 40, - 40); - - /**********控制页显示隐藏按钮********/ - ui->pushButShowCmdPage->setGeometry( - cmdAreaWidth * 0.5, GDDCPageHeight - cmdAreaHeight - 15, 50, 15); - ui->pushButShowCmdPage->raise(); - - /**********状态页显示隐藏按钮********/ - ui->pushButShowStatePage->setGeometry(GDDCPageWidth - stateAreaWidth - 15, - (stateAreaHeight - cmdAreaHeight) * 0.5, - 15, 50); - ui->pushButShowStatePage->raise(); + /* -------------->x + * | (0,0) + * | + * | + * | + * | + * ↓ y + */ + double GDDCPageHeight = (double)(this->height()); + double GDDCPageWidth = (double)(this->width()); + // qDebug()<<"宽度,高度:"<setGeometry(0, GDDCPageHeight - cmdAreaHeight, + (int)cmdAreaWidth, (int)cmdAreaHeight); + m_GDDCCmdDlg->setTabWidgetGeometry(0, 0, cmdAreaWidth, cmdAreaHeight); + + /*********状态区位置和大小设置***********/ + double stateAreaHeight = GDDCPageHeight; + double stateAreaWidth; + if (isStatePageShow) { + stateAreaWidth = STATEPAGEWIDTH; + } else { + stateAreaWidth = 0; + } + m_GDDCStateDlg->setGeometry(GDDCPageWidth - stateAreaWidth, 0, + stateAreaWidth, stateAreaHeight); + m_GDDCStateDlg->setTableViewGeometry(0, 0, stateAreaWidth, stateAreaHeight); + + /*******视频区位置和大小设置********/ + double VideoAreaHeight = GDDCPageHeight - cmdAreaHeight; // 视频区高度 + double VideoAreaWidth = GDDCPageWidth - stateAreaWidth; // 视频区宽度 + // //高度值相对比较大 + // if(VideoAreaHeight*16>VideoAreaWidth*9) + // { + // double setVideoAreaWidth = + // VideoAreaWidth;//等于吊舱页面宽度-状态区高度 double + // setVideoAreaHeight = VideoAreaWidth*9/16; + // ui->WgtffmpegVideo->setGeometry(0,0.5*(VideoAreaHeight-setVideoAreaHeight),(int)setVideoAreaWidth,(int)setVideoAreaHeight); + // } + // //宽度值相对比较大 + // else + // { + // double setVideoAreaHeight = + // VideoAreaHeight;//等于吊舱页面高度-控制区高度 double + // setVideoAreaWidth = VideoAreaHeight*16/9; + // ui->WgtffmpegVideo->setGeometry(0.5*(VideoAreaWidth-setVideoAreaWidth),0,(int)setVideoAreaWidth,(int)setVideoAreaHeight); + // } + ui->WgtffmpegVideo->setGeometry(0, 0, (int)VideoAreaWidth, + (int)VideoAreaHeight); + + /**************设置按钮****************/ + ui->pushButtonSet->setGeometry(GDDCPageWidth - stateAreaWidth, 0, 30, 30); + ui->pushButtonSet->raise(); + + /**********控制页显示隐藏按钮********/ + ui->pushButShowCmdPage->setGeometry( + cmdAreaWidth * 0.5, GDDCPageHeight - cmdAreaHeight - 15, 50, 15); + ui->pushButShowCmdPage->raise(); + + /**********状态页显示隐藏按钮********/ + ui->pushButShowStatePage->setGeometry( + GDDCPageWidth - stateAreaWidth - 15, + (stateAreaHeight - cmdAreaHeight) * 0.5, 15, 50); + ui->pushButShowStatePage->raise(); } void GDDCdlg::setGlobalSetMap( std::unordered_map &gSetMap) { - if (m_DlgGDDCSet) { - m_DlgGDDCSet->initPullURL(gSetMap["光电吊舱"].net.remoteIp); - } + if (m_DlgGDDCSet) { + m_DlgGDDCSet->initPullURL(gSetMap["光电吊舱"].net.remoteIp); + } } // 定时器处理 void GDDCdlg::GDDCControlTimeOut() { - if (m_GDDCCmdDlg->sendTimes > 0) { // 优先发送次数指令 - m_GDDCCmdDlg->sendTimes -= 1; - - // UDP控制 - if (connectFlag[3]) { - udpSocket->writeDatagram(m_GDDCCmdDlg->m_DCcmdBuffer, - m_DlgGDDCSet->m_myPairNetwork.getRemoteAddr(), - m_DlgGDDCSet->m_myPairNetwork.getRemotePort()); + if (m_GDDCCmdDlg->sendTimes > 0) { // 优先发送次数指令 + m_GDDCCmdDlg->sendTimes -= 1; + + // UDP控制 + if (connectFlag[3]) { + udpSocket->writeDatagram( + m_GDDCCmdDlg->m_DCcmdBuffer, + m_DlgGDDCSet->m_myPairNetwork.getRemoteAddr(), + m_DlgGDDCSet->m_myPairNetwork.getRemotePort()); + } + // TCP控制 + + // 串口控制 + + if (m_GDDCCmdDlg->sendTimes == 0) { + m_GDDCCmdDlg->clearTJDCCmdBuffer(); + } + } else { // 发送常发帧或长按指令 + m_GDDCCmdDlg->UpdateDataTJDC(); + // UDP控制 + if (connectFlag[3]) { + udpSocket->writeDatagram( + m_GDDCCmdDlg->m_DCcmdBuffer, + m_DlgGDDCSet->m_myPairNetwork.getRemoteAddr(), + m_DlgGDDCSet->m_myPairNetwork.getRemotePort()); + } + + // TCP控制 + + // 串口控制 } - // TCP控制 - - // 串口控制 - - if (m_GDDCCmdDlg->sendTimes == 0) { - m_GDDCCmdDlg->clearTJDCCmdBuffer(); - } - } else { // 发送常发帧或长按指令 - m_GDDCCmdDlg->UpdateDataTJDC(); - // UDP控制 - if (connectFlag[3]) { - udpSocket->writeDatagram(m_GDDCCmdDlg->m_DCcmdBuffer, - m_DlgGDDCSet->m_myPairNetwork.getRemoteAddr(), - m_DlgGDDCSet->m_myPairNetwork.getRemotePort()); - } - - // TCP控制 - - // 串口控制 - } } // 播放视频1 void GDDCdlg::startConnectURL1() { - if (!connectFlag[0]) { - connectFlag[0] = true; - ffmpegvideoDlg *videoDlg = ui->WgtffmpegVideo; - // 开始拉流 - videoDlg->m_flowType = m_DlgGDDCSet->m_FlowType; - videoDlg->setStreamIP(m_DlgGDDCSet->m_playURL1); - videoDlg->setPlayVideo(true); - // ui->WgtffmpegVideo->play(m_DlgGDDCSet->m_playURL1); - } + if (!connectFlag[0]) { + connectFlag[0] = true; + /* ffmpegvideoDlg版本 + ffmpegvideoDlg *videoDlg = ui->WgtffmpegVideo; + // 开始拉流 + videoDlg->m_flowType = m_DlgGDDCSet->m_FlowType; + videoDlg->setStreamIP(m_DlgGDDCSet->m_playURL1); + videoDlg->setPlayVideo(true); + // ui->WgtffmpegVideo->play(m_DlgGDDCSet->m_playURL1); + */ + + VideoWidget *videoWidget = ui->WgtffmpegVideo; + if (!videoWidget->play(m_DlgGDDCSet->m_playURL1)) { + g_notifyManager->notify("获取视频流失败!", "", 2, 3000); + // ui->WgtffmpegVideo->stopPlay(); + // m_DlgGDDCSet->setPullBtnText(false); + }; + } } // 关闭视频1 void GDDCdlg::stopConnectURL1() { - if (connectFlag[0]) { - connectFlag[0] = false; - // Is_openVideo = false; - // ui->WgtffmpegVideo->m_PlayStatus = Is_openVideo; - ui->WgtffmpegVideo->setPlayVideo(false); - // ui->WgtffmpegVideo->stop(); - } + if (connectFlag[0]) { + connectFlag[0] = false; + // ui->WgtffmpegVideo->setPlayVideo(false); + ui->WgtffmpegVideo->stopPlay(); + } } // 播放视频2 void GDDCdlg::startConnectURL2() { - if (!connectFlag[1]) { - connectFlag[1] = true; - } + if (!connectFlag[1]) { + connectFlag[1] = true; + } } // 关闭视频2 void GDDCdlg::stopConnectURL2() { - if (connectFlag[1]) { - connectFlag[1] = false; - } + if (connectFlag[1]) { + connectFlag[1] = false; + } } void GDDCdlg::startConnectSerialCtrl() { - if (!connectFlag[2]) { - connectFlag[2] = true; - } + if (!connectFlag[2]) { + connectFlag[2] = true; + } } void GDDCdlg::stopConnectSerialCtrl() { - if (connectFlag[2]) { - connectFlag[2] = false; - } + if (connectFlag[2]) { + connectFlag[2] = false; + } } // 开始UDP控制通信 void GDDCdlg::startConnectUDPCtrl() { - if (!connectFlag[3]) { - /*启动定时器*/ - GDDCControlTimer = new QTimer(); - GDDCControlTimer->setInterval(100); - connect(GDDCControlTimer, &QTimer::timeout, this, - [=]() { GDDCControlTimeOut(); }); - GDDCControlTimer->start(); - - // 创建udp socket对象 - udpSocket = new QUdpSocket(this); - /*接收*/ - // QList ipAddressesList = - // QNetworkInterface::allAddresses();//获取本机ip - udpSocket->bind(m_DlgGDDCSet->m_myPairNetwork.getLocalPort()); - connect(udpSocket, SIGNAL(readyRead()), this, SLOT(UDPMessageReceive())); - connectFlag[3] = true; - } + if (!connectFlag[3]) { + /*启动定时器*/ + GDDCControlTimer = new QTimer(); + GDDCControlTimer->setInterval(100); + connect(GDDCControlTimer, &QTimer::timeout, this, [=]() { + GDDCControlTimeOut(); + }); + GDDCControlTimer->start(); + + // 创建udp socket对象 + udpSocket = new QUdpSocket(this); + /*接收*/ + // QList ipAddressesList = + // QNetworkInterface::allAddresses();//获取本机ip + udpSocket->bind(m_DlgGDDCSet->m_myPairNetwork.getLocalPort()); + connect(udpSocket, SIGNAL(readyRead()), this, + SLOT(UDPMessageReceive())); + connectFlag[3] = true; + } } // 停止UDP控制通信 void GDDCdlg::stopConnectUDPCtrl() { - if (connectFlag[3]) { - // 关闭定时器 - GDDCControlTimer->stop(); - delete GDDCControlTimer; - udpSocket->abort(); // 关闭套接字,并丢缓冲区中的所有待处理数据 - delete udpSocket; - connectFlag[3] = false; - } + if (connectFlag[3]) { + // 关闭定时器 + GDDCControlTimer->stop(); + delete GDDCControlTimer; + udpSocket->abort(); // 关闭套接字,并丢缓冲区中的所有待处理数据 + delete udpSocket; + connectFlag[3] = false; + } } // 开始TCP控制通信 void GDDCdlg::startConnectTCPCtrl() { - if (!connectFlag[4]) { - connectFlag[4] = true; - } + if (!connectFlag[4]) { + connectFlag[4] = true; + } } // 停止TCP控制通信 void GDDCdlg::stopConnectTCPCtrl() { - if (connectFlag[4]) { - connectFlag[4] = false; - } + if (connectFlag[4]) { + connectFlag[4] = false; + } } // 开始视频推流 void GDDCdlg::startPushURL() { - if (!connectFlag[5]) { - - // //方式1:命令行推流 - // process = new QProcess(); - // connect(process, &QProcess::readyReadStandardOutput, this, [=]() mutable - // { - // QString Output = process->readAllStandardOutput(); - // qDebug() << "Output:" << Output; - // }); - // connect(process, &QProcess::readyReadStandardError, this, [=]() mutable { - // QString Error = process->readAllStandardError(); - // qDebug() << "Error Output:" << Error; - // }); - - // // process->start("cmd",QStringList()<<"/c"<<"ffmpeg -i - // // rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid -c copy -f - // flv - // // rtmp://182.92.130.23/app/test"); - - // QStringList m_cmd; - // QString str; - // // str = "ffmpeg -i " + m_DlgGDDCSet->m_playURL1 + " -c copy -f flv " + - // // m_DlgGDDCSet->m_pushURL; - // str = "ffmpeg -rtsp_transport tcp -i " + m_DlgGDDCSet->m_playURL1 + " - // -c:v libx264 -c:a copy -f flv " + - // m_DlgGDDCSet->m_pushURL; - // m_cmd << "/c" << str; - // process->start("cmd", m_cmd); - - // //方式2:代码推流 - // if(!connectFlag[0]) - // { - // QMessageBox::information(NULL, tr("提示"), "请先开始连接", - // QMessageBox::Ok); m_DlgGDDCSet->setPushStreamText("推送"); return; - // } - ffmpegvideoDlg *videoDlg = ui->WgtffmpegVideo; - videoDlg->setStreamIP(m_DlgGDDCSet->m_playURL1); - videoDlg->setPushStreamIP(m_DlgGDDCSet->m_pushURL); - qDebug() << "DLG:" << m_DlgGDDCSet->m_pushURL; - videoDlg->setPushStream(true); - m_DlgGDDCSet->setPushStreamText("停止推送"); - - connectFlag[5] = true; - } + if (!connectFlag[5]) { + // //方式1:命令行推流 + // process = new QProcess(); + // connect(process, &QProcess::readyReadStandardOutput, this, [=]() + // mutable + // { + // QString Output = process->readAllStandardOutput(); + // qDebug() << "Output:" << Output; + // }); + // connect(process, &QProcess::readyReadStandardError, this, [=]() + // mutable { + // QString Error = process->readAllStandardError(); + // qDebug() << "Error Output:" << Error; + // }); + + // // process->start("cmd",QStringList()<<"/c"<<"ffmpeg -i + // // rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid -c copy + // -f flv + // // rtmp://182.92.130.23/app/test"); + + // QStringList m_cmd; + // QString str; + // // str = "ffmpeg -i " + m_DlgGDDCSet->m_playURL1 + " -c copy -f flv " + // + + // // m_DlgGDDCSet->m_pushURL; + // str = "ffmpeg -rtsp_transport tcp -i " + m_DlgGDDCSet->m_playURL1 + " + // -c:v libx264 -c:a copy -f flv " + + // m_DlgGDDCSet->m_pushURL; + // m_cmd << "/c" << str; + // process->start("cmd", m_cmd); + + // //方式2:代码推流 + // if(!connectFlag[0]) + // { + // QMessageBox::information(NULL, tr("提示"), "请先开始连接", + // QMessageBox::Ok); m_DlgGDDCSet->setPushStreamText("推送"); + // return; + // } + + /* ffmpegvideoDlg版本 + ffmpegvideoDlg *videoDlg = ui->WgtffmpegVideo; + videoDlg->setStreamIP(m_DlgGDDCSet->m_playURL1); + videoDlg->setPushStreamIP(m_DlgGDDCSet->m_pushURL); + qDebug() << "DLG:" << m_DlgGDDCSet->m_pushURL; + videoDlg->setPushStream(true); + */ + + ui->WgtffmpegVideo->setPullURL(m_DlgGDDCSet->m_playURL1); + if (!ui->WgtffmpegVideo->pushStream(m_DlgGDDCSet->m_pushURL)) { + g_notifyManager->notify("推流失败!", "", 2, 3000); + }; + m_DlgGDDCSet->setPushStreamText("停止推送"); + + connectFlag[5] = true; + } } // 停止视频推流 void GDDCdlg::stopPushURL() { - if (connectFlag[5]) { - - // //方式1:命令行推流 - // if (process != nullptr) { - // process->terminate(); - // process->close(); - // process->kill(); - // // 检查进程退出状态 - // if (process->exitStatus() == QProcess::CrashExit) { - // qDebug() << "Process crashed"; - // } else { - // qDebug() << "Process exited normally"; - // } - // delete process; - - // // 推流进程未自动关闭,手动关闭 - // int pids = GetmPid(L"ffmpeg.exe"); - // qDebug() << "ffmpeg.exe进程的pid为:" << pids; - // if (pids != 0) { - // QStringList m_cmd; - // m_cmd << "/c" << "taskkill /pid " << QString::number(pids) << " -f"; - // QProcess::startDetached("cmd", m_cmd); - // } - // } - - // 方式2:代码推流 - // ui->WgtffmpegVideo->setPushStreamIP(""); - ui->WgtffmpegVideo->setPushStream(false); - m_DlgGDDCSet->setPushStreamText("推送"); - - connectFlag[5] = false; - } + if (connectFlag[5]) { + // //方式1:命令行推流 + // if (process != nullptr) { + // process->terminate(); + // process->close(); + // process->kill(); + // // 检查进程退出状态 + // if (process->exitStatus() == QProcess::CrashExit) { + // qDebug() << "Process crashed"; + // } else { + // qDebug() << "Process exited normally"; + // } + // delete process; + + // // 推流进程未自动关闭,手动关闭 + // int pids = GetmPid(L"ffmpeg.exe"); + // qDebug() << "ffmpeg.exe进程的pid为:" << pids; + // if (pids != 0) { + // QStringList m_cmd; + // m_cmd << "/c" << "taskkill /pid " << QString::number(pids) << " + // -f"; QProcess::startDetached("cmd", m_cmd); + // } + // } + + // 方式2:代码推流 + // ui->WgtffmpegVideo->setPushStream(false); + ui->WgtffmpegVideo->stopPushStream(); + m_DlgGDDCSet->setPushStreamText("推送"); + + connectFlag[5] = false; + } } // 设置页面弹出 void GDDCdlg::pushButtonSet_clicked() { - m_DlgGDDCSet->show(); - m_DlgGDDCSet->activateWindow(); // 置为顶层 + m_DlgGDDCSet->show(); + m_DlgGDDCSet->activateWindow(); // 置为顶层 } // udp数据接收 void GDDCdlg::UDPMessageReceive() { - QByteArray data; - data.resize(udpSocket->pendingDatagramSize()); - QHostAddress addr; - quint16 port; - udpSocket->readDatagram(data.data(), data.size(), &addr, &port); - - // 吊舱状态数据更新 - m_GDDCStateDlg->UDPMessageReceive(data, data.size()); + QByteArray data; + data.resize(udpSocket->pendingDatagramSize()); + QHostAddress addr; + quint16 port; + udpSocket->readDatagram(data.data(), data.size(), &addr, &port); + + // 吊舱状态数据更新 + m_GDDCStateDlg->UDPMessageReceive(data, data.size()); } // 控制页面隐藏与显示 void GDDCdlg::pushButShowCmdPage_clicked() { - if (isCmdPageShow) { - m_GDDCCmdDlg->setVisible(false); - isCmdPageShow = false; - resizeUI(); - ui->pushButShowCmdPage->setIcon(QIcon(":/res/up.png")); - // ui->pushButton->setGeometry(this->width()/2,this->height()-50,50,50); - } else { - m_GDDCCmdDlg->setVisible(true); - isCmdPageShow = true; - resizeUI(); - ui->pushButShowCmdPage->setIcon(QIcon(":/res/down.png")); - // ui->pushButton->setGeometry(this->width()/2,ui->tabWidget->height(),50,50); - } + if (isCmdPageShow) { + m_GDDCCmdDlg->setVisible(false); + isCmdPageShow = false; + resizeUI(); + ui->pushButShowCmdPage->setIcon(QIcon(":/res/up.png")); + // ui->pushButton->setGeometry(this->width()/2,this->height()-50,50,50); + } else { + m_GDDCCmdDlg->setVisible(true); + isCmdPageShow = true; + resizeUI(); + ui->pushButShowCmdPage->setIcon(QIcon(":/res/down.png")); + // ui->pushButton->setGeometry(this->width()/2,ui->tabWidget->height(),50,50); + } } // 状态页面隐藏与显示 void GDDCdlg::pushButShowStatePage_clicked() { - if (isStatePageShow) { - m_GDDCStateDlg->setVisible(false); - isStatePageShow = false; - resizeUI(); - ui->pushButShowStatePage->setIcon(QIcon(":/res/left.png")); - } else { - m_GDDCStateDlg->setVisible(true); - isStatePageShow = true; - resizeUI(); - ui->pushButShowStatePage->setIcon(QIcon(":/res/right.png")); - // ui->pushButton->setGeometry(this->width()/2,ui->tabWidget->height(),50,50); - } + if (isStatePageShow) { + m_GDDCStateDlg->setVisible(false); + isStatePageShow = false; + resizeUI(); + ui->pushButShowStatePage->setIcon(QIcon(":/res/left.png")); + } else { + m_GDDCStateDlg->setVisible(true); + isStatePageShow = true; + resizeUI(); + ui->pushButShowStatePage->setIcon(QIcon(":/res/right.png")); + // ui->pushButton->setGeometry(this->width()/2,ui->tabWidget->height(),50,50); + } +} + +void GDDCdlg::showErrorMessage(QString message, int type) { + g_notifyManager->notify(message, "", type, 3000); } diff --git a/Src/GDDC/gddcdlg.h b/Src/GDDC/gddcdlg.h index 07e5fe5..623d4fd 100644 --- a/Src/GDDC/gddcdlg.h +++ b/Src/GDDC/gddcdlg.h @@ -3,7 +3,6 @@ #include "Src/GDDC/gddcSet.h" // #include "Src/Video/cffmpeg_decode.h" -#include "gddcCmdDlg.h" //吊舱控制对话框 #include #include #include @@ -17,86 +16,92 @@ #include #include #include + +#include "gddcCmdDlg.h" //吊舱控制对话框 +#include "global.h" // #include "ui_gddcCmdDlg.h" //吊舱控制对话框ui -#include "gddcStateInfo.h" //吊舱状态信息显示对话框 +#include "gddcStateInfo.h" //吊舱状态信息显示对话框 // #include "ui_gddcStateInfo.h" //吊舱状态信息显示对话框 // #include "ui_gddcSet.h" -#include "QProcess" #include #include +#include "QProcess" + #define cmdLength 44 namespace Ui { class GDDCdlg; } class GDDCdlg : public QWidget { - Q_OBJECT + Q_OBJECT public: - explicit GDDCdlg(QWidget *parent = nullptr); - ~GDDCdlg(); + explicit GDDCdlg(QWidget *parent = nullptr); + ~GDDCdlg(); private: - Ui::GDDCdlg *ui; - QTimer *GDDCControlTimer; + Ui::GDDCdlg *ui; + QTimer *GDDCControlTimer; protected: - void resizeEvent(QResizeEvent *event); + void resizeEvent(QResizeEvent *event); public: - void initWindow(); // 初始化窗口 - void initParam(); // 初始化参数 - void initSignalSlot(); // 初始化信号与槽 - void resizeUI(); // 重新设置布局 - void setGlobalSetMap(std::unordered_map &gSetMap); + void initWindow(); // 初始化窗口 + void initParam(); // 初始化参数 + void initSignalSlot(); // 初始化信号与槽 + void resizeUI(); // 重新设置布局 + void setGlobalSetMap(std::unordered_map &gSetMap); - GDDCSet *m_DlgGDDCSet; // 光电吊舱设置对话框 - GDDCCmdDlg *m_GDDCCmdDlg; // 光电吊舱控制对话框 - GDDCStateInfo *m_GDDCStateDlg; // 光电吊舱状态数据对话框 + GDDCSet *m_DlgGDDCSet; // 光电吊舱设置对话框 + GDDCCmdDlg *m_GDDCCmdDlg; // 光电吊舱控制对话框 + GDDCStateInfo *m_GDDCStateDlg; // 光电吊舱状态数据对话框 public: - // socket对象 - QUdpSocket *udpSocket; - // QString RemoteIP; //目标IP - // QHostAddress RemoteAddr; //目标地址 - // quint16 RemotePort; //目标port - QString localIP; // 本地IP - QHostAddress localAddr; // 本地地址 - quint16 localPort; // 本地port - QProcess *process; // 执行CMD - QThread workerThread; // 线程 - // bool eventFilter(QObject *,QEvent *); //事件过滤器 - void mousePressEvent(QMouseEvent *event); // 事件过滤器 - void mouseMoveEvent(QMouseEvent *event); // 事件过滤器 + // socket对象 + QUdpSocket *udpSocket; + // QString RemoteIP; //目标IP + // QHostAddress RemoteAddr; //目标地址 + // quint16 RemotePort; //目标port + QString localIP; // 本地IP + QHostAddress localAddr; // 本地地址 + quint16 localPort; // 本地port + QProcess *process; // 执行CMD + QThread workerThread; // 线程 + // bool eventFilter(QObject *,QEvent *); //事件过滤器 + void mousePressEvent(QMouseEvent *event); // 事件过滤器 + void mouseMoveEvent(QMouseEvent *event); // 事件过滤器 - void startConnectURL1(); - void stopConnectURL1(); - void startConnectURL2(); - void stopConnectURL2(); - void startConnectSerialCtrl(); - void stopConnectSerialCtrl(); - void startConnectUDPCtrl(); - void stopConnectUDPCtrl(); - void startConnectTCPCtrl(); - void stopConnectTCPCtrl(); - void startPushURL(); - void stopPushURL(); + void startConnectURL1(); + void stopConnectURL1(); + void startConnectURL2(); + void stopConnectURL2(); + void startConnectSerialCtrl(); + void stopConnectSerialCtrl(); + void startConnectUDPCtrl(); + void stopConnectUDPCtrl(); + void startConnectTCPCtrl(); + void stopConnectTCPCtrl(); + void startPushURL(); + void stopPushURL(); public: - bool pointSelectionTracking; // 选点跟踪 - bool Is_openVideo; // 视频是否已打开,默认未打开 - std::vector connectFlag; // 0视频流1;1视频流2;2串口通信,3网口通信 - bool isCmdPageShow; // 控制页是否显示 - bool isStatePageShow; // 状态页是否显示 - bool detectionAreaSetting; // 检测区域设置 + bool pointSelectionTracking; // 选点跟踪 + bool Is_openVideo; // 视频是否已打开,默认未打开 + std::vector connectFlag; // 0视频流1;1视频流2;2串口通信,3网口通信 + bool isCmdPageShow; // 控制页是否显示 + bool isStatePageShow; // 状态页是否显示 + bool detectionAreaSetting; // 检测区域设置 public slots: - void GDDCControlTimeOut(); - void startConnect(int); // 开始连接 - void stopConnect(int); // 停止连接 - void UDPMessageReceive(); // udp数据接收 - void pushButtonSet_clicked(); - void pushButShowCmdPage_clicked(); - void pushButShowStatePage_clicked(); + void GDDCControlTimeOut(); + void startConnect(int); // 开始连接 + void stopConnect(int); // 停止连接 + void UDPMessageReceive(); // udp数据接收 + void pushButtonSet_clicked(); + void pushButShowCmdPage_clicked(); + void pushButShowStatePage_clicked(); + + void showErrorMessage(QString message, int type); }; -#endif // GDDCDLG_H +#endif // GDDCDLG_H diff --git a/Src/GDDC/gddcdlg.ui b/Src/GDDC/gddcdlg.ui index 6eaa58b..e2b077b 100644 --- a/Src/GDDC/gddcdlg.ui +++ b/Src/GDDC/gddcdlg.ui @@ -41,12 +41,12 @@ Form - Qt::LayoutDirection::LeftToRight + Qt::LeftToRight - + true @@ -83,16 +83,16 @@ - Qt::FocusPolicy::NoFocus + Qt::NoFocus - Qt::ContextMenuPolicy::NoContextMenu + Qt::NoContextMenu false - Qt::LayoutDirection::LeftToRight + Qt::LeftToRight false @@ -153,9 +153,9 @@ - ffmpegvideoDlg + VideoWidget QWidget -
ffmpegvideodlg.h
+
videowidget.h
1
diff --git a/Src/ModelCamera/modelcameradlg.cpp b/Src/ModelCamera/modelcameradlg.cpp index dc2d05f..68b27c3 100644 --- a/Src/ModelCamera/modelcameradlg.cpp +++ b/Src/ModelCamera/modelcameradlg.cpp @@ -1,394 +1,397 @@ #include "modelcameradlg.h" + #include "ui_modelcameradlg.h" ModelCameraDlg::ModelCameraDlg(QWidget *parent) : QDialog(parent), ui(new Ui::ModelCameraDlg) { - ui->setupUi(this); - ui->videoIPLineEdit->setText( - QStringLiteral("rtsp://192.168.5.74:8554/live")); // - ui->pushStreamIPEdit->setText( - QStringLiteral("rtmp://182.92.130.23/app/stream99")); - ui->cameraVideoWidget->setVedioSaveFileDirPath("./3DCameraVideo"); - InitialComboBox(); - cameraCMDThread = new QThread(); - encodeModelCamera = new EncodeModelCamera(); - encodeModelCamera->moveToThread(cameraCMDThread); - cameraCMDThread->start(); - connect(this, &ModelCameraDlg::sendCmdData_signal, encodeModelCamera, - &EncodeModelCamera::SendCMD); - connect(encodeModelCamera, &EncodeModelCamera::UDP_Receive, this, - &ModelCameraDlg::on_receiveUDP); - connect(this, &ModelCameraDlg::sendNetParam_signal, encodeModelCamera, - &EncodeModelCamera::setIPandPort); + ui->setupUi(this); + ui->videoIPLineEdit->setText(QStringLiteral( + "rtsp://192.168.55.65:554/live/track0")); // rtsp://192.168.5.74:8554/LIVE + ui->pushStreamIPEdit->setText( + QStringLiteral("rtmp://182.92.130.23/app/stream99")); + ui->cameraVideoWidget->setVedioSaveFileDirPath("./3DCameraVideo"); + InitialComboBox(); + cameraCMDThread = new QThread(); + encodeModelCamera = new EncodeModelCamera(); + encodeModelCamera->moveToThread(cameraCMDThread); + cameraCMDThread->start(); + connect(this, &ModelCameraDlg::sendCmdData_signal, encodeModelCamera, + &EncodeModelCamera::SendCMD); + connect(encodeModelCamera, &EncodeModelCamera::UDP_Receive, this, + &ModelCameraDlg::on_receiveUDP); + connect(this, &ModelCameraDlg::sendNetParam_signal, encodeModelCamera, + &EncodeModelCamera::setIPandPort); } ModelCameraDlg::~ModelCameraDlg() { - delete ui; - if (cameraCMDThread != nullptr) { - cameraCMDThread->quit(); - cameraCMDThread->wait(); - encodeModelCamera->deleteLater(); - cameraCMDThread->deleteLater(); - } + delete ui; + if (cameraCMDThread != nullptr) { + cameraCMDThread->quit(); + cameraCMDThread->wait(); + encodeModelCamera->deleteLater(); + cameraCMDThread->deleteLater(); + } } void ModelCameraDlg::InitialComboBox() { - ui->photoTimeDbSpinBox->setSuffix("s"); - - // 快门速度 - ui->SSComboBox->insertItem(0, "1/100"); - ui->SSComboBox->insertItem(1, "1/125"); - ui->SSComboBox->insertItem(2, "1/160"); - ui->SSComboBox->insertItem(3, "1/200"); - ui->SSComboBox->insertItem(4, "1/250"); - ui->SSComboBox->insertItem(5, "1/320"); - ui->SSComboBox->insertItem(6, "1/400"); - ui->SSComboBox->insertItem(7, "1/500"); - ui->SSComboBox->insertItem(8, "1/640"); - ui->SSComboBox->insertItem(9, "1/800"); - ui->SSComboBox->insertItem(10, "1/1000"); - ui->SSComboBox->insertItem(11, "1/1250"); - ui->SSComboBox->insertItem(12, "1/1600"); - ui->SSComboBox->insertItem(13, "1/2000"); - - // ISO - ui->ISOComboBox->insertItem(0, "50~800"); - ui->ISOComboBox->insertItem(1, "50~1600"); - ui->ISOComboBox->insertItem(2, "50"); - ui->ISOComboBox->insertItem(3, "100"); - ui->ISOComboBox->insertItem(4, "125"); - ui->ISOComboBox->insertItem(5, "160"); - ui->ISOComboBox->insertItem(6, "200"); - ui->ISOComboBox->insertItem(7, "250"); - ui->ISOComboBox->insertItem(8, "320"); - ui->ISOComboBox->insertItem(9, "400"); - ui->ISOComboBox->insertItem(10, "500"); - ui->ISOComboBox->insertItem(11, "640"); - ui->ISOComboBox->insertItem(12, "800"); - ui->ISOComboBox->insertItem(13, "1000"); - ui->ISOComboBox->insertItem(14, "1250"); - ui->ISOComboBox->insertItem(15, "1600"); - - // AWB - ui->AWBComboBox->insertItem(0, "自动"); - ui->AWBComboBox->insertItem(1, "日光"); - - // 相机模式 - ui->cameraModelComboBox->insertItem(0, "拍照模式"); - ui->cameraModelComboBox->insertItem(1, "录像模式"); - - // 色彩模式 - ui->ColorModelComboBox->insertItem(0, "艳丽"); - ui->ColorModelComboBox->insertItem(1, "标准"); + ui->photoTimeDbSpinBox->setSuffix("s"); + + // 快门速度 + ui->SSComboBox->insertItem(0, "1/100"); + ui->SSComboBox->insertItem(1, "1/125"); + ui->SSComboBox->insertItem(2, "1/160"); + ui->SSComboBox->insertItem(3, "1/200"); + ui->SSComboBox->insertItem(4, "1/250"); + ui->SSComboBox->insertItem(5, "1/320"); + ui->SSComboBox->insertItem(6, "1/400"); + ui->SSComboBox->insertItem(7, "1/500"); + ui->SSComboBox->insertItem(8, "1/640"); + ui->SSComboBox->insertItem(9, "1/800"); + ui->SSComboBox->insertItem(10, "1/1000"); + ui->SSComboBox->insertItem(11, "1/1250"); + ui->SSComboBox->insertItem(12, "1/1600"); + ui->SSComboBox->insertItem(13, "1/2000"); + + // ISO + ui->ISOComboBox->insertItem(0, "50~800"); + ui->ISOComboBox->insertItem(1, "50~1600"); + ui->ISOComboBox->insertItem(2, "50"); + ui->ISOComboBox->insertItem(3, "100"); + ui->ISOComboBox->insertItem(4, "125"); + ui->ISOComboBox->insertItem(5, "160"); + ui->ISOComboBox->insertItem(6, "200"); + ui->ISOComboBox->insertItem(7, "250"); + ui->ISOComboBox->insertItem(8, "320"); + ui->ISOComboBox->insertItem(9, "400"); + ui->ISOComboBox->insertItem(10, "500"); + ui->ISOComboBox->insertItem(11, "640"); + ui->ISOComboBox->insertItem(12, "800"); + ui->ISOComboBox->insertItem(13, "1000"); + ui->ISOComboBox->insertItem(14, "1250"); + ui->ISOComboBox->insertItem(15, "1600"); + + // AWB + ui->AWBComboBox->insertItem(0, "自动"); + ui->AWBComboBox->insertItem(1, "日光"); + + // 相机模式 + ui->cameraModelComboBox->insertItem(0, "拍照模式"); + ui->cameraModelComboBox->insertItem(1, "录像模式"); + + // 色彩模式 + ui->ColorModelComboBox->insertItem(0, "艳丽"); + ui->ColorModelComboBox->insertItem(1, "标准"); } // 解析通过校验的udp数据、界面刷新显示 void ModelCameraDlg::on_receiveUDP(QByteArray arrdata) { - int picNum = (arrdata[3] << 8) | arrdata[4]; // 照片数量(某一个视角) - QString str = QString::number(picNum); - ui->lineEdit_2->setText(QString::number(picNum * 5)); - ui->lineEdit_3->setText(str); - ui->lineEdit_4->setText(str); - ui->lineEdit_5->setText(str); - ui->lineEdit_6->setText(str); - ui->lineEdit_7->setText(str); - - int shutterSpd = (arrdata[7] << 8) | arrdata[8]; // 快门速度(倒数) - ui->lineEdit_10->setText(QString("1/%1").arg(shutterSpd)); - - int iso = - (arrdata[9] << 8) | arrdata[10]; // iso固定值 -1表示50~1600,-2表示50~800 - if (iso == -1) { - ui->lineEdit_14->setText("50~1600"); - } else if (iso == -2) { - ui->lineEdit_14->setText("50~800"); - } else { - QString qstr = QString("%1").arg(iso); - ui->lineEdit_14->setText(qstr); - } - - int awb = - (arrdata[11] << 8) | arrdata[12]; // 白平衡值 0x0001:自动,0x0002:日光 - if (awb == 1) { - ui->lineEdit_9->setText("自动"); - } else if (awb == 2) { - ui->lineEdit_9->setText("日光"); - } - - int colorMode = - (arrdata[13] << 8) | arrdata[14]; // 色彩模式 0x0001:艳丽,0x0002:标准 - if (colorMode == 1) { - ui->lineEdit_12->setText("艳丽"); - } else if (colorMode == 2) { - ui->lineEdit_12->setText("标准"); - } + int picNum = (arrdata[3] << 8) | arrdata[4]; // 照片数量(某一个视角) + QString str = QString::number(picNum); + ui->lineEdit_2->setText(QString::number(picNum * 5)); + ui->lineEdit_3->setText(str); + ui->lineEdit_4->setText(str); + ui->lineEdit_5->setText(str); + ui->lineEdit_6->setText(str); + ui->lineEdit_7->setText(str); + + int shutterSpd = (arrdata[7] << 8) | arrdata[8]; // 快门速度(倒数) + ui->lineEdit_10->setText(QString("1/%1").arg(shutterSpd)); + + int iso = (arrdata[9] << 8) | + arrdata[10]; // iso固定值 -1表示50~1600,-2表示50~800 + if (iso == -1) { + ui->lineEdit_14->setText("50~1600"); + } else if (iso == -2) { + ui->lineEdit_14->setText("50~800"); + } else { + QString qstr = QString("%1").arg(iso); + ui->lineEdit_14->setText(qstr); + } + + int awb = (arrdata[11] << 8) | + arrdata[12]; // 白平衡值 0x0001:自动,0x0002:日光 + if (awb == 1) { + ui->lineEdit_9->setText("自动"); + } else if (awb == 2) { + ui->lineEdit_9->setText("日光"); + } + + int colorMode = (arrdata[13] << 8) | + arrdata[14]; // 色彩模式 0x0001:艳丽,0x0002:标准 + if (colorMode == 1) { + ui->lineEdit_12->setText("艳丽"); + } else if (colorMode == 2) { + ui->lineEdit_12->setText("标准"); + } } // 开始拍照点击事件 void ModelCameraDlg::on_startPhotoBtn_clicked() { - quint8 photoTime = ui->photoTimeDbSpinBox->value() * 10; - - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x02); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x03); - cmdDataArray.insert(3, 0x01); - cmdDataArray.insert(4, photoTime); - emit sendCmdData_signal(cmdDataArray); + quint8 photoTime = ui->photoTimeDbSpinBox->value() * 10; + + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x02); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x03); + cmdDataArray.insert(3, 0x01); + cmdDataArray.insert(4, photoTime); + emit sendCmdData_signal(cmdDataArray); } // 停止拍照 void ModelCameraDlg::on_stopPhotoBtn_clicked() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x03); - cmdDataArray.insert(3, QByteArray(1, char(0x00))); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x03); + cmdDataArray.insert(3, QByteArray(1, char(0x00))); + emit sendCmdData_signal(cmdDataArray); } // 开机 void ModelCameraDlg::on_ONBtn_clicked() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x01); - cmdDataArray.insert(3, 0x01); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x01); + cmdDataArray.insert(3, 0x01); + emit sendCmdData_signal(cmdDataArray); } // 关机 void ModelCameraDlg::on_OFFBtn_clicked() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x01); - cmdDataArray.insert(3, QByteArray(1, char(0x00))); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x01); + cmdDataArray.insert(3, QByteArray(1, char(0x00))); + emit sendCmdData_signal(cmdDataArray); } // 播放视频 void ModelCameraDlg::on_pushButton_5_clicked() { - QString str = ui->pushButton_5->text(); - ffmpegvideoDlg *videoDlg = ui->cameraVideoWidget; - if (str == "播放视频") { - QString streamIP = ui->videoIPLineEdit->text(); - if (streamIP.isEmpty()) { - QMessageBox::warning(NULL, "提示", "拉流地址为空!", QMessageBox::Ok); - return; - } - if (!(streamIP.left(4) == "rtmp" || streamIP.left(4) == "rtsp")) { - QMessageBox::warning(NULL, "提示", "拉流地址有误!", QMessageBox::Ok); - return; + QString str = ui->pushButton_5->text(); + VideoWidget *videoDlg = ui->cameraVideoWidget; + if (str == "播放视频") { + QString streamIP = ui->videoIPLineEdit->text(); + if (streamIP.isEmpty()) { + QMessageBox::warning(NULL, "提示", "拉流地址为空!", + QMessageBox::Ok); + return; + } + if (!(streamIP.left(4) == "rtmp" || streamIP.left(4) == "rtsp")) { + QMessageBox::warning(NULL, "提示", "拉流地址有误!", + QMessageBox::Ok); + return; + } + videoDlg->play(streamIP); + ui->pushButton_5->setText("暂停播放"); + } else { + videoDlg->stopPlay(); + ui->pushButton_5->setText("播放视频"); } - videoDlg->setStreamIP(streamIP); - videoDlg->setPlayVideo(true); - ui->pushButton_5->setText("暂停播放"); - } else { - videoDlg->setPlayVideo(false); - ui->pushButton_5->setText("播放视频"); - } } // 推流 void ModelCameraDlg::on_pushStreamBtn_clicked() { - QString str = ui->pushStreamBtn->text(); - ffmpegvideoDlg *videoDlg = ui->cameraVideoWidget; - if (str == "开始推流") { - QString streamIP = ui->videoIPLineEdit->text(); - QString pushIP = ui->pushStreamIPEdit->text(); - if (streamIP.isEmpty() || pushIP.isEmpty()) { - QMessageBox::warning(NULL, "提示", "拉流或推流地址为空!", - QMessageBox::Ok); - return; - } - if (!(streamIP.left(4) == "rtmp" || streamIP.left(4) == "rtsp")) { - QMessageBox::warning(NULL, "提示", "拉流地址有误!", QMessageBox::Ok); - return; + QString str = ui->pushStreamBtn->text(); + VideoWidget *videoDlg = ui->cameraVideoWidget; + if (str == "开始推流") { + QString streamIP = ui->videoIPLineEdit->text(); + QString pushIP = ui->pushStreamIPEdit->text(); + if (streamIP.isEmpty() || pushIP.isEmpty()) { + QMessageBox::warning(NULL, "提示", "拉流或推流地址为空!", + QMessageBox::Ok); + return; + } + if (!(streamIP.left(4) == "rtmp" || streamIP.left(4) == "rtsp")) { + QMessageBox::warning(NULL, "提示", "拉流地址有误!", + QMessageBox::Ok); + return; + } + if (!(pushIP.left(4) == "rtmp" || pushIP.left(4) == "rtsp")) { + QMessageBox::warning(NULL, "提示", "推流地址有误!", + QMessageBox::Ok); + return; + } + videoDlg->setPullURL(streamIP); + videoDlg->pushStream(pushIP); + ui->pushStreamBtn->setText("停止推流"); + } else { + videoDlg->stopPlay(); + ui->pushStreamBtn->setText("开始推流"); } - if (!(pushIP.left(4) == "rtmp" || pushIP.left(4) == "rtsp")) { - QMessageBox::warning(NULL, "提示", "推流地址有误!", QMessageBox::Ok); - return; - } - videoDlg->setStreamIP(streamIP); - videoDlg->setPushStreamIP(pushIP); - videoDlg->setPushStream(true); - ui->pushStreamBtn->setText("停止推流"); - } else { - videoDlg->setPushStream(false); - ui->pushStreamBtn->setText("开始推流"); - } } // 快门速度 void ModelCameraDlg::on_SSComboBox_activated(int index) { - QString tmp = ui->SSComboBox->itemText(index); - QString strSS = tmp.right(tmp.length() - 2); - qint16 hexValue = strSS.toShort(); // - - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x04); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x01); - cmdDataArray.insert(3, 0x01); - - QByteArray byteArray; - byteArray.resize(2); - qToBigEndian(hexValue, (char *)byteArray.data()); - - cmdDataArray.append(byteArray); - cmdDataArray.insert(6, 0xFF); - emit sendCmdData_signal(cmdDataArray); + QString tmp = ui->SSComboBox->itemText(index); + QString strSS = tmp.right(tmp.length() - 2); + qint16 hexValue = strSS.toShort(); // + + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x04); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x01); + cmdDataArray.insert(3, 0x01); + + QByteArray byteArray; + byteArray.resize(2); + qToBigEndian(hexValue, (char *)byteArray.data()); + + cmdDataArray.append(byteArray); + cmdDataArray.insert(6, 0xFF); + emit sendCmdData_signal(cmdDataArray); } // ISO void ModelCameraDlg::on_ISOComboBox_activated(int index) { - QString strSS = ui->ISOComboBox->itemText(index); - if (index == 0) - strSS = "-2"; - else if (index == 1) - strSS = "-1"; - qint16 hexValue = strSS.toShort(); // - - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x04); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x02); - cmdDataArray.insert(3, 0x01); - - QByteArray byteArray; - byteArray.resize(2); - qToBigEndian(hexValue, (char *)byteArray.data()); - - cmdDataArray.append(byteArray); - cmdDataArray.insert(6, 0xFF); - - emit sendCmdData_signal(cmdDataArray); + QString strSS = ui->ISOComboBox->itemText(index); + if (index == 0) + strSS = "-2"; + else if (index == 1) + strSS = "-1"; + qint16 hexValue = strSS.toShort(); // + + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x04); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x02); + cmdDataArray.insert(3, 0x01); + + QByteArray byteArray; + byteArray.resize(2); + qToBigEndian(hexValue, (char *)byteArray.data()); + + cmdDataArray.append(byteArray); + cmdDataArray.insert(6, 0xFF); + + emit sendCmdData_signal(cmdDataArray); } // AWB白平衡 void ModelCameraDlg::on_AWBComboBox_activated(int index) { - quint16 hexValue = index + 1; // + quint16 hexValue = index + 1; // - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x04); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x06); - cmdDataArray.insert(3, 0x01); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x04); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x06); + cmdDataArray.insert(3, 0x01); - QByteArray byteArray; - byteArray.resize(2); - qToBigEndian(hexValue, (uchar *)byteArray.data()); + QByteArray byteArray; + byteArray.resize(2); + qToBigEndian(hexValue, (uchar *)byteArray.data()); - cmdDataArray.append(byteArray); - cmdDataArray.insert(6, 0xFF); + cmdDataArray.append(byteArray); + cmdDataArray.insert(6, 0xFF); - emit sendCmdData_signal(cmdDataArray); + emit sendCmdData_signal(cmdDataArray); } // 相机模式 void ModelCameraDlg::on_cameraModelComboBox_activated(int index) { - // quint16 hexValue = index + 1;// - - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x02); - if (index == 0) - cmdDataArray.insert(3, QByteArray(1, char(0x00))); - else if (index == 1) - cmdDataArray.insert(3, 0x01); - - emit sendCmdData_signal(cmdDataArray); + // quint16 hexValue = index + 1;// + + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x02); + if (index == 0) + cmdDataArray.insert(3, QByteArray(1, char(0x00))); + else if (index == 1) + cmdDataArray.insert(3, 0x01); + + emit sendCmdData_signal(cmdDataArray); } // 色彩模式 void ModelCameraDlg::on_ColorModelComboBox_activated(int index) { - quint16 hexValue = index + 1; // + quint16 hexValue = index + 1; // - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x04); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x08); - cmdDataArray.insert(3, 0x01); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x04); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x08); + cmdDataArray.insert(3, 0x01); - QByteArray byteArray; - byteArray.resize(2); - qToBigEndian(hexValue, (uchar *)byteArray.data()); + QByteArray byteArray; + byteArray.resize(2); + qToBigEndian(hexValue, (uchar *)byteArray.data()); - cmdDataArray.append(byteArray); - cmdDataArray.insert(6, 0xFF); + cmdDataArray.append(byteArray); + cmdDataArray.insert(6, 0xFF); - emit sendCmdData_signal(cmdDataArray); + emit sendCmdData_signal(cmdDataArray); } // 获取开关机状态 void ModelCameraDlg::quireOnorOff() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x01); - cmdDataArray.insert(3, 0xFF); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x01); + cmdDataArray.insert(3, 0xFF); + emit sendCmdData_signal(cmdDataArray); } // 查询图传状态 void ModelCameraDlg::quirePictranStatus() {} // 查询快门速度 void ModelCameraDlg::quireShutterSpeed() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x02); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x01); - cmdDataArray.insert(3, 0xFF); - cmdDataArray.insert(4, 0xFF); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x02); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x01); + cmdDataArray.insert(3, 0xFF); + cmdDataArray.insert(4, 0xFF); + emit sendCmdData_signal(cmdDataArray); } // 查询ISO void ModelCameraDlg::quireISO() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x02); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x02); - cmdDataArray.insert(3, 0xFF); - cmdDataArray.insert(4, 0xFF); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x02); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x02); + cmdDataArray.insert(3, 0xFF); + cmdDataArray.insert(4, 0xFF); + emit sendCmdData_signal(cmdDataArray); } // 查询白平衡 void ModelCameraDlg::quireAWB() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x02); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x06); - cmdDataArray.insert(3, 0xFF); - cmdDataArray.insert(4, 0xFF); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x02); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x06); + cmdDataArray.insert(3, 0xFF); + cmdDataArray.insert(4, 0xFF); + emit sendCmdData_signal(cmdDataArray); } // 查询相机模式 void ModelCameraDlg::quireCameraMode() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x02); - cmdDataArray.insert(3, 0xFF); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x02); + cmdDataArray.insert(3, 0xFF); + emit sendCmdData_signal(cmdDataArray); } // 查询色彩(饱和度)模式 void ModelCameraDlg::quireColorMode() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA2); - cmdDataArray.insert(2, 0x08); - cmdDataArray.insert(3, 0xFF); - cmdDataArray.insert(4, 0xFF); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA2); + cmdDataArray.insert(2, 0x08); + cmdDataArray.insert(3, 0xFF); + cmdDataArray.insert(4, 0xFF); + emit sendCmdData_signal(cmdDataArray); } // 查询温度 void ModelCameraDlg::quireTempe() {} // 查询照片总数,以及各个视角的照片数量 void ModelCameraDlg::quirePicNumAll() { - cmdDataArray.clear(); - cmdDataArray.insert(0, 0x01); - cmdDataArray.insert(1, 0xA1); - cmdDataArray.insert(2, 0x07); - cmdDataArray.insert(3, 0xFF); - emit sendCmdData_signal(cmdDataArray); + cmdDataArray.clear(); + cmdDataArray.insert(0, 0x01); + cmdDataArray.insert(1, 0xA1); + cmdDataArray.insert(2, 0x07); + cmdDataArray.insert(3, 0xFF); + emit sendCmdData_signal(cmdDataArray); } diff --git a/Src/ModelCamera/modelcameradlg.h b/Src/ModelCamera/modelcameradlg.h index 61e8512..dcdb6bd 100644 --- a/Src/ModelCamera/modelcameradlg.h +++ b/Src/ModelCamera/modelcameradlg.h @@ -1,72 +1,75 @@ #ifndef MODELCAMERADLG_H #define MODELCAMERADLG_H -#include "Src/GDDC/structDefineMyslef.h" -#include "encodemodelcamera.h" +#include + #include #include #include #include -#include + +#include "Src/GDDC/structDefineMyslef.h" +#include "encodemodelcamera.h" +#include "videowidget.h" namespace Ui { class ModelCameraDlg; } class ModelCameraDlg : public QDialog { - Q_OBJECT + Q_OBJECT public: - explicit ModelCameraDlg(QWidget *parent = nullptr); - ~ModelCameraDlg(); - // void setNetParam(netStruct); + explicit ModelCameraDlg(QWidget *parent = nullptr); + ~ModelCameraDlg(); + // void setNetParam(netStruct); signals: - void sendCmdData_signal(QByteArray cmdDataArray); - void sendNetParam_signal(netStruct netParam); + void sendCmdData_signal(QByteArray cmdDataArray); + void sendNetParam_signal(netStruct netParam); private slots: - void on_startPhotoBtn_clicked(); + void on_startPhotoBtn_clicked(); - void on_stopPhotoBtn_clicked(); + void on_stopPhotoBtn_clicked(); - void on_ONBtn_clicked(); + void on_ONBtn_clicked(); - void on_OFFBtn_clicked(); + void on_OFFBtn_clicked(); - void on_pushButton_5_clicked(); + void on_pushButton_5_clicked(); - void on_SSComboBox_activated(int index); + void on_SSComboBox_activated(int index); - void on_ISOComboBox_activated(int index); + void on_ISOComboBox_activated(int index); - void on_AWBComboBox_activated(int index); + void on_AWBComboBox_activated(int index); - void on_cameraModelComboBox_activated(int index); + void on_cameraModelComboBox_activated(int index); - void on_ColorModelComboBox_activated(int index); + void on_ColorModelComboBox_activated(int index); - void on_receiveUDP(QByteArray cmdDataArray); + void on_receiveUDP(QByteArray cmdDataArray); - void on_pushStreamBtn_clicked(); + void on_pushStreamBtn_clicked(); private: - void InitialComboBox(); - // 状态查询指令 - // 查询开关机 - void quireOnorOff(); - void quirePictranStatus(); - void quireShutterSpeed(); - void quireISO(); - void quireAWB(); - void quireCameraMode(); - void quireColorMode(); - void quireTempe(); - void quirePicNumAll(); + void InitialComboBox(); + // 状态查询指令 + // 查询开关机 + void quireOnorOff(); + void quirePictranStatus(); + void quireShutterSpeed(); + void quireISO(); + void quireAWB(); + void quireCameraMode(); + void quireColorMode(); + void quireTempe(); + void quirePicNumAll(); private: - Ui::ModelCameraDlg *ui; - QThread *cameraCMDThread; - QByteArray cmdDataArray; - EncodeModelCamera *encodeModelCamera; + Ui::ModelCameraDlg *ui; + QThread *cameraCMDThread; + QByteArray cmdDataArray; + EncodeModelCamera *encodeModelCamera; }; -#endif // MODELCAMERADLG_H +#endif // MODELCAMERADLG_H diff --git a/Src/ModelCamera/modelcameradlg.ui b/Src/ModelCamera/modelcameradlg.ui index 88dde32..227098f 100644 --- a/Src/ModelCamera/modelcameradlg.ui +++ b/Src/ModelCamera/modelcameradlg.ui @@ -7,7 +7,7 @@ 0 0 1071 - 720 + 722 @@ -1308,32 +1308,19 @@ - 7 + 2 - 7 + 2 - 7 + 2 - 7 + 2 - - - - 0 - 0 - - - - - 600 - 400 - - - +
@@ -1342,10 +1329,9 @@ - ffmpegvideoDlg - QWidget -
ffmpegvideodlg.h
- 1 + VideoWidget + QOpenGLWidget +
videowidget.h
diff --git a/Src/Video/cffmpeg_decode.cpp b/Src/Video/cffmpeg_decode.cpp index 340a31a..d635d5a 100644 --- a/Src/Video/cffmpeg_decode.cpp +++ b/Src/Video/cffmpeg_decode.cpp @@ -126,7 +126,7 @@ bool Cffmpeg_decode::open_input_file() { videoStreamIndex = i; break; } - } + } if (videoStreamIndex == -1) { printf("Cannot find video stream in file.\n"); return 0; diff --git a/Src/VideoGL/VideoGL.pri b/Src/VideoGL/VideoGL.pri new file mode 100644 index 0000000..f7ea39f --- /dev/null +++ b/Src/VideoGL/VideoGL.pri @@ -0,0 +1,25 @@ +QT += opengl openglwidgets + +SOURCES += \ + $$PWD/avpacketqueuemanager.cpp \ + $$PWD/readstream.cpp \ + $$PWD/savestream.cpp \ + $$PWD/decodestream.cpp \ + $$PWD/pushstream.cpp \ + $$PWD/videowidget.cpp \ + +HEADERS += \ + $$PWD/avpacketqueuemanager.h \ + $$PWD/readstream.h \ + $$PWD/savestream.h \ + $$PWD/decodestream.h \ + $$PWD/pushstream.h \ + $$PWD/videowidget.h \ + $$PWD/ffmpeginclude.h \ + +DISTFILES += \ + $$PWD/fragment.fsh \ + $$PWD/vertex.vsh + +RESOURCES += \ + $$PWD/glrc.qrc diff --git a/Src/VideoGL/avpacketqueuemanager.cpp b/Src/VideoGL/avpacketqueuemanager.cpp new file mode 100644 index 0000000..824edb8 --- /dev/null +++ b/Src/VideoGL/avpacketqueuemanager.cpp @@ -0,0 +1,72 @@ +#include "avpacketqueuemanager.h" + +AVPacketQueueManager::AVPacketQueueManager() { + m_decodeQueue.reserve(QUEUECAPACITY); + m_saveQueue.reserve(QUEUECAPACITY); + m_pushQueue.reserve(QUEUECAPACITY); +} + +void AVPacketQueueManager::enqueueDecodePacket(AVPacket *pkt) { + QMutexLocker locker(&m_decodeMutex); + AVPacket *clonedPacket = av_packet_clone(pkt); + if (clonedPacket) m_decodeQueue.enqueue(clonedPacket); +} + +void AVPacketQueueManager::enqueueSavePacket(AVPacket *pkt) { + QMutexLocker locker(&m_saveMutex); + AVPacket *clonedPacket = av_packet_clone(pkt); + if (clonedPacket) m_saveQueue.enqueue(clonedPacket); +} + +void AVPacketQueueManager::enqueuePushPacket(AVPacket *pkt) { + QMutexLocker locker(&m_pushMutex); + AVPacket *clonedPacket = av_packet_clone(pkt); + if (clonedPacket) m_pushQueue.enqueue(clonedPacket); +} + +AVPacket *AVPacketQueueManager::dequeueDecodePacket() { + QMutexLocker locker(&m_decodeMutex); + if (!m_decodeQueue.isEmpty()) { + AVPacket *pkt = m_decodeQueue.dequeue(); + return pkt; + } + return nullptr; +} + +AVPacket *AVPacketQueueManager::dequeueSavePacket() { + QMutexLocker locker(&m_saveMutex); + if (!m_saveQueue.isEmpty()) { + AVPacket *pkt = m_saveQueue.dequeue(); + return pkt; + } + return nullptr; +} + +AVPacket *AVPacketQueueManager::dequeuePushPacket() { + QMutexLocker locker(&m_pushMutex); + if (!m_pushQueue.isEmpty()) { + AVPacket *pkt = m_pushQueue.dequeue(); + return pkt; + } + return nullptr; +} + +void AVPacketQueueManager::clearDecodeQueue() { + QMutexLocker locker(&m_decodeMutex); + m_decodeQueue.clear(); +} + +void AVPacketQueueManager::clearSaveQueue() { + QMutexLocker locker(&m_saveMutex); + m_saveQueue.clear(); +} + +void AVPacketQueueManager::clearPushQueue() { + QMutexLocker locker(&m_pushMutex); + m_pushQueue.clear(); +} + +bool AVPacketQueueManager::isEmptySaveQueue() { + QMutexLocker locker(&m_saveMutex); + return m_saveQueue.isEmpty(); +} diff --git a/Src/VideoGL/avpacketqueuemanager.h b/Src/VideoGL/avpacketqueuemanager.h new file mode 100644 index 0000000..895f36b --- /dev/null +++ b/Src/VideoGL/avpacketqueuemanager.h @@ -0,0 +1,38 @@ +#ifndef AVPACKETQUEUEMANAGER_H +#define AVPACKETQUEUEMANAGER_H + +#include +#include + +#include "ffmpeginclude.h" + +class AVPacketQueueManager { +public: + AVPacketQueueManager(); + + void enqueueDecodePacket(AVPacket* pkt); + void enqueueSavePacket(AVPacket* pkt); + void enqueuePushPacket(AVPacket* pkt); + + AVPacket* dequeueDecodePacket(); + AVPacket* dequeueSavePacket(); + AVPacket* dequeuePushPacket(); + + void clearDecodeQueue(); + void clearSaveQueue(); + void clearPushQueue(); + + // bool isEmptyDecodeQueue(); + bool isEmptySaveQueue(); + +private: + int QUEUECAPACITY = 100; + QQueue m_decodeQueue; + QQueue m_saveQueue; + QQueue m_pushQueue; + QMutex m_decodeMutex; // 共享的互斥锁 + QMutex m_saveMutex; // 共享的互斥锁 + QMutex m_pushMutex; // 共享的互斥锁 +}; + +#endif // AVPACKETQUEUEMANAGER_H diff --git a/Src/VideoGL/decodestream.cpp b/Src/VideoGL/decodestream.cpp new file mode 100644 index 0000000..0267f2f --- /dev/null +++ b/Src/VideoGL/decodestream.cpp @@ -0,0 +1,367 @@ +#include "decodestream.h" + +DecodeStream::DecodeStream(QObject *parent) : QObject{parent} { + /************* 获取当前环境支持的硬件解码器 **************/ + AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; + QStringList strTypes; + while ((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) { + m_HWDeviceTypes.append(type); + const char *ctype = av_hwdevice_get_type_name(type); + if (ctype) { + strTypes.append(QString(ctype)); + } + } + qDebug() << "支持的硬件解码器:" << strTypes; +} + +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; + + return initDecoder(formatContext, videoIndex); +} + +// 视频解码线程任务 +void DecodeStream::startDecode() { + qDebug() << "deocdeStreamThreadID:" << QThread::currentThreadId(); + m_start = initObject(); + if (!m_start) { + free(); + return; + } + while (m_start) { + try { + AVPacket *inputPacket = m_queueManager->dequeueDecodePacket(); + if (inputPacket) { + AVFrame *frame = decodePacket(inputPacket); + emit repaintSignal(frame); + av_packet_unref(inputPacket); + av_packet_free(&inputPacket); + inputPacket = nullptr; + } else { + // QThread::usleep(1000); + // av_usleep(1000); + } + } catch (...) { + } + av_usleep(1000); + } + + free(); + qDebug() << "Decoding Thread End!"; + emit sendErrorMessageSignal("视频解码结束!", + NotificationType::NOTIFICATION_SUCCESS); +} + +void DecodeStream::close() { + // QMutexLocker locker(&m_mutex); + m_start = false; + qDebug() << "decode Stream close!" << m_start; +} + +/** + * @brief 设置是否使用硬件解码 + * @param flag true:使用 false:不使用 + */ +void DecodeStream::setHWDecoder(bool flag) { + m_HWDecoder = flag; +} + +bool DecodeStream::initObject() { + // 分配AVFrame并将其字段设置为默认值。 + m_frame = av_frame_alloc(); + if (!m_frame) { + qWarning() << "av_frame_alloc() Error!"; + free(); + return false; + } + + m_frameHW = av_frame_alloc(); + if (!m_frameHW) { +#if PRINT_LOG + qWarning() << "av_frame_alloc() Error!"; +#endif + free(); + return false; + } + + return true; +} + +bool DecodeStream::initDecoder(AVFormatContext *inputFormatContext, + int videoIndex) { + if (!inputFormatContext) return false; + AVStream *videoStream = + inputFormatContext->streams[videoIndex]; // 通过查询到的索引获取视频流 + + // 获取视频图像分辨率(AVStream中的AVCodecContext在新版本中弃用,改为使用AVCodecParameters) + // m_size.setWidth(videoStream->codecpar->width); + // m_size.setHeight(videoStream->codecpar->height); + // m_frameRate = rationalToDouble(&videoStream->avg_frame_rate); // + // 视频帧率 + AVCodecParameters *videoCodecPara = videoStream->codecpar; + // 通过解码器ID获取视频解码器(新版本返回值必须使用const) + const AVCodec *codec = avcodec_find_decoder(videoCodecPara->codec_id); + if (!codec) { + printf("Cannot find valid decode codec.\n"); + return false; + } + + // 分配AVCodecContext并将其字段设置为默认值。 + m_codecContext = avcodec_alloc_context3(codec); + if (!m_codecContext) { +#if PRINT_LOG + qWarning() << "创建视频解码器上下文失败!"; +#endif + free(); + return false; + } + + // 使用视频流的codecpar为解码器上下文赋值 + int ret = avcodec_parameters_to_context(m_codecContext, videoCodecPara); + if (ret < 0) { + showError(ret); + free(); + return false; + } + + 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; + + if (m_HWDecoder) { + // 初始化硬件解码器(在avcodec_open2前调用) + initHWDecoder(codec); + } + + // 初始化解码器上下文,如果之前avcodec_alloc_context3传入了解码器,这里设置NULL就可以 + 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; + // 将读取到的原始数据包传入解码器 + int ret = avcodec_send_packet(m_codecContext, inputPacket); + if (ret >= 0) { + while ((ret = avcodec_receive_frame(m_codecContext, m_frame)) >= 0) { + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + showError(ret); + qWarning() << "decoding file end\n"; + break; + } else if (ret < 0) { + showError(ret); + qWarning() << "Error during decoding\n"; + break; + } + if (!isValidAVFrame(m_frame)) { + break; + } + + m_frameTemp = m_frame; + if (!m_frame->data[0]) { + m_frameTemp = m_frameHW; + if (!dataCopy()) { + break; + } + } + return m_frameTemp; + // QThread::msleep(1); + } + } else { + qDebug() << "avcodec_send_packet error:" << ret << "\n"; + if (ret == AVERROR(EAGAIN)) { + qDebug() << "AVERROR(EAGAIN)"; + av_usleep(10000); + } + if (ret == AVERROR_EOF) { + qDebug() << " AVERROR_EOF"; + avcodec_flush_buffers(m_codecContext); + av_usleep(10000); + } + showError(ret); + } + av_frame_unref(m_frame); + return nullptr; +} + +void DecodeStream::free() { + if (m_codecContext) { + avcodec_free_context(&m_codecContext); + } + if (hw_device_ctx) { + av_buffer_unref(&hw_device_ctx); + } + if (m_frame) { + av_frame_free(&m_frame); + } + if (m_frameHW) { + av_frame_free(&m_frameHW); + } +} + +/*********** FFmpeg获取GPU硬件解码帧格式的回调函数 ***************/ +static enum AVPixelFormat g_pixelFormat; +/** + * @brief 回调函数,获取GPU硬件解码帧的格式 + * @param s + * @param fmt + * @return + */ +AVPixelFormat get_hw_format(AVCodecContext *s, const enum AVPixelFormat *fmt) { + Q_UNUSED(s) + const enum AVPixelFormat *p; + + for (p = fmt; *p != -1; p++) { + if (*p == g_pixelFormat) { + return *p; + } + } + qDebug() << "无法获取硬件表面格式."; + return AV_PIX_FMT_NONE; +} + +/** + * @brief 初始化硬件解码器 + * @param codec + */ +bool DecodeStream::initHWDecoder(const AVCodec *codec) { + if (!codec) return false; + + for (int i = 0;; i++) { + const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i); + if (!config) { + qDebug() << "打开硬件解码器失败!"; + return false; + } + + if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) { + for (auto i : m_HWDeviceTypes) { + if (config->device_type == AVHWDeviceType(i)) { + g_pixelFormat = config->pix_fmt; + + // 打开指定类型的设备,并为其创建AVHWDeviceContext。 + int ret = av_hwdevice_ctx_create(&hw_device_ctx, + config->device_type, + nullptr, nullptr, 0); + if (ret < 0) { + showError(ret); + free(); + return false; + } + qDebug() << "打开硬件解码器:" + << av_hwdevice_get_type_name(config->device_type); + m_codecContext->hw_device_ctx = + av_buffer_ref(hw_device_ctx); + m_codecContext->get_format = get_hw_format; + return true; + } + } + } + } + return false; +} + +/** + * @brief 硬件解码完成需要将数据从GPU复制到CPU + * @return + */ +bool DecodeStream::dataCopy() { + if (m_frame->format != g_pixelFormat) { + av_frame_unref(m_frame); + return false; + } +#if 1 + int ret = av_hwframe_map(m_frameHW, m_frame, 0); + if (ret < 0) { + showError(ret); + av_frame_unref(m_frame); + return false; + } + m_frameHW->width = m_frame->width; + m_frameHW->height = m_frame->height; +#else + +#endif + return true; +} + +bool DecodeStream::isValidAVFrame(AVFrame *frame) { + // 空指针检查 + if (!frame) { + return false; + } + + // 检查像素格式是否有效 + if (frame->format == AV_PIX_FMT_NONE) { + return false; + } + + // 检查数据指针是否有效 + if (!frame->data[0]) { + return false; + } + + // 检查宽高是否有效 + if (frame->width <= 0 || frame->height <= 0) { + return false; + } + + // 检查行大小是否有效 + if (frame->linesize[0] <= 0) { + return false; + } + + // 如果需要,添加更多判断条件,例如时间戳或关键帧检查 + if (frame->pts == AV_NOPTS_VALUE) { + return false; + } + + return true; // 如果所有条件都通过,则认为 AVFrame 有效 +} + +bool DecodeStream::isValidAVPacket(AVPacket *pkt) { + if (pkt == nullptr) { + qDebug() << "Invalid AVPacket: packet pointer is null."; + return false; + } + // 检查数据指针和大小 + if (pkt->data == nullptr || pkt->size <= 0) { + 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() << "Invalid AVPacket: pts or dts is AV_NOPTS_VALUE.\n"; + return false; + } + + // 检查流索引(如果是多流) + if (pkt->stream_index < 0) { + qDebug() << "Invalid AVPacket: stream_index is invalid.\n"; + return false; + } + + // 检查是否是有效的关键帧(可选) + if (pkt->flags & AV_PKT_FLAG_KEY) { + // 是关键帧 + // qDebug() << "This is a keyframe.\n"; + } + + return true; +} diff --git a/Src/VideoGL/decodestream.h b/Src/VideoGL/decodestream.h new file mode 100644 index 0000000..ab19d65 --- /dev/null +++ b/Src/VideoGL/decodestream.h @@ -0,0 +1,59 @@ +#ifndef DECODESTREAM_H +#define DECODESTREAM_H + +#include +#include +#include +#include +#include +#include + +#include "avpacketqueuemanager.h" +#include "ffmpeginclude.h" + +class DecodeStream : public QObject { + Q_OBJECT +public: + DecodeStream(QObject *parent = nullptr); + bool init(AVPacketQueueManager *queueManager, + AVFormatContext *formatContext, int videoIndex); + void close(); + void setHWDecoder(bool flag); // 是否使用硬件解码器 +public slots: + void startDecode(); + +signals: + void repaintSignal(AVFrame *frame); // 重绘 + void startDecodeSignal(); + void sendErrorMessageSignal(QString message, int type); + +private: + bool initObject(); // 初始化对象 + bool initDecoder(AVFormatContext *inputFormatContext, + int videoIndex); // 初始化解码器 + AVFrame *decodePacket(AVPacket *inputPacket); + void free(); // 释放 + + bool initHWDecoder(const AVCodec *codec); // 初始化硬件解码器 + bool dataCopy(); // 硬件解码完成需要将数据从GPU复制到CPU + + bool isValidAVFrame(AVFrame *frame); + bool isValidAVPacket(AVPacket *pkt); + +private: + bool m_start = true; + int m_videoIndex = 0; + AVFormatContext *m_formatContext = nullptr; + AVCodecContext *m_codecContext = nullptr; // 解码器上下文 + QQueue *m_packetsQueue = nullptr; // 解码前的视频帧队列 + AVFrame *m_frame = nullptr; // 解码后的视频帧 + AVFrame *m_frameHW = nullptr; // 硬件解码后的视频帧 + AVFrame *m_frameTemp = nullptr; + QList m_HWDeviceTypes; // 保存当前环境支持的硬件解码器 + AVBufferRef *hw_device_ctx = nullptr; // 对数据缓冲区的引用 + bool m_HWDecoder = false; // 记录是否使用硬件解码 + AVPacketQueueManager *m_queueManager = nullptr; + QMutex m_mutex; +}; + +#endif // DECODESTREAM_H diff --git a/Src/VideoGL/ffmpeginclude.h b/Src/VideoGL/ffmpeginclude.h new file mode 100644 index 0000000..24031fd --- /dev/null +++ b/Src/VideoGL/ffmpeginclude.h @@ -0,0 +1,57 @@ +#ifndef FFMPEGINCLUDE_H +#define FFMPEGINCLUDE_H + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libavcodec/avcodec.h" +} + +#include +#include +#include +#include + +#include "global.h" + +#define PRINT_LOG 1 +#define ERROR_LEN 1024 // 异常信息数组长度 + +/** + * @brief 显示ffmpeg函数调用异常信息 + * @param err + */ +inline void showError(int err) { + char *m_error = new char[ERROR_LEN]; // 保存异常信息 +#if PRINT_LOG + memset(m_error, 0, ERROR_LEN); // 将数组置零 + av_strerror(err, m_error, ERROR_LEN); + qWarning() << "DecodeVideo Error:" << m_error; +#else + Q_UNUSED(err) +#endif + delete[] m_error; // 释放内存 +} + +// void highPrecisionSleep(qint64 microseconds) { +// QElapsedTimer timer; +// timer.start(); + +// QEventLoop loop; +// while (timer.nsecsElapsed() < microseconds * 1000) { +// QCoreApplication::processEvents(QEventLoop::AllEvents, +// 1); // 处理事件并短暂阻塞 +// } +// } + +#endif // FFMPEGINCLUDE_H diff --git a/Src/VideoGL/fragment.fsh b/Src/VideoGL/fragment.fsh new file mode 100644 index 0000000..105b7ab --- /dev/null +++ b/Src/VideoGL/fragment.fsh @@ -0,0 +1,42 @@ +#version 330 core +in vec2 TexCord; // 纹理坐标 +uniform int format = -1; // 像素格式 +uniform sampler2D tex_y; +uniform sampler2D tex_u; +uniform sampler2D tex_v; +uniform sampler2D tex_uv; + +void main() +{ + vec3 yuv; + vec3 rgb; + + + if(format == 0) // YUV420P转RGB + { + yuv.x = texture2D(tex_y, TexCord).r; + yuv.y = texture2D(tex_u, TexCord).r-0.5; + yuv.z = texture2D(tex_v, TexCord).r-0.5; + } + else if(format == 23) // NV12转RGB + { + yuv.x = texture2D(tex_y, TexCord.st).r; + yuv.y = texture2D(tex_uv, TexCord.st).r - 0.5; + yuv.z = texture2D(tex_uv, TexCord.st).g - 0.5; + } + else if(format == 12){ //YUVJ420P (Full Range YUV) 转RGB + yuv.x = (texture2D(tex_y, TexCord).r * 255.0 - 16.0) / 219.0; + yuv.y = (texture2D(tex_u, TexCord).r * 255.0 - 128.0) / 224.0; + yuv.z = (texture2D(tex_v, TexCord).r * 255.0 - 128.0) / 224.0; + } + else + { + } + + rgb = mat3(1.0, 1.0, 1.0, + 0.0, -0.39465, 2.03211, + 1.13983, -0.58060, 0.0) * yuv; + // gl_FragColor = vec4(rgb, 1.0); + // Clamp RGB 范围到 [0, 1],以避免溢出 + gl_FragColor = vec4(clamp(rgb, 0.0, 1.0), 1.0); +} diff --git a/Src/VideoGL/glrc.qrc b/Src/VideoGL/glrc.qrc new file mode 100644 index 0000000..786d0c2 --- /dev/null +++ b/Src/VideoGL/glrc.qrc @@ -0,0 +1,6 @@ + + + fragment.fsh + vertex.vsh + + diff --git a/Src/VideoGL/pushstream.cpp b/Src/VideoGL/pushstream.cpp new file mode 100644 index 0000000..51a1e86 --- /dev/null +++ b/Src/VideoGL/pushstream.cpp @@ -0,0 +1,273 @@ +#include "pushstream.h" + +PushStream::PushStream(QObject *parent) : QObject{parent} {} + +void PushStream::setRemoteIP(QString url) { + m_pushStreamIP = url; +} + +bool PushStream::init(AVFormatContext *inputFormatCtx, + AVPacketQueueManager *queueManager) { + // m_pusherQueue = queue; + m_queueManager = queueManager; + m_inputFormatCtx = inputFormatCtx; + m_start = openNetworkStream(inputFormatCtx); + return m_start; +} + +void PushStream::close() { + // QMutexLocker locker(&m_mutex); + m_start = false; + m_end = true; + // qDebug() << "*******m_end0:" << m_end; +} + +bool PushStream::openNetworkStream(AVFormatContext *inputFormatCtx) { + if (m_pushStreamIP.isEmpty()) return false; + + if (!inputFormatCtx) return false; + + // 初始化网络输出流 + // QString m_pushStreamIP = "rtsp://182.92.130.23/app/stream999"; + int ret = avformat_alloc_output_context2( + &m_outputFormatCtx, NULL, "flv", m_pushStreamIP.toUtf8().constData()); + if (ret < 0) { + showError(ret); + free(); + qDebug() << "Could not create output context."; + return false; + } + + // 复制流信息 + for (unsigned int i = 0; i < inputFormatCtx->nb_streams; ++i) { + // AVStream *stream = inputFormatCtx->streams[i]; + if (inputFormatCtx->streams[i]->codecpar->codec_type == + AVMEDIA_TYPE_VIDEO) { + m_istream = inputFormatCtx->streams[i]; + m_ostream = avformat_new_stream(m_outputFormatCtx, nullptr); + if (!m_ostream) { + qDebug() << "Failed allocating output stream.\n"; + free(); + return false; + } + // 复制编解码器参数 + ret = avcodec_parameters_copy(m_ostream->codecpar, + m_istream->codecpar); + if (ret < 0) { + showError(ret); + free(); + qWarning() << "avcodec_parameters_from_context Failed"; + return false; + } + // outputStream->codecpar = inputStream->codecpar; + m_ostream->codecpar->codec_tag = 0; + break; + } + } + + m_inputTimeBase = m_istream->time_base; + m_inputFrameRate = m_istream->r_frame_rate; + m_outputTimeBase = m_ostream->time_base; + + // 打开输出文件 + if (!(m_outputFormatCtx->flags & AVFMT_NOFILE)) { + if (ret = avio_open(&m_outputFormatCtx->pb, + m_pushStreamIP.toUtf8().constData(), + AVIO_FLAG_WRITE) < 0) { + showError(ret); + free(); + qDebug() << "Could not open output file.\n"; + return false; + } + } + + // 写入头文件 + ret = avformat_write_header(m_outputFormatCtx, NULL); + if (ret < 0) { + showError(ret); + free(); + qDebug() << "Error occurred when write_header into output file.\n"; + return false; + } + // sendSPS_PPS(inputFormatCtx, outputFormatCtx); + // m_InitStatus = true; + // startTime = av_gettime_relative(); + + m_bwriteHeader = true; + m_firstPts = AV_NOPTS_VALUE; + return true; +} + +int PushStream::reconnect(int ret) { + if (ret == -10053 || ret == -10054) { + m_end = false; + // qDebug() << "m_end:" << m_end; + for (int nRetryCount = 0; nRetryCount < MAXCONNECT; ++nRetryCount) { + // 关闭输出 + if (m_outputFormatCtx && + !(m_outputFormatCtx->flags & AVFMT_NOFILE)) { + avio_close(m_outputFormatCtx->pb); + } + ret = + avio_open(&m_outputFormatCtx->pb, + m_pushStreamIP.toUtf8().constData(), AVIO_FLAG_WRITE); + if (ret < 0) { + showError(ret); + qDebug() << "Failed to reconnect" + << QString::number(nRetryCount + 1); + QString str = + QString("网络中断,尝试重连第%1次!").arg(nRetryCount + 1); + emit sendErrorMessageSignal(str, 3); + if (m_end) break; + // av_usleep(5 * 1000000); + continue; + } + // Try to reconnect + ret = avformat_write_header(m_outputFormatCtx, nullptr); + if (ret < 0) { + showError(ret); + // free(); + qDebug() << "Failed to reconnect" + << QString::number(nRetryCount + 1); + QString str = + QString("网络中断,尝试重连第%1次!").arg(nRetryCount + 1); + emit sendErrorMessageSignal(str, 3); + if (m_end) break; + // nRetryCount++; + // av_usleep(5 * 1000000); + } else { + m_start = true; + m_firstPts = AV_NOPTS_VALUE; + m_frm_cnt = 0; + m_bwriteHeader = true; + emit sendErrorMessageSignal("重连成功!", 1); + m_queueManager->clearPushQueue(); + qDebug() << "重连成功!"; + return ret; + } + + if (m_end) break; + } + m_start = false; + m_bwriteHeader = false; + emit sendErrorMessageSignal("重连失败,推流停止!", 2); + return -1; + } +} + +void PushStream::pushStream(int64_t startTime) { + qDebug() << "PushStreamThreadID:" << QThread::currentThreadId(); + // m_startTime = startTime; + while (m_start) { + AVPacket *inputPacket = m_queueManager->dequeuePushPacket(); + if (inputPacket) { + if (inputPacket->data == nullptr || inputPacket->size <= 0 || + inputPacket->pts <= 0) { + // av_packet_unref(inputPacket); + continue; + } + int outputStreamIndex = 0; + // int inputStreamIndex = inputPacket->stream_index; + // AVStream *istream = m_inputFormatCtx->streams[inputStreamIndex]; + // AVStream *ostream = + // m_outputFormatCtx->streams[outputStreamIndex]; 时间基 + // AVRational istream_base = m_istream->time_base; + // AVRational ostream_base = ostream->time_base; + // 没有pts的视频数据,如未解码的H.264裸流,需要重新计算其pts。 + if (inputPacket->pts == AV_NOPTS_VALUE) { + // Duration between 2 frames (us) + int64_t calc_duration = + (double)AV_TIME_BASE / av_q2d(m_inputFrameRate); + // Reset Parameters + inputPacket->pts = + (double)(m_frm_cnt * calc_duration) / + (double)(av_q2d(m_inputTimeBase) * AV_TIME_BASE); + inputPacket->dts = inputPacket->pts; + inputPacket->duration = + (double)calc_duration / + (double)(av_q2d(m_inputTimeBase) * AV_TIME_BASE); + } + // 视频帧推送速度 + if (m_firstPts == AV_NOPTS_VALUE) { + m_startTime = av_gettime(); + m_firstPts = av_rescale_q(inputPacket->dts, m_inputTimeBase, + AVRational{1, AV_TIME_BASE}); + } + auto pts_time = av_rescale_q(inputPacket->pts, m_inputTimeBase, + AVRational{1, AV_TIME_BASE}); + int64_t pts_time_corrected = pts_time - m_firstPts; + auto now_time = av_gettime() - m_startTime; + int64_t delay = pts_time_corrected - now_time; + // qDebug() << "****************PushStream sleep time:" + // << QString::number(delay / 1000); + // delay = delay < MAXDELAY ? delay : MAXDELAY; + if (delay > 0) { + // qDebug() << "****************PushStream sleep time:" + // << QString::number(delay / 1000); + av_usleep(delay); + // sleepMsec(40); + } else { + if (delay < -50000) { + // 滞后50ms以上,丢弃非重要帧 + if (!(inputPacket->flags & AV_PKT_FLAG_KEY)) { + av_packet_unref(inputPacket); + continue; + } + // 调整基准时间,减少滞后 + m_startTime += 50000; + } + } + // 计算延时后,重新指定时间戳 + av_packet_rescale_ts(inputPacket, m_inputTimeBase, + m_outputTimeBase); + inputPacket->pos = -1; + inputPacket->stream_index = 0; + if (inputPacket->pts < inputPacket->dts) { + // qDebug() << "pts < dts"; + if (!(inputPacket->flags & AV_PKT_FLAG_KEY)) { + av_packet_unref(inputPacket); + continue; + } + } + + // 向推流服务器推送流数据 + m_frm_cnt++; + int ret = + av_interleaved_write_frame(m_outputFormatCtx, inputPacket); + if (ret < 0) { + av_packet_unref(inputPacket); + showError(ret); + // if (ret == -10053) { + // qDebug() << "网络不稳定"; + // } + if (reconnect(ret) < 0) { + break; + }; + continue; + } + // 数据包写入成功,现在可以释放pkt + av_packet_unref(inputPacket); + av_packet_free(&inputPacket); + } else { + QThread::usleep(1000); + } + } + + if (m_bwriteHeader) av_write_trailer(m_outputFormatCtx); + free(); + qDebug() << "Push Stream End!"; + emit sendErrorMessageSignal("推流结束!", + NotificationType::NOTIFICATION_SUCCESS); +} + +void PushStream::free() { + m_start = false; + // 关闭输出 + if (m_outputFormatCtx && !(m_outputFormatCtx->flags & AVFMT_NOFILE)) { + avio_close(m_outputFormatCtx->pb); + } + if (m_outputFormatCtx) { + avformat_free_context(m_outputFormatCtx); + m_outputFormatCtx = nullptr; + } +} diff --git a/Src/VideoGL/pushstream.h b/Src/VideoGL/pushstream.h new file mode 100644 index 0000000..d42c233 --- /dev/null +++ b/Src/VideoGL/pushstream.h @@ -0,0 +1,59 @@ +#ifndef PUSHSTREAM_H +#define PUSHSTREAM_H + +#include +#include +#include +#include +#include + +#include "avpacketqueuemanager.h" +#include "ffmpeginclude.h" +class PushStream : public QObject { + Q_OBJECT +public: + explicit PushStream(QObject *parent = nullptr); + /** + * @brief 设置推流地址 + * @param url 远端推流地址 + */ + void setRemoteIP(QString url); + bool init(AVFormatContext *inputFormatCtx, + AVPacketQueueManager *queueManager); + void close(); +public slots: + void pushStream(int64_t startTime); +signals: + void startPushStreamSignal(int64_t startTime); + void sendErrorMessageSignal(QString message, int type); + +private: + bool openNetworkStream(AVFormatContext *inputFormatCtx); + int reconnect(int ret); + void free(); + +private: + // QQueue *m_pusherQueue = nullptr; + AVFormatContext *m_inputFormatCtx = nullptr; // + AVFormatContext *m_outputFormatCtx = NULL; // + AVStream *m_istream = nullptr; + AVStream *m_ostream = nullptr; + bool m_bwriteHeader = false; + int m_videoIndex = -1; + QString m_pushStreamIP; // 推流地址 + bool m_start = false; + bool m_end = false; + int64_t m_startTime; + int64_t m_firstPts; + int m_frm_cnt = 0; + int MAXCONNECT = 12; + int MAXDELAY = 40000; // 最大休眠时间40ms + AVPacketQueueManager *m_queueManager = nullptr; + // QMutex m_mutex; + + AVRational m_inputTimeBase; + AVRational m_inputFrameRate; + AVRational m_outputTimeBase; +}; + +#endif // PUSHSTREAM_H diff --git a/Src/VideoGL/readstream.cpp b/Src/VideoGL/readstream.cpp new file mode 100644 index 0000000..8885900 --- /dev/null +++ b/Src/VideoGL/readstream.cpp @@ -0,0 +1,309 @@ +#include "readstream.h" + +ReadStream::ReadStream(QObject *parent) : QObject{parent} { + // m_packetsQueue.reserve(QUEUECAPACITY); + // m_saverQueue.reserve(QUEUECAPACITY); + // m_pusherQueue.reserve(QUEUECAPACITY); + initFFmpeg(); +} + +ReadStream::~ReadStream() {} + +bool ReadStream::openFile(const QString &url) { + if (url.isNull()) return false; + AVDictionary *dict = nullptr; + // 如果设置失败,则设置UDP传输 + // av_dict_set(&dict, "rtsp_transport", "udp", 0); + // ////注:设置tcp会导致吊舱拉流中断 设置缓存大小,1080p可将值调大 + av_dict_set(&dict, "buffer_size", "4096000", 0); + // 设置超时断开连接时间,单位微秒//listen_timeout + // av_dict_set(&avdic, "listen_timeout", "200000", 0); + av_dict_set(&dict, "stimeout", "5000000", 0); // 设置超时5秒 + av_dict_set(&dict, "timeout", "5000000", 0); // 设置5秒超时 + av_dict_set(&dict, "max_delay", "300000", 0); // 设置最大时延300ms + av_dict_set(&dict, "tune", "zerolatency", 0); // 实时编码 + av_dict_set(&dict, "preset", "faster", 0); // ultrafast,faster + av_dict_set(&dict, "threads", "auto", 0); // 自动开启线程数 + // 设置最大重试时间为1s,解决avformat_open_input打开空流时间过长问题 + av_dict_set(&dict, "max_interleave_delta", "1000000", 0); + // av_dict_set(&dict, "reconnect", "1", 0); // 开启自动重连 + // av_dict_set(&dict, "reconnect_streamed", "1", 0); // 对于流媒体自动重连 + // av_dict_set(&dict, "reconnect_at_eof", "1", 0); + av_dict_set(&dict, "reconnect_delay_max", "5", + 0); // 最大重连延时 5 秒 + // 设置非阻塞标志 + // av_dict_set(&dict, "flags", "+nonblock", 0); + // 打开输入流之前,设置非阻塞模式 + // m_formatContext = avformat_alloc_context(); + // m_formatContext->flags |= AVFMT_FLAG_NONBLOCK; + // 打开输入流并返回解封装上下文 + int ret = avformat_open_input( + &m_formatContext, // 返回解封装上下文 + url.toUtf8().data(), // 打开视频地址 + nullptr, // 如果非null,此参数强制使用特定的输入格式。自动选择解封装器(文件格式) + &dict); // 参数设置 + // 释放参数字典 + if (dict) { + av_dict_free(&dict); + } + // 打开视频失败 + if (ret < 0) { + showError(ret); + free(); + return false; + } + // 读取媒体文件的数据包以获取流信息。 + ret = avformat_find_stream_info(m_formatContext, nullptr); + if (ret < 0) { + showError(ret); + free(); + return false; + } + + // 通过AVMediaType枚举查询视频流ID(也可以通过遍历查找),最后一个参数无用 + m_videoIndex = av_find_best_stream(m_formatContext, AVMEDIA_TYPE_VIDEO, -1, + -1, nullptr, 0); + if (m_videoIndex < 0) { + showError(m_videoIndex); + free(); + return false; + } + + m_startTime = -1; + m_pullURL = url; + return initObject(); +} + +bool ReadStream::setStreamDecoder(DecodeStream *decodeStreamer) { + if (decodeStreamer) { + // QMutexLocker locker(&m_mutex); + m_streamDecoder = decodeStreamer; + m_queueManager.clearDecodeQueue(); + m_decodeStreamFlag = m_streamDecoder->init( + &m_queueManager, m_formatContext, m_videoIndex); + if (m_decodeStreamFlag) emit decodeStreamer->startDecodeSignal(); + return m_decodeStreamFlag; + } else { + m_decodeStreamFlag = false; + } + return false; +} + +bool ReadStream::setStreamSaver(SaveStream *streamSaver) { + if (streamSaver) { + m_streamSaver = streamSaver; + m_queueManager.clearSaveQueue(); + m_saveStreamFlag = + m_streamSaver->init(m_formatContext, &m_queueManager, m_videoIndex); + return m_saveStreamFlag; + } else { + m_saveStreamFlag = false; + } + return false; +} + +bool ReadStream::setStreamPusher(PushStream *streamPusher) { + if (streamPusher) { + m_streamPusher = streamPusher; + m_queueManager.clearPushQueue(); + m_pushStreamFlag = streamPusher->init(m_formatContext, &m_queueManager); + if (m_pushStreamFlag) streamPusher->startPushStreamSignal(0); + return m_pushStreamFlag; + } else { + m_pushStreamFlag = false; + } + return false; +} + +void ReadStream::close() { + // QMutexLocker locker(&m_mutex); + m_start = false; + m_end = true; + // if (m_streamDecoder) { + // m_streamDecoder->close(); + // } + // if (m_streamSaver) { + // m_streamSaver->close(); + // } + // if (m_streamPusher) { + // m_streamPusher->close(); + // } +} + +void ReadStream::startPullStream() { + // 如果没有打开则返回 + if (!m_formatContext) { + return; + } + qDebug() << "readStreamThreadID:" << QThread::currentThreadId(); + emit m_streamSaver->startSaveStreamSignal(); + m_start = true; + int readRet; + // 读取数据包 + while (m_start) { + 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) { // 流文件结束 + qDebug() << "Stream End"; + av_packet_unref(m_inputPacket); + close(); + break; + } else if (readRet < 0) { // 发生错误 + qDebug() << "Stream Error"; + if (reconnect()) { + continue; + } else { + if (m_streamDecoder) { + m_streamDecoder->close(); + } + if (m_streamSaver) { + m_streamSaver->close(); + } + if (m_streamPusher) { + m_streamPusher->close(); + } + break; + } + } + if (isValidAVPacket(m_inputPacket)) { + if (m_inputPacket->stream_index == m_videoIndex) { + if (m_decodeStreamFlag) { + m_queueManager.enqueueDecodePacket(m_inputPacket); + } + + if (m_saveStreamFlag) { + m_queueManager.enqueueSavePacket(m_inputPacket); + } + + if (m_pushStreamFlag) { + m_queueManager.enqueuePushPacket(m_inputPacket); + } + } + } + av_packet_unref(m_inputPacket); + QThread::usleep(2000); // 等待 2 毫秒 + } + clear(); + free(); + qDebug() << "read Stream End!"; +} + +void ReadStream::initFFmpeg() { + avformat_network_init(); + // m_formatContext = avformat_alloc_context(); + // m_formatContext->flags |= AVFMT_FLAG_NONBLOCK; +} + +bool ReadStream::initObject() { + // 分配AVPacket并将其字段设置为默认值。 + m_inputPacket = av_packet_alloc(); + if (!m_inputPacket) { +#if PRINT_LOG + qWarning() << "av_packet_alloc() Error!"; +#endif + free(); + return false; + } + + return true; +} + +/** + * @brief 清空读取缓冲 + */ +void ReadStream::clear() { + // 因为avformat_flush不会刷新AVIOContext + // (s->pb)。如果有必要,在调用此函数之前调用avio_flush(s->pb)。 + if (m_formatContext && m_formatContext->pb) { + avio_flush(m_formatContext->pb); + } + if (m_formatContext) { + avformat_flush(m_formatContext); // 清理读取缓冲 + } +} + +void ReadStream::free() { + // 关闭并失败m_formatContext,并将指针置为null + if (m_formatContext) { + avformat_close_input(&m_formatContext); + } + if (m_inputPacket) { + av_packet_free(&m_inputPacket); + } +} + +bool ReadStream::reconnect() { + m_end = false; + if (m_streamDecoder) { + m_streamDecoder->close(); + } + if (m_streamSaver) { + m_streamSaver->close(); + } + if (m_streamPusher) { + m_streamPusher->close(); + } + free(); + for (int i = 0; i < MAXRECONNECT; ++i) { + m_start = openFile(m_pullURL); + if (m_start) { + emit sendErrorMessageSignal("重连成功!", 1); + if (m_streamDecoder) { + setStreamDecoder(m_streamDecoder); + } + if (m_streamSaver) { + setStreamSaver(m_streamSaver); + } + if (m_streamPusher) { + setStreamPusher(m_streamPusher); + } + return true; + } else { + qDebug() << "reconnect failed:" << QString::number(i + 1); + QString str = QString("流中断,尝试重新连接第%1次").arg(i + 1); + emit sendErrorMessageSignal(str, 3); + free(); + // close(); + } + if (m_end) break; + } + emit sendErrorMessageSignal("重连失败!", 2); + return false; +} + +bool ReadStream::isValidAVPacket(AVPacket *pkt) { + if (pkt == nullptr) { + qDebug() << "Invalid AVPacket 0: packet pointer is null."; + return false; + } + // 检查数据指针和大小 + if (pkt->data == nullptr || pkt->size <= 0) { + qDebug() + << "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() << "Invalid AVPacket 0: pts or dts is AV_NOPTS_VALUE.\n"; + return false; + } + + // 检查流索引(如果是多流) + if (pkt->stream_index < 0) { + qDebug() << "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; +} diff --git a/Src/VideoGL/readstream.h b/Src/VideoGL/readstream.h new file mode 100644 index 0000000..bc05ed2 --- /dev/null +++ b/Src/VideoGL/readstream.h @@ -0,0 +1,83 @@ +#ifndef READSTREAM_H +#define READSTREAM_H + +#include +#include +#include +#include +#include +#include + +#include "avpacketqueuemanager.h" +#include "decodestream.h" +#include "ffmpeginclude.h" +#include "pushstream.h" +#include "savestream.h" + +class ReadStream : public QObject { + Q_OBJECT +public: + explicit ReadStream(QObject *parent = nullptr); + ~ReadStream(); + bool openFile(const QString &url); + bool setStreamDecoder(DecodeStream *decodeStreamer); + bool setStreamSaver(SaveStream *streamSaver); + bool setStreamPusher(PushStream *streamPusher); // 开启推流 + void close(); + +public slots: + void startPullStream(); +signals: + // void startDecodeSignal(); + void startPullStreamSignal(); + void sendErrorMessageSignal(QString message, int type); + +private: + void initFFmpeg(); // 初始化ffmpeg库(整个程序中只需加载一次) + bool initObject(); // 初始化对象 + // void showError(int err); // 显示ffmpeg执行错误时的错误信息 + // qreal rationalToDouble(AVRational* rational); // + // 将AVRational转换为double + void clear(); // 清空读取缓冲 + void free(); // 释放 + + /** + * @brief 重连 + * @return 重连成功或失败 + */ + bool reconnect(); + + bool isValidAVPacket(AVPacket *pkt); + +private: + bool m_pushStreamFlag = false; // 推流开始标识 + bool m_decodeStreamFlag = false; + bool m_saveStreamFlag = false; + QString m_pullURL; // 拉流地址 + int MAXRECONNECT = 12; // 最大重连次数 + qreal m_frameRate = 0; // 视频帧率 + QSize m_size; // 视频分辨率大小 + uchar *m_buffer = nullptr; + 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 m_packetsQueue; + // QQueue m_saverQueue; + // QQueue m_pusherQueue; + + DecodeStream *m_streamDecoder = nullptr; + SaveStream *m_streamSaver = nullptr; + PushStream *m_streamPusher = nullptr; + + // QMutex m_mutex; + AVPacketQueueManager m_queueManager; +}; + +#endif // READSTREAM_H diff --git a/Src/VideoGL/savestream.cpp b/Src/VideoGL/savestream.cpp new file mode 100644 index 0000000..505895e --- /dev/null +++ b/Src/VideoGL/savestream.cpp @@ -0,0 +1,140 @@ +#include "savestream.h" + +SaveStream::SaveStream(QObject *parent) : QObject{parent} {} + +bool SaveStream::init(AVFormatContext *formatContext, + AVPacketQueueManager *queueManager, int videoIndex) { + // m_inputCodecContex = codecContex; + m_inputFormatContext = formatContext; + // m_saverQueue = queue; + m_queueManager = queueManager; + m_videoIndex = videoIndex; + m_start = openFile(); + if (!m_start) { + free(); + } + return m_start; +} + +void SaveStream::setSaveFileDirPath(QString fileDirPath) { + m_outputDirPath = fileDirPath; +} + +void SaveStream::close() { + // QMutexLocker locker(&m_mutex); + m_start = false; +} + +void SaveStream::startSaveStream() { + qDebug() << "SaveStreamThreadID:" << QThread::currentThreadId(); + if (!m_start) { + return; + } + while (m_start || !m_queueManager->isEmptySaveQueue()) { + AVPacket *inputPacket = m_queueManager->dequeueSavePacket(); + if (inputPacket) { + // 由于保存的m_formatContextSave只创建了一个视频流,而读取到的图像的流索引不一定为0,可能会出现错误【Invalid + // packet stream index: 1】 + // 所以这里需要将stream_index指定为和m_formatContextSave中视频流索引相同,因为就一个流,所以直接设置为0 + inputPacket->stream_index = 0; + av_write_frame(m_formatContextSave, + inputPacket); // 将数据包写入输出媒体文件 + av_packet_unref(inputPacket); + inputPacket = nullptr; + } else { + QThread::usleep(1000); + } + } + // 写入文件尾 + if (m_formatContextSave && m_writeHeader) { + av_write_trailer(m_formatContextSave); + m_writeHeader = false; + } + free(); + qDebug() << "视频保存结束!"; + emit sendErrorMessageSignal("视频保存结束!", + NotificationType::NOTIFICATION_SUCCESS); +} + +bool SaveStream::openFile() { + // QMutexLocker locker(&m_mutex); + QDir dir; + if (!dir.exists(m_outputDirPath)) { + dir.mkdir(m_outputDirPath); + } + 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( + &m_formatContextSave, nullptr, nullptr, strName.toStdString().data()); + if (ret < 0) { + showError(ret); + qWarning() << "avformat_alloc_output_context2 Error!"; + 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) { + free(); + qWarning() << "Create New Stream Error"; + return false; + } + // 拷贝一些参数,给codecpar赋值(这里使用编码器上下文进行赋值) + // ret = avcodec_parameters_from_context(m_videoStreamOut->codecpar, + // m_inputCodecContex); + ret = avcodec_parameters_copy( + m_videoStreamOut->codecpar, + m_inputFormatContext->streams[m_videoIndex]->codecpar); + if (ret < 0) { + showError(ret); + free(); + qWarning() << "avcodec_parameters_from_context Failed"; + return false; + } + + // 写入文件头 + ret = avformat_write_header(m_formatContextSave, nullptr); + if (ret < 0) { + showError(ret); + free(); + qWarning() << "avformat_write_header Error"; + return false; + } + + m_writeHeader = true; + qDebug() << "保存视频文件初始化成功!"; + return true; +} + +void SaveStream::free() { + // 关闭文件 + if (m_formatContextSave && !(m_formatContextSave->flags & AVFMT_NOFILE)) { + avio_close(m_formatContextSave->pb); + // av_freep(m_videoStreamOut); + + // avformat_free_context(m_formatContextSave); + // m_formatContextSave = nullptr; + } + if (m_formatContextSave) { + avformat_free_context(m_formatContextSave); + m_formatContextSave = nullptr; + } +} diff --git a/Src/VideoGL/savestream.h b/Src/VideoGL/savestream.h new file mode 100644 index 0000000..4825356 --- /dev/null +++ b/Src/VideoGL/savestream.h @@ -0,0 +1,52 @@ +#ifndef SAVESTREAM_H +#define SAVESTREAM_H + +#include +#include +#include +#include +#include +#include + +#include "avpacketqueuemanager.h" +#include "ffmpeginclude.h" + +class SaveStream : public QObject { + Q_OBJECT +public: + explicit SaveStream(QObject *parent = nullptr); + bool init(AVFormatContext *formatContext, + AVPacketQueueManager *queueManager, int videoIndex); + /** + * @brief 设置拉流保存文件夹路径 + * @param fileDirPath 文件夹路径 + */ + void setSaveFileDirPath(QString fileDirPath); + void close(); +public slots: + void startSaveStream(); +signals: + void startSaveStreamSignal(); + void sendErrorMessageSignal(QString message, int type); + +private: + bool openFile(); + void free(); + +private: + AVFormatContext *m_formatContextSave = nullptr; // 封装上下文 + AVFormatContext *m_inputFormatContext = nullptr; + // AVCodecContext *m_inputCodecContex = nullptr; // 解码器上下文 + QString m_strCodecName; // 编解码器名称 + AVStream *m_videoStreamOut = nullptr; // 输出视频流 + int m_videoIndex = 0; + bool m_writeHeader = false; // 是否写入文件头 + QString m_outputDirPath; + bool m_start; + + // QQueue *m_saverQueue; + AVPacketQueueManager *m_queueManager = nullptr; + // QMutex m_mutex; +}; + +#endif // SAVESTREAM_H diff --git a/Src/VideoGL/vertex.vsh b/Src/VideoGL/vertex.vsh new file mode 100644 index 0000000..fb7430e --- /dev/null +++ b/Src/VideoGL/vertex.vsh @@ -0,0 +1,9 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCord; +out vec2 TexCord; // 纹理坐标 +void main() +{ + gl_Position = vec4(aPos.x, -aPos.y, aPos.z, 1.0); // 图像坐标和OpenGL坐标Y轴相反, + TexCord = aTexCord; +} diff --git a/Src/VideoGL/videowidget.cpp b/Src/VideoGL/videowidget.cpp new file mode 100644 index 0000000..b9368a9 --- /dev/null +++ b/Src/VideoGL/videowidget.cpp @@ -0,0 +1,579 @@ +#include "videowidget.h" + +#if USE_WINDOW +VideoWidget::VideoWidget(QOpenGLWindow::UpdateBehavior updateBehavior, + QWindow *parent) + : QOpenGLWindow(updateBehavior, parent) { + // 初始化视图大小,由于Shader里面有YUV转RGB的代码,会初始化显示为绿色,这里通过将视图大小设置为0避免显示绿色背景 + m_pos = QPointF(0, 0); + m_zoomSize = QSize(0, 0); +} +#else +VideoWidget::VideoWidget(QWidget *parent, Qt::WindowFlags f) + : QOpenGLWidget(parent, f) { + // 初始化视图大小,由于Shader里面有YUV转RGB的代码,会初始化显示为绿色,这里通过将视图大小设置为0避免显示绿色背景 + m_pos = QPointF(0, 0); + m_zoomSize = QSize(0, 0); +} +#endif + +VideoWidget::~VideoWidget() { + if (!isValid()) + return; // 如果控件和OpenGL资源(如上下文)已成功初始化,则返回true。 + + decodeStreamer->disconnect(this); + stopPlay(); + stopPushStream(); + + if (readStreamer) { + readStreamer->deleteLater(); + } + if (decodeStreamer) { + decodeStreamer->deleteLater(); + } + if (saveStreamer) { + saveStreamer->deleteLater(); + } + if (streamPusher) { + streamPusher->deleteLater(); + } + + // 通过将相应的上下文设置为当前上下文并在该上下文中绑定帧缓冲区对象,为呈现此小部件的OpenGL内容做准备。 + this->makeCurrent(); + + freeTexYUV420P(); + freeTexNV12(); + this->doneCurrent(); // 释放上下文 + // 释放 + glDeleteBuffers(1, &VBO); + glDeleteBuffers(1, &EBO); + glDeleteVertexArrays(1, &VAO); +} + +bool VideoWidget::play(const QString &url) { + // if (url.isEmpty()) return; + if (!m_pullFlag) { + m_pullFlag = pullStream(url); + 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 + + if (m_HWDecoder) decodeStreamer->setHWDecoder(m_HWDecoder); + decodeStreamer->moveToThread(&decodeStreamThread); + decodeStreamThread.start(); + + bool ss = readStreamer->setStreamDecoder(decodeStreamer); + if (!ss) { + qDebug() << "解码器初始化失败!\n"; + emit sendErrorMessageSignal("解码器初始化失败!", + NotificationType::NOTIFICATION_ERROR); + stopPlay(); + return false; + } + + m_playFlag = true; + return true; +} + +void VideoWidget::stopPlay() { + m_playFlag = false; + if (decodeStreamer) { + decodeStreamer->disconnect(this); + // QThread::usleep(2000); + decodeStreamer->close(); + } + decodeStreamThread.quit(); + decodeStreamThread.wait(); + if (!m_pushFlag) { + if (readStreamer) { + readStreamer->close(); + } + readStreamThread.quit(); + readStreamThread.wait(); + m_pullFlag = false; + + if (saveStreamer) { + saveStreamer->close(); + } + saveStreamThread.quit(); + saveStreamThread.wait(); + } +} + +// 推流 +bool VideoWidget::pushStream(const QString &url) { + if (url.isEmpty()) { + return false; + } else { + // 先拉流 + if (!m_pullFlag) { + m_pullFlag = this->pullStream(m_pullURL); + if (!m_pullFlag) { + emit sendErrorMessageSignal("获取视频流失败!", 2); + return false; + } + } + // 推流线程 + if (!streamPusher) { + streamPusher = new PushStream; + connect(streamPusher, &PushStream::startPushStreamSignal, + streamPusher, &PushStream::pushStream, + Qt::UniqueConnection); + connect(streamPusher, &PushStream::sendErrorMessageSignal, this, + &VideoWidget::receiveErrorMessage, Qt::UniqueConnection); + } + streamPusher->setRemoteIP(url); + streamPusher->moveToThread(&pushStreamThread); + pushStreamThread.start(); + + bool ss = readStreamer->setStreamPusher(streamPusher); + if (!ss) { + emit sendErrorMessageSignal("推流初始化失败!", 2); + stopPushStream(); + return false; + } + + m_pushURL = url; + m_pushFlag = true; + return true; + } +} + +void VideoWidget::stopPushStream() { + m_pushFlag = false; + if (streamPusher) streamPusher->close(); + pushStreamThread.quit(); + pushStreamThread.wait(); + if (!m_playFlag) { + if (readStreamer) readStreamer->close(); + readStreamThread.quit(); + readStreamThread.wait(); + m_pullFlag = false; + + if (saveStreamer) saveStreamer->close(); + saveStreamThread.quit(); + saveStreamThread.wait(); + } +} + +void VideoWidget::setPullURL(const QString &url) { + m_pullURL = url; +} + +void VideoWidget::setPushURL(const QString &url) { + m_pushURL = url; +} + +void VideoWidget::setHWDecoder(bool flag) { + m_HWDecoder = flag; +} + +void VideoWidget::setVedioSaveFileDirPath(const QString &dirPath) { + m_videoSaveDirPath = dirPath; +} + +void VideoWidget::repaint(AVFrame *frame) { + try { + QMutexLocker locker(&m_mutex); + // 如果帧长宽为0则不需要绘制 + if (!frame || frame->width <= 0 || frame->height <= 0) return; + if (!isValid() || frame->format == AV_PIX_FMT_NONE) { + av_frame_unref(frame); + return; + } + + m_format = frame->format; + switch (m_format) { + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUV420P: // ffmpeg软解码的像素格式为YUV420P + { + repaintTexYUV420P(frame); + break; + } + case AV_PIX_FMT_NV12: // 由于ffmpeg硬件解码的像素格式为NV12,不是YUV,所以需要单独处理 + { + repaintTexNV12(frame); + break; + } + default: { + // av_frame_unref(frame); + // return; + break; + } + } + + av_frame_unref(frame); // 取消引用帧引用的所有缓冲区并重置帧字段。 + + this->update(); + } catch (...) { + return; + } +} + +/** + * @brief 更新YUV420P图像数据纹理 + * @param frame + */ +void VideoWidget::repaintTexYUV420P(AVFrame *frame) { + // 当切换显示的视频后,如果分辨率不同则需要重新创建纹理,否则会崩溃 + if (frame->width != m_size.width() || frame->height != m_size.height()) { + freeTexYUV420P(); + } + + initTexYUV420P(frame->width, frame->height); + + if (m_texY && m_texU && m_texV) { + m_options.setImageHeight(frame->height); + m_options.setRowLength(frame->linesize[0]); + m_texY->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, + static_cast(frame->data[0]), + &m_options); // 设置图像数据 Y + + m_options.setRowLength(frame->linesize[1]); + m_texU->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, + static_cast(frame->data[1]), + &m_options); // 设置图像数据 U + m_options.setRowLength(frame->linesize[2]); + m_texV->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, + static_cast(frame->data[2]), + &m_options); // 设置图像数据 V + } +} + +/** + * @brief 初始化YUV420P图像纹理 + * @param frame + */ +void VideoWidget::initTexYUV420P(int width, int height) { + if (!m_texY) // 初始化纹理 + { + // 创建2D纹理 + m_texY = new QOpenGLTexture(QOpenGLTexture::Target2D); + // 设置纹理大小 + m_texY->setSize(width, height); + // 设置放大、缩小过滤器 + m_texY->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, + QOpenGLTexture::Linear); + // 设置图像格式 + m_texY->setFormat(QOpenGLTexture::R8_UNorm); + // 分配内存 + m_texY->allocateStorage(); + // 记录图像分辨率 + m_size.setWidth(width); + m_size.setHeight(height); + resizeGL(this->width(), this->height()); + } + if (!m_texU) { + m_texU = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texU->setSize(width / 2, height / 2); + m_texU->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, + QOpenGLTexture::Linear); + m_texU->setFormat(QOpenGLTexture::R8_UNorm); + m_texU->allocateStorage(); + } + if (!m_texV) // 初始化纹理 + { + m_texV = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texV->setSize(width / 2, height / 2); + m_texV->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, + QOpenGLTexture::Linear); + m_texV->setFormat(QOpenGLTexture::R8_UNorm); + m_texV->allocateStorage(); + } +} + +/** + * @brief 释放YUV420P图像纹理 + */ +void VideoWidget::freeTexYUV420P() { + // 释放纹理 + if (m_texY) { + m_texY->destroy(); + delete m_texY; + m_texY = nullptr; + } + if (m_texU) { + m_texU->destroy(); + delete m_texU; + m_texU = nullptr; + } + if (m_texV) { + m_texV->destroy(); + delete m_texV; + m_texV = nullptr; + } +} + +/** + * @brief 更新NV12图像数据纹理 + * @param frame + */ +void VideoWidget::repaintTexNV12(AVFrame *frame) { + // 当切换显示的视频后,如果分辨率不同则需要重新创建纹理,否则会崩溃 + if (frame->width != m_size.width() || frame->height != m_size.height()) { + freeTexNV12(); + } + initTexNV12(frame); + + if (m_texY && m_texUV) { + m_options.setImageHeight(frame->height); + m_options.setRowLength(frame->linesize[0]); + m_texY->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, + static_cast(frame->data[0]), + &m_options); // 设置图像数据 Y + m_options.setImageHeight(frame->height / 2); + m_options.setRowLength(frame->linesize[1] / 2); + m_texUV->setData(QOpenGLTexture::RG, QOpenGLTexture::UInt8, + static_cast(frame->data[1]), + &m_options); // 设置图像数据 UV + } +} + +/** + * @brief 初始化NV12图像纹理 + * @param frame + */ +void VideoWidget::initTexNV12(AVFrame *frame) { + if (!m_texY) // 初始化纹理 + { + // 创建2D纹理 + m_texY = new QOpenGLTexture(QOpenGLTexture::Target2D); + // 设置纹理大小 + m_texY->setSize(frame->width, frame->height); + // 设置放大、缩小过滤器 + m_texY->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, + QOpenGLTexture::Linear); + // 设置图像格式 + m_texY->setFormat(QOpenGLTexture::R8_UNorm); + // 分配内存 + m_texY->allocateStorage(); + // 记录图像分辨率 + m_size.setWidth(frame->width); + m_size.setHeight(frame->height); + resizeGL(this->width(), this->height()); + } + if (!m_texUV) { + m_texUV = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texUV->setSize(frame->width / 2, frame->height / 2); + m_texUV->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, + QOpenGLTexture::Linear); + m_texUV->setFormat(QOpenGLTexture::RG8_UNorm); + m_texUV->allocateStorage(); + } +} + +/** + * @brief 释放NV12图像纹理 + */ +void VideoWidget::freeTexNV12() { + // 释放纹理 + if (m_texY) { + m_texY->destroy(); + delete m_texY; + m_texY = nullptr; + } + if (m_texUV) { + m_texUV->destroy(); + delete m_texUV; + m_texUV = nullptr; + } +} + +// 三个顶点坐标XYZ,VAO、VBO数据播放,范围时[-1 ~ 1]直接 +static GLfloat vertices[] = { + // 前三列点坐标,后两列为纹理坐标 + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // 右上角 + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // 右下 + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // 左下 + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f // 左上 +}; + +static GLuint indices[] = {0, 1, 3, 1, 2, 3}; + +void VideoWidget::initializeGL() { + // 初始化 OpenGL 功能 + initializeOpenGLFunctions(); + + // 加载shader脚本程序 + m_program = new QOpenGLShaderProgram(this); + m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, + ":/gl/vertex.vsh"); + m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, + ":/gl/fragment.fsh"); + m_program->link(); + + // 绑定YUV 变量值 + m_program->bind(); + m_program->setUniformValue("tex_y", 0); + m_program->setUniformValue("tex_u", 1); + m_program->setUniformValue("tex_v", 2); + m_program->setUniformValue("tex_uv", 3); + + GLuint posAttr = GLuint(m_program->attributeLocation("aPos")); + GLuint texCord = GLuint(m_program->attributeLocation("aTexCord")); + + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + + glGenBuffers(1, &VBO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glGenBuffers(1, &EBO); // 创建一个EBO + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, + GL_STATIC_DRAW); // 将顶点索引数组传入EBO缓存 + // 设置顶点坐标数据 + glVertexAttribPointer(posAttr, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), + nullptr); + // 启用通用顶点属性数组 + glEnableVertexAttribArray(posAttr); + + // 设置纹理坐标数据 + glVertexAttribPointer( + texCord, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), + reinterpret_cast(3 * sizeof(GLfloat))); + + glEnableVertexAttribArray(texCord); + + // 释放 + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); +} + +void VideoWidget::resizeGL(int w, int h) { + if (m_size.width() < 0 || m_size.height() < 0) return; + + QScreen *screen = this->window()->windowHandle() + ? this->window()->windowHandle()->screen() + : QGuiApplication::primaryScreen(); + double scaleFactor = screen->devicePixelRatio(); + w = static_cast(w * scaleFactor); + h = static_cast(h * scaleFactor); + + // 计算需要显示图片的窗口大小,用于实现长宽等比自适应显示 + if ((double(w) / h) < (double(m_size.width()) / m_size.height())) { + m_zoomSize.setWidth(w); + m_zoomSize.setHeight(((double(w) / m_size.width()) * m_size.height())); + } else { + m_zoomSize.setHeight(h); + m_zoomSize.setWidth((double(h) / m_size.height()) * m_size.width()); + } + m_pos.setX(double(w - m_zoomSize.width()) / 2); + m_pos.setY(double(h - m_zoomSize.height()) / 2); + this->update(QRect(0, 0, w, h)); +} + +void VideoWidget::paintGL() { + glClear(GL_COLOR_BUFFER_BIT); + glViewport(m_pos.x(), m_pos.y(), m_zoomSize.width(), m_zoomSize.height()); + + m_program->bind(); + m_program->setUniformValue("format", m_format); + + // 绑定纹理 + switch (m_format) { + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUV420P: { + if (m_texY && m_texU && m_texV) { + m_texY->bind(0); + m_texU->bind(1); + m_texV->bind(2); + } + break; + } + case AV_PIX_FMT_NV12: { + if (m_texY && m_texUV) { + m_texY->bind(0); + m_texUV->bind(3); + } + break; + } + default: + break; + } + + glBindVertexArray(VAO); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); + glBindVertexArray(0); + + // 释放纹理 + switch (m_format) { + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUV420P: { + if (m_texY && m_texU && m_texV) { + m_texY->release(); + m_texU->release(); + m_texV->release(); + } + break; + } + case AV_PIX_FMT_NV12: { + if (m_texY && m_texUV) { + m_texY->release(); + m_texUV->release(); + } + break; + } + default: + break; + } + m_program->release(); +} + +bool VideoWidget::pullStream(const QString &url) { + if (url.isEmpty()) return false; + if (!readStreamer) { + readStreamer = new ReadStream; + 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)) { + // 保存线程 + if (!saveStreamer) { + saveStreamer = new SaveStream; + connect(saveStreamer, &SaveStream::startSaveStreamSignal, + saveStreamer, &SaveStream::startSaveStream, + Qt::UniqueConnection); + } + saveStreamer->setSaveFileDirPath(m_videoSaveDirPath); + saveStreamer->moveToThread(&saveStreamThread); + saveStreamThread.start(); + + readStreamer->setStreamSaver(saveStreamer); + + qDebug() << "UIThreadID:" << QThread::currentThreadId(); + readStreamer->moveToThread(&readStreamThread); + readStreamThread.start(); + emit readStreamer->startPullStreamSignal(); + // emit startPullSignal(); + + return true; + } + return false; +} + +void VideoWidget::receiveErrorMessage(QString message, int type) { + // qDebug() << "receive message:" << message; + emit sendErrorMessageSignal(message, type); +} diff --git a/Src/VideoGL/videowidget.h b/Src/VideoGL/videowidget.h new file mode 100644 index 0000000..9638f56 --- /dev/null +++ b/Src/VideoGL/videowidget.h @@ -0,0 +1,120 @@ +#ifndef VIDEOWIDGET_H +#define VIDEOWIDGET_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "decodestream.h" +#include "ffmpeginclude.h" +#include "pushstream.h" +#include "readstream.h" + +#define USE_WINDOW 0 // 1:使用QOpenGLWindow显示, 0:使用QOpenGLWidget显示 + +#if USE_WINDOW +#include +class VideoWidget : public QOpenGLWindow, + public QOpenGLFunctions_3_3_Core +#else +#include +class VideoWidget : public QOpenGLWidget, + public QOpenGLFunctions_3_3_Core +#endif +{ + Q_OBJECT +public: +#if USE_WINDOW + explicit VideoWidget(UpdateBehavior updateBehavior = NoPartialUpdate, + QWindow *parent = nullptr); +#else + explicit VideoWidget(QWidget *parent = nullptr, + Qt::WindowFlags f = Qt::WindowFlags()); +#endif + ~VideoWidget() override; + + 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 setHWDecoder(bool flag); + void setVedioSaveFileDirPath(const QString &dirPath); + +protected: + void initializeGL() override; // 初始化gl + void resizeGL(int w, int h) override; // 窗口尺寸变化 + void paintGL() override; // 刷新显示 + void repaint(AVFrame *frame); // 设置需要绘制的图像帧 +private: + // YUV420图像数据更新 + void repaintTexYUV420P(AVFrame *frame); + void initTexYUV420P(int width, int height); + void freeTexYUV420P(); + // NV12图像数据更新 + void repaintTexNV12(AVFrame *frame); + void initTexNV12(AVFrame *frame); + void freeTexNV12(); + +private: // opengl + QOpenGLShaderProgram *m_program = nullptr; + QOpenGLTexture *m_texY = nullptr; + QOpenGLTexture *m_texU = nullptr; + QOpenGLTexture *m_texV = nullptr; + QOpenGLTexture *m_texUV = nullptr; + QOpenGLPixelTransferOptions m_options; + + GLuint VBO = + 0; // 顶点缓冲对象,负责将数据从内存放到缓存,一个VBO可以用于多个VAO + GLuint VAO = + 0; // 顶点数组对象,任何随后的顶点属性调用都会储存在这个VAO中,一个VAO可以有多个VBO + GLuint EBO = 0; // 元素缓冲对象,它存储 OpenGL 用来决定要绘制哪些顶点的索引 + QSize m_size; + QSizeF m_zoomSize; + QPointF m_pos; + int m_format; // 像素格式 + +private: + bool pullStream(const QString &url); + void receiveErrorMessage(QString message, int type); + +private: + QString m_pullURL; + QString m_pushURL; + bool m_playFlag = false; + bool m_pullFlag = false; + bool m_pushFlag = false; + bool m_HWDecoder = false; + QString m_videoSaveDirPath; + + ReadStream *readStreamer = nullptr; + QThread readStreamThread; + + DecodeStream *decodeStreamer = nullptr; + QThread decodeStreamThread; + + SaveStream *saveStreamer = nullptr; + QThread saveStreamThread; + + PushStream *streamPusher = nullptr; + QThread pushStreamThread; + + QMutex m_mutex; + +signals: + void startPullSignal(); + void sendErrorMessageSignal(QString message, int type); +}; + +#endif // VIDEOWIDGET_H diff --git a/ffmpeg/bin/ffmpeg.exe b/ffmpeg/bin/ffmpeg.exe deleted file mode 100644 index b5d3f69..0000000 Binary files a/ffmpeg/bin/ffmpeg.exe and /dev/null differ diff --git a/ffmpeg/bin/ffplay.exe b/ffmpeg/bin/ffplay.exe deleted file mode 100644 index 79ee210..0000000 Binary files a/ffmpeg/bin/ffplay.exe and /dev/null differ diff --git a/ffmpeg/bin/ffprobe.exe b/ffmpeg/bin/ffprobe.exe deleted file mode 100644 index e575016..0000000 Binary files a/ffmpeg/bin/ffprobe.exe and /dev/null differ diff --git a/global.cpp b/global.cpp index 8c952b5..8ebc371 100644 --- a/global.cpp +++ b/global.cpp @@ -2,7 +2,9 @@ global::global() {} -QString g_SoftwareVersion = "版本号:V1.0.2.3_20241114"; +QString g_SoftwareVersion = "版本号:V1.1.0.0_20241127"; + +NotifyManager *g_notifyManager = nullptr; QColor g_themeColor(51, 51, 51); QString g_PushBtnStyle = /**正常情况下样式**/ @@ -143,16 +145,16 @@ QString g_ToolBtnSelStyle = /**选中情况下样式**/ * @return */ uint16_t calCRC16(const uint8_t *cpu8Data, uint16_t u16Len) { - uint8_t u8X; - uint16_t u16CRC = 0X8848; + uint8_t u8X; + uint16_t u16CRC = 0X8848; - while (u16Len--) { - u8X = u16CRC >> 8 ^ *cpu8Data++; - u8X ^= u8X >> 4; - u16CRC = (u16CRC << 8) ^ ((uint16_t)(u8X << 12)) ^ ((uint16_t)(u8X << 5)) ^ - ((uint16_t)u8X); - } - return u16CRC; + while (u16Len--) { + u8X = u16CRC >> 8 ^ *cpu8Data++; + u8X ^= u8X >> 4; + u16CRC = (u16CRC << 8) ^ ((uint16_t)(u8X << 12)) ^ + ((uint16_t)(u8X << 5)) ^ ((uint16_t)u8X); + } + return u16CRC; } /** @@ -161,9 +163,9 @@ uint16_t calCRC16(const uint8_t *cpu8Data, uint16_t u16Len) { * @return 字符串MD5值 */ QString calculateMD5(const QString &str) { - QByteArray hash = - QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Md5); - return hash.toHex(); + QByteArray hash = + QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Md5); + return hash.toHex(); } /** @@ -179,27 +181,28 @@ QString calculateMD5(const QString &str) { QString generatePushURL(int uavID, QString appName, QString pushKey, QString uavName, int clientID, QString pushDomain, long expireTime) { - QString clientName = ""; - if (0 == clientID) { - clientName = "gcs"; // 地面端 - } else { - clientName = "uav"; // 载荷端 - } - QString streamName = - uavName + "_" + QString::number(uavID) + "_" + clientName; - QString pushURL = ""; - if (pushKey == "") { - pushURL = "rtmp://" + pushDomain + "/" + appName + "/" + streamName; - } else { - // 计算鉴权串 - long timeStamp = QDateTime::currentMSecsSinceEpoch() / 1000 + expireTime; - QString stringToMd5 = "/" + appName + "/" + streamName + "-" + - QString::number(timeStamp) + "-0-0-" + pushKey; - QString authKey = calculateMD5(stringToMd5); - pushURL = "rtmp://" + pushDomain + "/" + appName + "/" + streamName + - "?auth_key=" + QString::number(timeStamp) + "-0-0-" + authKey; - } - return pushURL; + QString clientName = ""; + if (0 == clientID) { + clientName = "gcs"; // 地面端 + } else { + clientName = "uav"; // 载荷端 + } + QString streamName = + uavName + "_" + QString::number(uavID) + "_" + clientName; + QString pushURL = ""; + if (pushKey == "") { + pushURL = "rtmp://" + pushDomain + "/" + appName + "/" + streamName; + } else { + // 计算鉴权串 + long timeStamp = + QDateTime::currentMSecsSinceEpoch() / 1000 + expireTime; + QString stringToMd5 = "/" + appName + "/" + streamName + "-" + + QString::number(timeStamp) + "-0-0-" + pushKey; + QString authKey = calculateMD5(stringToMd5); + pushURL = "rtmp://" + pushDomain + "/" + appName + "/" + streamName + + "?auth_key=" + QString::number(timeStamp) + "-0-0-" + authKey; + } + return pushURL; } std::map g_mapAppName; @@ -218,27 +221,28 @@ std::map g_mapAppName; QString generatePullURL(int uavID, QString appName, QString pullKey, QString uavName, int clientID, QString pullDomain, long expireTime) { - QString rtmpUrl = ""; - QString clientName = ""; - if (0 == clientID) { - clientName = "gcs"; // 地面端 - } else { - clientName = "uav"; // 载荷端 - } - QString streamName = - uavName + "_" + QString::number(uavID) + "_" + clientName; - if (pullKey == "") { - rtmpUrl = "rtmp://" + pullDomain + "/" + appName + "/" + streamName; - } else { - // 计算鉴权串 - long timeStamp = QDateTime::currentMSecsSinceEpoch() / 1000 + expireTime; - QString stringToMd5 = "/" + appName + "/" + streamName + "-" + - QString::number(timeStamp) + "-0-0-" + pullKey; - QString authKey = calculateMD5(stringToMd5); - rtmpUrl = "rtmp://" + pullDomain + "/" + appName + "/" + streamName + - "?auth_key=" + QString::number(timeStamp) + "-0-0-" + authKey; - } - return rtmpUrl; + QString rtmpUrl = ""; + QString clientName = ""; + if (0 == clientID) { + clientName = "gcs"; // 地面端 + } else { + clientName = "uav"; // 载荷端 + } + QString streamName = + uavName + "_" + QString::number(uavID) + "_" + clientName; + if (pullKey == "") { + rtmpUrl = "rtmp://" + pullDomain + "/" + appName + "/" + streamName; + } else { + // 计算鉴权串 + long timeStamp = + QDateTime::currentMSecsSinceEpoch() / 1000 + expireTime; + QString stringToMd5 = "/" + appName + "/" + streamName + "-" + + QString::number(timeStamp) + "-0-0-" + pullKey; + QString authKey = calculateMD5(stringToMd5); + rtmpUrl = "rtmp://" + pullDomain + "/" + appName + "/" + streamName + + "?auth_key=" + QString::number(timeStamp) + "-0-0-" + authKey; + } + return rtmpUrl; } /** @@ -246,12 +250,12 @@ QString generatePullURL(int uavID, QString appName, QString pullKey, * @param msec 延时毫秒 */ void sleepMsec(int msec) { - if (msec <= 0) - return; - QEventLoop loop; // 定义一个新的事件循环 - QTimer::singleShot( - msec, &loop, SLOT(quit())); // 创建单次定时器,槽函数为事件循环的退出函数 - loop.exec(); // 事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出 + if (msec <= 0) return; + QEventLoop loop; // 定义一个新的事件循环 + QTimer::singleShot( + msec, &loop, + SLOT(quit())); // 创建单次定时器,槽函数为事件循环的退出函数 + loop.exec(); // 事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出 } /** @@ -263,17 +267,17 @@ void sleepMsec(int msec) { */ QString generatePushURL2(int uavID, QString appName, QString uavName, int clientID, QString pushDomain) { - QString rtmpUrl = ""; - QString clientName = ""; - if (0 == clientID) { - clientName = "gcs"; // 地面端 - } else { - clientName = "uav"; // 载荷端 - } - QString streamName = - uavName + "_" + QString::number(uavID) + "_" + clientName; - rtmpUrl = "rtmp://" + pushDomain + "/" + appName + "/" + streamName; - return rtmpUrl; + QString rtmpUrl = ""; + QString clientName = ""; + if (0 == clientID) { + clientName = "gcs"; // 地面端 + } else { + clientName = "uav"; // 载荷端 + } + QString streamName = + uavName + "_" + QString::number(uavID) + "_" + clientName; + rtmpUrl = "rtmp://" + pushDomain + "/" + appName + "/" + streamName; + return rtmpUrl; } /** @@ -287,16 +291,16 @@ QString generatePushURL2(int uavID, QString appName, QString uavName, */ QString generatePullURL2(int uavID, QString appName, QString uavName, int clientID, QString pullDomain) { - QString clientName = ""; - if (0 == clientID) { - clientName = "gcs"; // 地面端 - } else { - clientName = "uav"; // 载荷端 - } - QString streamName = - uavName + "_" + QString::number(uavID) + "_" + clientName; - QString pushURL = ""; - pushURL = "rtsp://" + pullDomain + "/" + appName + "/" + streamName; + QString clientName = ""; + if (0 == clientID) { + clientName = "gcs"; // 地面端 + } else { + clientName = "uav"; // 载荷端 + } + QString streamName = + uavName + "_" + QString::number(uavID) + "_" + clientName; + QString pushURL = ""; + pushURL = "rtsp://" + pullDomain + "/" + appName + "/" + streamName; - return pushURL; + return pushURL; } diff --git a/global.h b/global.h index 381929a..3291987 100644 --- a/global.h +++ b/global.h @@ -8,7 +8,9 @@ #include #include -extern QString g_SoftwareVersion; // 软件版本号 +#include "NotifyManager.h" + +extern QString g_SoftwareVersion; // 软件版本号 /*******************系统颜色***************************************/ extern QColor g_themeColor; @@ -101,9 +103,11 @@ extern std::map g_mapAppName; */ void sleepMsec(int msec); +extern NotifyManager *g_notifyManager; + class global { public: - global(); + global(); }; -#endif // GLOBAL_H +#endif // GLOBAL_H diff --git a/main.cpp b/main.cpp index 1243f0f..0432eee 100644 --- a/main.cpp +++ b/main.cpp @@ -1,25 +1,25 @@ -#include "mainwindow.h" - #include #include #include #include +#include "mainwindow.h" + int main(int argc, char *argv[]) { - // QApplication::setAttribute(Qt::AA_UseOpenGLES); - // qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--enable-gpu-rasterization"); - QApplication a(argc, argv); - QTranslator translator; - const QStringList uiLanguages = QLocale::system().uiLanguages(); - for (const QString &locale : uiLanguages) { - const QString baseName = "PayloadAPP_" + QLocale(locale).name(); - if (translator.load(":/i18n/" + baseName)) { - a.installTranslator(&translator); - break; + // QApplication::setAttribute(Qt::AA_UseOpenGLES); + // qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--enable-gpu-rasterization"); + QApplication a(argc, argv); + QTranslator translator; + const QStringList uiLanguages = QLocale::system().uiLanguages(); + for (const QString &locale : uiLanguages) { + const QString baseName = "PayloadAPP_" + QLocale(locale).name(); + if (translator.load(":/i18n/" + baseName)) { + a.installTranslator(&translator); + break; + } } - } - MainWindow w; - w.show(); - return a.exec(); + MainWindow w; + w.show(); + return a.exec(); } diff --git a/mainwindow.cpp b/mainwindow.cpp index 9896f54..7a74723 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -1,374 +1,384 @@ #include "mainwindow.h" + +#include + +#include +#include +#include +#include + #include "Src/HomePage/homepagesetingwidget.h" #include "Src/WebPage/CustomWebEnginePage.h" #include "Src/WebPage/cwebengineview.h" #include "global.h" #include "ui_mainwindow.h" -#include -#include -#include -#include -#include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { - ui->setupUi(this); - - initFile(); - initWindow(); - initButton(); - initSignalSlot(); - processPDT = new QProcess(this); - // apply the qss - QFile file(":/res/Qss/qss.qss"); - if (file.open(QFile::ReadOnly)) { - // file.open(QFile::ReadOnly); - QString style = QLatin1String(file.readAll()); - - qApp->setStyleSheet(style); - // qDebug()<setupUi(this); + + initFile(); + initWindow(); + initButton(); + initSignalSlot(); + processPDT = new QProcess(this); + // apply the qss + QFile file(":/res/Qss/qss.qss"); + if (file.open(QFile::ReadOnly)) { + // file.open(QFile::ReadOnly); + QString style = QLatin1String(file.readAll()); + + qApp->setStyleSheet(style); + // qDebug()<state() == QProcess::NotRunning) - processPDT->kill(); - processPDT->deleteLater(); - } - delete ui; + delete m_SDFPDlg; + delete m_GDDCdlg; + delete m_HomePagedlg; + // delete processPDT; + // delete mWeb; + delete lLinkWeb; + delete adHocNetworkWeb; + delete satelliteCommWeb; + if (m_ModelCameraDlg != nullptr) delete m_ModelCameraDlg; + if (processPDT != nullptr) { + if (processPDT->state() == QProcess::NotRunning) processPDT->kill(); + processPDT->deleteLater(); + } + delete ui; } /** * @brief MainWindow::initFile 初始化配置文件 .ini */ void MainWindow::initFile() { - QString urlFile = QCoreApplication::applicationDirPath() + "/config.ini"; - QFile file(urlFile); - if (!file.open(QIODevice::ReadWrite)) { - return; - } + QString urlFile = QCoreApplication::applicationDirPath() + "/config.ini"; + QFile file(urlFile); + if (!file.open(QIODevice::ReadWrite)) { + return; + } } void MainWindow::initWindow() { - setWindowIcon(QIcon(":/res/SDFP3.png")); - - // 设置主窗口背景颜色 - QPalette palette; - palette.setColor(QPalette::Window, g_themeColor); - this->setPalette(palette); - this->setWindowTitle("载荷应用软件"); - this->resize(1450, 860); - // this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);//隐藏边框 - - m_SDFPDlg = new SDFPDlg(this); - m_GDDCdlg = new GDDCdlg(this); - m_HomePagedlg = new HomePageDlg(this); - m_rescueLoadWidget = new RescueLoadWidget(this); - - // 使用类中的get方法获取配置文件中的IP - m_allSetMap = m_HomePagedlg->settingWidget->getAllParam(); - m_GDDCdlg->setGlobalSetMap(m_allSetMap); - qDebug() << "=============设备配置================"; - qDebug() << "光电吊舱------"; - qDebug() << "远端ip" << m_allSetMap["光电吊舱"].net.remoteIp; - qDebug() << "L链----------"; - qDebug() << "ULR:" << m_allSetMap["L链"].url; - qDebug() << "宽带自组网-----"; - qDebug() << "URL:" << m_allSetMap["宽带自组网"].url; - qDebug() << "机载卫通------"; - qDebug() << "URL:" << m_allSetMap["机载卫通"].url; - qDebug() << "三维建模------"; - 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链"].url)); - - adHocNetworkWeb = new CWebEngineView(); - adHocNetworkWeb->setPage(new CustomWebEnginePage()); - adHocNetworkWeb->load(QUrl(m_allSetMap["宽带自组网"].url)); - - satelliteCommWeb = new CWebEngineView(); - satelliteCommWeb->setPage(new CustomWebEnginePage()); - satelliteCommWeb->load(QUrl(m_allSetMap["机载卫通"].url)); - - m_ModelCameraDlg = new ModelCameraDlg(this); - emit m_ModelCameraDlg->sendNetParam_signal(m_allSetMap["三维建模"].net); - // 接收主页面设置窗口的url数据传递并设置 - connect(m_HomePagedlg->settingWidget, &HomePageSetingWidget::sendOneSet, this, - [&](unsigned char urlIndex, settingStruct settings) { - switch (urlIndex) { - case HomePageSetingWidget::GDDC: - // dosomething - break; - case HomePageSetingWidget::L_Link: - lLinkWeb->load(QUrl(settings.url)); - break; - case HomePageSetingWidget::Adhoc_Network: - adHocNetworkWeb->load(QUrl(settings.url)); - break; - case HomePageSetingWidget::Satelite_Comm: - satelliteCommWeb->load(QUrl(settings.url)); - break; - case HomePageSetingWidget::ModelCamera: - m_ModelCameraDlg->sendNetParam_signal(settings.net); - break; - default: - break; - } - }); - - // 设置栈窗口,多页面共享同一窗口 - 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); - ui->stackedWidget->addWidget(m_rescueLoadWidget); - ui->stackedWidget->addWidget(m_ModelCameraDlg); - // 初始栈窗口显示主页 - ui->stackedWidget->setCurrentWidget(m_SDFPDlg); + setWindowIcon(QIcon(":/res/SDFP3.png")); + + // 设置主窗口背景颜色 + QPalette palette; + palette.setColor(QPalette::Window, g_themeColor); + this->setPalette(palette); + this->setWindowTitle("载荷应用软件"); + this->resize(1450, 860); + // this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);//隐藏边框 + + m_SDFPDlg = new SDFPDlg(this); + m_GDDCdlg = new GDDCdlg(this); + m_HomePagedlg = new HomePageDlg(this); + m_rescueLoadWidget = new RescueLoadWidget(this); + + // 使用类中的get方法获取配置文件中的IP + m_allSetMap = m_HomePagedlg->settingWidget->getAllParam(); + m_GDDCdlg->setGlobalSetMap(m_allSetMap); + qDebug() << "=============设备配置================"; + qDebug() << "光电吊舱------"; + qDebug() << "远端ip" << m_allSetMap["光电吊舱"].net.remoteIp; + qDebug() << "L链----------"; + qDebug() << "ULR:" << m_allSetMap["L链"].url; + qDebug() << "宽带自组网-----"; + qDebug() << "URL:" << m_allSetMap["宽带自组网"].url; + qDebug() << "机载卫通------"; + qDebug() << "URL:" << m_allSetMap["机载卫通"].url; + qDebug() << "三维建模------"; + 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链"].url)); + + adHocNetworkWeb = new CWebEngineView(); + adHocNetworkWeb->setPage(new CustomWebEnginePage()); + adHocNetworkWeb->load(QUrl(m_allSetMap["宽带自组网"].url)); + + satelliteCommWeb = new CWebEngineView(); + satelliteCommWeb->setPage(new CustomWebEnginePage()); + satelliteCommWeb->load(QUrl(m_allSetMap["机载卫通"].url)); + + m_ModelCameraDlg = new ModelCameraDlg(this); + emit m_ModelCameraDlg->sendNetParam_signal(m_allSetMap["三维建模"].net); + // 接收主页面设置窗口的url数据传递并设置 + connect(m_HomePagedlg->settingWidget, &HomePageSetingWidget::sendOneSet, + this, [&](unsigned char urlIndex, settingStruct settings) { + switch (urlIndex) { + case HomePageSetingWidget::GDDC: + // dosomething + break; + case HomePageSetingWidget::L_Link: + lLinkWeb->load(QUrl(settings.url)); + break; + case HomePageSetingWidget::Adhoc_Network: + adHocNetworkWeb->load(QUrl(settings.url)); + break; + case HomePageSetingWidget::Satelite_Comm: + satelliteCommWeb->load(QUrl(settings.url)); + break; + case HomePageSetingWidget::ModelCamera: + m_ModelCameraDlg->sendNetParam_signal(settings.net); + break; + default: + break; + } + }); + + // 设置栈窗口,多页面共享同一窗口 + 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); + ui->stackedWidget->addWidget(m_rescueLoadWidget); + ui->stackedWidget->addWidget(m_ModelCameraDlg); + // 初始栈窗口显示主页 + ui->stackedWidget->setCurrentWidget(m_SDFPDlg); } void MainWindow::initButton() { - int sizeX = 30; - int sizeY = 30; - int FixedWidth = 80; - ui->toolButton->setIcon(QIcon(":/res/home.png")); - ui->toolButton_2->setIcon(QIcon(":/res/GDDC.png")); - ui->toolButton_3->setIcon(QIcon(":/res/LChain.png")); - ui->toolButton_4->setIcon(QIcon(":/res/wifi4G.png")); - ui->toolButton_5->setIcon(QIcon(":/res/PDT.png")); - ui->toolButton_6->setIcon(QIcon(":/res/Ku.png")); - 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->setIconSize(QSize(sizeX, sizeY)); - ui->toolButton_2->setIconSize(QSize(sizeX, sizeY)); - ui->toolButton_3->setIconSize(QSize(sizeX, sizeY)); - ui->toolButton_4->setIconSize(QSize(sizeX, sizeY)); - ui->toolButton_5->setIconSize(QSize(sizeX, sizeY)); - ui->toolButton_6->setIconSize(QSize(sizeX, sizeY)); - 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->setText("主页"); - ui->toolButton_2->setText("光电吊舱"); - ui->toolButton_3->setText("L链"); - ui->toolButton_4->setText("自组网"); - ui->toolButton_5->setText("PDT集群"); - ui->toolButton_6->setText("机载卫通"); - ui->toolButton_7->setText("搜救载荷"); - ui->toolButton_8->setText("三维建模"); - ui->toolButton_9->setText("时代飞鹏"); - ui->toolButton->setFixedWidth(FixedWidth); - ui->toolButton_2->setFixedWidth(FixedWidth); - ui->toolButton_3->setFixedWidth(FixedWidth); - ui->toolButton_4->setFixedWidth(FixedWidth); - ui->toolButton_5->setFixedWidth(FixedWidth); - ui->toolButton_6->setFixedWidth(FixedWidth); - ui->toolButton_7->setFixedWidth(FixedWidth); - ui->toolButton_8->setFixedWidth(FixedWidth); - ui->toolButton_9->setFixedWidth(FixedWidth); - ui->toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_2->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_3->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_4->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_5->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_6->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_7->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_8->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton_9->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - ui->toolButton->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_2->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_3->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_4->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_5->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_6->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_7->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_8->setStyleSheet(g_ToolBtnStyle); - ui->toolButton_9->setStyleSheet(g_ToolBtnStyle); - // ui->pushButton->setStyleSheet(g_PushBtnStyle); + int sizeX = 30; + int sizeY = 30; + int FixedWidth = 80; + ui->toolButton->setIcon(QIcon(":/res/home.png")); + ui->toolButton_2->setIcon(QIcon(":/res/GDDC.png")); + ui->toolButton_3->setIcon(QIcon(":/res/LChain.png")); + ui->toolButton_4->setIcon(QIcon(":/res/wifi4G.png")); + ui->toolButton_5->setIcon(QIcon(":/res/PDT.png")); + ui->toolButton_6->setIcon(QIcon(":/res/Ku.png")); + 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->setIconSize(QSize(sizeX, sizeY)); + ui->toolButton_2->setIconSize(QSize(sizeX, sizeY)); + ui->toolButton_3->setIconSize(QSize(sizeX, sizeY)); + ui->toolButton_4->setIconSize(QSize(sizeX, sizeY)); + ui->toolButton_5->setIconSize(QSize(sizeX, sizeY)); + ui->toolButton_6->setIconSize(QSize(sizeX, sizeY)); + 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->setText("主页"); + ui->toolButton_2->setText("光电吊舱"); + ui->toolButton_3->setText("L链"); + ui->toolButton_4->setText("自组网"); + ui->toolButton_5->setText("PDT集群"); + ui->toolButton_6->setText("机载卫通"); + ui->toolButton_7->setText("搜救载荷"); + ui->toolButton_8->setText("三维建模"); + ui->toolButton_9->setText("时代飞鹏"); + ui->toolButton->setFixedWidth(FixedWidth); + ui->toolButton_2->setFixedWidth(FixedWidth); + ui->toolButton_3->setFixedWidth(FixedWidth); + ui->toolButton_4->setFixedWidth(FixedWidth); + ui->toolButton_5->setFixedWidth(FixedWidth); + ui->toolButton_6->setFixedWidth(FixedWidth); + ui->toolButton_7->setFixedWidth(FixedWidth); + ui->toolButton_8->setFixedWidth(FixedWidth); + ui->toolButton_9->setFixedWidth(FixedWidth); + ui->toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_2->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_3->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_4->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_5->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_6->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_7->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_8->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton_9->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->toolButton->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_2->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_3->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_4->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_5->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_6->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_7->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_8->setStyleSheet(g_ToolBtnStyle); + ui->toolButton_9->setStyleSheet(g_ToolBtnStyle); + // ui->pushButton->setStyleSheet(g_PushBtnStyle); } // 初始化信号与槽 void MainWindow::initSignalSlot() { - connect(ui->toolButton, SIGNAL(clicked()), this, SLOT(toolButton_clicked())); - connect(ui->toolButton_2, SIGNAL(clicked()), this, - SLOT(toolButton_2_clicked())); - connect(ui->toolButton_3, SIGNAL(clicked()), this, - SLOT(toolButton_3_clicked())); - connect(ui->toolButton_4, SIGNAL(clicked()), this, - SLOT(toolButton_4_clicked())); - connect(ui->toolButton_5, SIGNAL(clicked()), this, - SLOT(toolButton_5_clicked())); - connect(ui->toolButton_6, SIGNAL(clicked()), this, - SLOT(toolButton_6_clicked())); - connect(ui->toolButton_7, SIGNAL(clicked()), this, - SLOT(toolButton_7_clicked())); - connect(ui->toolButton_8, SIGNAL(clicked()), this, - SLOT(toolButton_8_clicked())); - connect(ui->toolButton_9, SIGNAL(clicked()), this, - SLOT(toolButton_9_clicked())); - connect(m_HomePagedlg->m_deviceStateDlg, &deviceStateDlg::switchToDevicePage, - this, [&](int id) { - switch (id) { - case 0: - toolButton_2_clicked(); // 光电吊舱 - break; - case 1: - toolButton_3_clicked(); // L链 - break; - case 2: - toolButton_4_clicked(); // 自组网 - break; - case 3: - toolButton_5_clicked(); // PDT集群 - break; - case 4: - toolButton_6_clicked(); // Ku卫通 - break; - case 5: - toolButton_7_clicked(); // 搜救载荷 - break; - case 6: - toolButton_8_clicked(); // 三维建模 - break; - default: - break; - } - }); + connect(ui->toolButton, SIGNAL(clicked()), this, + SLOT(toolButton_clicked())); + connect(ui->toolButton_2, SIGNAL(clicked()), this, + SLOT(toolButton_2_clicked())); + connect(ui->toolButton_3, SIGNAL(clicked()), this, + SLOT(toolButton_3_clicked())); + connect(ui->toolButton_4, SIGNAL(clicked()), this, + SLOT(toolButton_4_clicked())); + connect(ui->toolButton_5, SIGNAL(clicked()), this, + SLOT(toolButton_5_clicked())); + connect(ui->toolButton_6, SIGNAL(clicked()), this, + SLOT(toolButton_6_clicked())); + connect(ui->toolButton_7, SIGNAL(clicked()), this, + SLOT(toolButton_7_clicked())); + connect(ui->toolButton_8, SIGNAL(clicked()), this, + SLOT(toolButton_8_clicked())); + connect(ui->toolButton_9, SIGNAL(clicked()), this, + SLOT(toolButton_9_clicked())); + connect(m_HomePagedlg->m_deviceStateDlg, + &deviceStateDlg::switchToDevicePage, this, [&](int id) { + switch (id) { + case 0: + toolButton_2_clicked(); // 光电吊舱 + break; + case 1: + toolButton_3_clicked(); // L链 + break; + case 2: + toolButton_4_clicked(); // 自组网 + break; + case 3: + toolButton_5_clicked(); // PDT集群 + break; + case 4: + toolButton_6_clicked(); // Ku卫通 + break; + case 5: + toolButton_7_clicked(); // 搜救载荷 + break; + case 6: + toolButton_8_clicked(); // 三维建模 + break; + default: + break; + } + }); } // 主页 void MainWindow::toolButton_clicked() { - changeBtnColor(1); - ui->stackedWidget->setCurrentWidget(m_HomePagedlg); + changeBtnColor(1); + ui->stackedWidget->setCurrentWidget(m_HomePagedlg); } // 光电吊舱 void MainWindow::toolButton_2_clicked() { - changeBtnColor(2); - ui->stackedWidget->setCurrentWidget(m_GDDCdlg); + changeBtnColor(2); + ui->stackedWidget->setCurrentWidget(m_GDDCdlg); } // L链 void MainWindow::toolButton_3_clicked() { - changeBtnColor(3); - // mWeb->load(QUrl("http://192.168.1.10")); - ui->stackedWidget->setCurrentWidget(lLinkWeb); + changeBtnColor(3); + // mWeb->load(QUrl("http://192.168.1.10")); + ui->stackedWidget->setCurrentWidget(lLinkWeb); } // 自组网 void MainWindow::toolButton_4_clicked() { - changeBtnColor(4); - // mWeb->load(QUrl("http://192.168.1.10")); - // mWeb->show(); - ui->stackedWidget->setCurrentWidget(adHocNetworkWeb); + changeBtnColor(4); + // mWeb->load(QUrl("http://192.168.1.10")); + // mWeb->show(); + ui->stackedWidget->setCurrentWidget(adHocNetworkWeb); } // PDT集群 void MainWindow::toolButton_5_clicked() { - changeBtnColor(5); + changeBtnColor(5); - QString pdtDirPath = QCoreApplication::applicationDirPath() + "/NMC7.0"; - QString exePath = pdtDirPath + "/NMC.exe"; - // qDebug() << "*********PDT Path:" << pdtDirPath; - processPDT->setWorkingDirectory(pdtDirPath); // 设置工作目录 - processPDT->start(exePath); // + QString pdtDirPath = QCoreApplication::applicationDirPath() + "/NMC7.0"; + QString exePath = pdtDirPath + "/NMC.exe"; + // qDebug() << "*********PDT Path:" << pdtDirPath; + processPDT->setWorkingDirectory(pdtDirPath); // 设置工作目录 + processPDT->start(exePath); // } // Ku卫通 void MainWindow::toolButton_6_clicked() { - changeBtnColor(6); - ui->stackedWidget->setCurrentWidget(satelliteCommWeb); + changeBtnColor(6); + ui->stackedWidget->setCurrentWidget(satelliteCommWeb); } // 搜救载荷 void MainWindow::toolButton_7_clicked() { - changeBtnColor(7); - ui->stackedWidget->setCurrentWidget(m_rescueLoadWidget); + changeBtnColor(7); + ui->stackedWidget->setCurrentWidget(m_rescueLoadWidget); } // 三维建模 void MainWindow::toolButton_8_clicked() { - changeBtnColor(8); - ui->stackedWidget->setCurrentWidget(m_ModelCameraDlg); + changeBtnColor(8); + ui->stackedWidget->setCurrentWidget(m_ModelCameraDlg); } // 时代飞鹏 void MainWindow::toolButton_9_clicked() { - changeBtnColor(9); - ui->stackedWidget->setCurrentWidget(m_SDFPDlg); + changeBtnColor(9); + ui->stackedWidget->setCurrentWidget(m_SDFPDlg); } // 更新主界面按钮颜色 void MainWindow::changeBtnColor(int num) { - initButton(); - switch (num) { - case 1: - ui->toolButton->setStyleSheet(g_ToolBtnSelStyle); - break; - case 2: - ui->toolButton_2->setStyleSheet(g_ToolBtnSelStyle); - break; - case 3: - ui->toolButton_3->setStyleSheet(g_ToolBtnSelStyle); - break; - case 4: - ui->toolButton_4->setStyleSheet(g_ToolBtnSelStyle); - break; - case 5: - ui->toolButton_5->setStyleSheet(g_ToolBtnSelStyle); - break; - case 6: - ui->toolButton_6->setStyleSheet(g_ToolBtnSelStyle); - break; - case 7: - ui->toolButton_7->setStyleSheet(g_ToolBtnSelStyle); - break; - case 8: - ui->toolButton_8->setStyleSheet(g_ToolBtnSelStyle); - break; - case 9: - ui->toolButton_9->setStyleSheet(g_ToolBtnSelStyle); - break; - } + initButton(); + switch (num) { + case 1: + ui->toolButton->setStyleSheet(g_ToolBtnSelStyle); + break; + case 2: + ui->toolButton_2->setStyleSheet(g_ToolBtnSelStyle); + break; + case 3: + ui->toolButton_3->setStyleSheet(g_ToolBtnSelStyle); + break; + case 4: + ui->toolButton_4->setStyleSheet(g_ToolBtnSelStyle); + break; + case 5: + ui->toolButton_5->setStyleSheet(g_ToolBtnSelStyle); + break; + case 6: + ui->toolButton_6->setStyleSheet(g_ToolBtnSelStyle); + break; + case 7: + ui->toolButton_7->setStyleSheet(g_ToolBtnSelStyle); + break; + case 8: + ui->toolButton_8->setStyleSheet(g_ToolBtnSelStyle); + break; + case 9: + ui->toolButton_9->setStyleSheet(g_ToolBtnSelStyle); + break; + } } /** * @brief 初始化UAVID与推流APPName的映射关系 */ void MainWindow::initUAVIDMap() { - g_mapAppName[5] = "nmyj"; - g_mapAppName[7] = "nmyj"; - for (int i = 8; i < 13; ++i) { - g_mapAppName[i] = "jsyj"; - } - g_mapAppName[99] = "testyj"; + g_mapAppName[5] = "nmyj"; + g_mapAppName[7] = "nmyj"; + for (int i = 8; i < 13; ++i) { + g_mapAppName[i] = "jsyj"; + } + g_mapAppName[99] = "testyj"; +} + +void MainWindow::initNotifyManager() { + g_notifyManager = new NotifyManager(this, this); + g_notifyManager->setMaxCount(5); + g_notifyManager->setDisplayTime(2000); + g_notifyManager->setNotifyWndSize(300, 60); } diff --git a/mainwindow.h b/mainwindow.h index e5abac1..c8d6a9b 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -1,11 +1,6 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include "SDFPDlg.h" -#include "Src/GDDC/gddcdlg.h" -#include "Src/HomePage/homepagedlg.h" -#include "Src/ModelCamera/modelcameradlg.h" -#include "Src/RescueLoad/rescueloadwidget.h" #include #include #include @@ -18,6 +13,12 @@ #include #include +#include "SDFPDlg.h" +#include "Src/GDDC/gddcdlg.h" +#include "Src/HomePage/homepagedlg.h" +#include "Src/ModelCamera/modelcameradlg.h" +#include "Src/RescueLoad/rescueloadwidget.h" + #ifdef Q_OS_WIN // #include // #include @@ -30,55 +31,57 @@ class MainWindow; QT_END_NAMESPACE class MainWindow : public QMainWindow { - Q_OBJECT + Q_OBJECT public: - MainWindow(QWidget *parent = nullptr); - ~MainWindow(); + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); private: - Ui::MainWindow *ui; + Ui::MainWindow *ui; - void initFile(); + void initFile(); public: - void initWindow(); - void initButton(); - void initSignalSlot(); + void initWindow(); + void initButton(); + void initSignalSlot(); private slots: - void toolButton_clicked(); - void toolButton_2_clicked(); - void toolButton_3_clicked(); - void toolButton_4_clicked(); - void toolButton_5_clicked(); - void toolButton_6_clicked(); - void toolButton_7_clicked(); - void toolButton_8_clicked(); - void toolButton_9_clicked(); + void toolButton_clicked(); + void toolButton_2_clicked(); + void toolButton_3_clicked(); + void toolButton_4_clicked(); + void toolButton_5_clicked(); + void toolButton_6_clicked(); + void toolButton_7_clicked(); + void toolButton_8_clicked(); + void toolButton_9_clicked(); public: - GDDCdlg *m_GDDCdlg; - HomePageDlg *m_HomePagedlg; - RescueLoadWidget *m_rescueLoadWidget; - SDFPDlg *m_SDFPDlg; - // QWeb *m_qWeb; - // QWebEngineView *mWeb; - ModelCameraDlg *m_ModelCameraDlg; - QWebEngineView *lLinkWeb; // L链 - QWebEngineView *adHocNetworkWeb; // 自组网 - QWebEngineView *satelliteCommWeb; // 卫通 + GDDCdlg *m_GDDCdlg; + HomePageDlg *m_HomePagedlg; + RescueLoadWidget *m_rescueLoadWidget; + SDFPDlg *m_SDFPDlg; + // QWeb *m_qWeb; + // QWebEngineView *mWeb; + ModelCameraDlg *m_ModelCameraDlg; + QWebEngineView *lLinkWeb; // L链 + QWebEngineView *adHocNetworkWeb; // 自组网 + QWebEngineView *satelliteCommWeb; // 卫通 private: - QProcess *processPDT; - QString exeDirPathName = ""; - std::unordered_map m_allSetMap; + QProcess *processPDT; + QString exeDirPathName = ""; + std::unordered_map m_allSetMap; public: - void changeBtnColor(int num); + void changeBtnColor(int num); private: - /** - * @brief 初始化UAVID与推流APPName的映射关系 - */ - void initUAVIDMap(); + /** + * @brief 初始化UAVID与推流APPName的映射关系 + */ + void initUAVIDMap(); + + void initNotifyManager(); }; -#endif // MAINWINDOW_H +#endif // MAINWINDOW_H