新增大窗口播放视频按键,窗口大小根据解码视频分辨率自动调整,关掉大窗口回到原来位置播放视频
This commit is contained in:
parent
4bd2d7eab5
commit
9a49eab4af
|
@ -4,6 +4,7 @@
|
|||
FFmpegDecoder::FFmpegDecoder(QObject* parent) :
|
||||
QThread(parent),
|
||||
videoLabel(nullptr),
|
||||
resolutionEdit(nullptr),
|
||||
abort(false),
|
||||
restart(false),
|
||||
formatContext(nullptr),
|
||||
|
@ -33,32 +34,49 @@ FFmpegDecoder::~FFmpegDecoder()
|
|||
|
||||
void FFmpegDecoder::processVideo(int itemIndex)
|
||||
{
|
||||
#if 1
|
||||
int width = 720;
|
||||
int height = 1280;
|
||||
#elif 1
|
||||
int width = 640;
|
||||
int height = 480;
|
||||
#else
|
||||
int width = 480;
|
||||
int height = 640;
|
||||
#endif
|
||||
QLabel* originalLabel = this->videoLabel;
|
||||
if ((FocusWindowWidth != 0) && (FocusWindowHeight != 0)) {
|
||||
qDebug() << "------ processVideo";
|
||||
if (width * 16 == height * 9) {
|
||||
FocusWindowDialog* dialog = new FocusWindowDialog(nullptr, QSize(540, 960));
|
||||
dialog->exec();
|
||||
FocusWindowDialog* dialog = nullptr;
|
||||
if (FocusWindowWidth * 16 == FocusWindowHeight * 9) {
|
||||
dialog = new FocusWindowDialog(nullptr, QSize(540, 960));
|
||||
}
|
||||
else if (width * 9 == height * 16) {
|
||||
FocusWindowDialog* dialog = new FocusWindowDialog(nullptr, QSize(960, 540));
|
||||
dialog->exec();
|
||||
else if (FocusWindowWidth * 9 == FocusWindowHeight * 16) {
|
||||
dialog = new FocusWindowDialog(nullptr, QSize(960, 540));
|
||||
}
|
||||
else if (width * 4 == height * 3) {
|
||||
FocusWindowDialog* dialog = new FocusWindowDialog(nullptr, QSize(480, 640));
|
||||
dialog->exec();
|
||||
else if (FocusWindowWidth * 4 == FocusWindowHeight * 3) {
|
||||
dialog = new FocusWindowDialog(nullptr, QSize(480, 640));
|
||||
}
|
||||
else if (width * 3 == height * 4) {
|
||||
FocusWindowDialog* dialog = new FocusWindowDialog(nullptr, QSize(640, 480));
|
||||
dialog->exec();
|
||||
else if (FocusWindowWidth * 3 == FocusWindowHeight * 4) {
|
||||
dialog = new FocusWindowDialog(nullptr, QSize(640, 480));
|
||||
}
|
||||
else {
|
||||
qDebug() << "------ Other scaled resolutions use 480x640";
|
||||
dialog = new FocusWindowDialog(nullptr, QSize(480, 640));
|
||||
}
|
||||
#if 0
|
||||
// 将视频显示的 QLabel 切换为对话框内的 videoDisplayLabel
|
||||
this->videoLabel = dialog->videoDisplayLabel;
|
||||
if ((dialog->exec() == QDialog::Accepted) || (dialog->exec() == QDialog::Rejected)) {
|
||||
this->videoLabel = originalLabel;
|
||||
}
|
||||
#else
|
||||
mutex.lock();
|
||||
this->videoLabelTemp = dialog->videoDisplayLabel; // 更新临时标签
|
||||
this->videoLabelChanged = true; // 设置标志位,表示标签已更改
|
||||
mutex.unlock();
|
||||
|
||||
if ((dialog->exec() == QDialog::Accepted) || (dialog->exec() == QDialog::Rejected)) {
|
||||
mutex.lock();
|
||||
this->videoLabelTemp = originalLabel; // 还原回原始标签
|
||||
this->videoLabelChanged = true; // 设置标志位
|
||||
mutex.unlock();
|
||||
}
|
||||
#endif
|
||||
delete dialog;
|
||||
}
|
||||
else {
|
||||
qDebug() << "------ Please wait for the video to be decoded and rendered before clicking";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +112,7 @@ void FFmpegDecoder::run()
|
|||
{
|
||||
QFile file(filePath);
|
||||
qint64 fileSize = 0;
|
||||
|
||||
QLabel* currentVideoLabel = videoLabel;
|
||||
while (!isInterruptionRequested()) {
|
||||
mutex.lock();
|
||||
while (!restart && !abort) {
|
||||
|
@ -105,7 +123,7 @@ void FFmpegDecoder::run()
|
|||
qDebug() << "Decoder thread aborting";
|
||||
break;
|
||||
}
|
||||
QLabel* currentVideoLabel = videoLabel;
|
||||
/*QLabel* currentVideoLabel = videoLabel;*/
|
||||
QSize labelSize = currentVideoLabel->size();
|
||||
mutex.unlock();
|
||||
|
||||
|
@ -153,9 +171,18 @@ void FFmpegDecoder::run()
|
|||
qWarning() << "Error during decoding";
|
||||
break;
|
||||
}
|
||||
mutex.lock();
|
||||
if (videoLabelChanged) {
|
||||
currentVideoLabel = videoLabelTemp; // 更新 currentVideoLabel
|
||||
videoLabelChanged = false; // 重置标志位
|
||||
labelSize = currentVideoLabel->size();
|
||||
}
|
||||
mutex.unlock();
|
||||
|
||||
QImage img = avFrameToQImage(frame);
|
||||
QImage scaledImage = img.scaled(labelSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
currentVideoLabel->setPixmap(QPixmap::fromImage(scaledImage));
|
||||
//currentVideoLabel->setPixmap(QPixmap::fromImage(scaledImage));
|
||||
QMetaObject::invokeMethod(currentVideoLabel, "setPixmap", Qt::QueuedConnection, Q_ARG(QPixmap, QPixmap::fromImage(scaledImage)));
|
||||
QThread::msleep(10); // Simulate 25 FPS frame rate
|
||||
}
|
||||
}
|
||||
|
@ -266,12 +293,18 @@ QImage FFmpegDecoder::avFrameToQImage(AVFrame* frame)
|
|||
{
|
||||
int width = frame->width;
|
||||
int height = frame->height;
|
||||
// 这里注意切换镜头后是否改变分辨率去改变 isGotResolution
|
||||
if (!isGotResolution && (width != 0) && (height != 0)) {
|
||||
isGotResolution = true;
|
||||
FocusWindowWidth = width;
|
||||
FocusWindowHeight = height;
|
||||
}
|
||||
QString resolutionText = QString::number(width) + " x " + QString::number(height);
|
||||
resolutionEdit->setText(resolutionText);
|
||||
//resolutionEdit->setText(resolutionText);
|
||||
QMetaObject::invokeMethod(resolutionEdit, "setText", Qt::QueuedConnection, Q_ARG(QString, resolutionText));
|
||||
//qDebug() << "H264 video resolution: Width =" << frame->width << ", Height =" << frame->height;
|
||||
|
||||
AVPixelFormat pixFmt = (AVPixelFormat)frame->format;
|
||||
|
||||
if (!swsContext) {
|
||||
swsContext = sws_getContext(width, height, pixFmt, width, height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||
if (!swsContext) {
|
||||
|
|
|
@ -56,9 +56,12 @@ private:
|
|||
QWaitCondition condition;
|
||||
QString filePath;
|
||||
QLabel* videoLabel;
|
||||
QLabel* videoLabelTemp; // 临时存储新标签
|
||||
QLineEdit* resolutionEdit;
|
||||
bool videoLabelChanged = false;
|
||||
bool abort;
|
||||
bool restart;
|
||||
bool isGotResolution = false;
|
||||
|
||||
AVFormatContext* formatContext;
|
||||
AVCodecContext* codecContext;
|
||||
|
@ -66,9 +69,10 @@ private:
|
|||
AVPacket* packet;
|
||||
SwsContext* swsContext;
|
||||
int videoStreamIndex;
|
||||
int FocusWindowWidth = 0;
|
||||
int FocusWindowHeight = 0;
|
||||
|
||||
RingBuffer* ringBuffer;
|
||||
//QLabel* singleFrameLabel; // 用于解码单帧的标签
|
||||
};
|
||||
|
||||
#endif // FFMPEGDECODER_H
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// FocusWindow.h
|
||||
#include <QDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
|
@ -8,12 +9,13 @@ class FocusWindowDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QLabel* videoDisplayLabel;
|
||||
FocusWindowDialog(QWidget* parent = nullptr, const QSize& labelSize = QSize(480, 640)) : QDialog(parent)
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
QLabel* label = new QLabel("1111 This is a new window opened by clicking the new button.", this);
|
||||
label->setFixedSize(labelSize); // 设置QLabel的固定大小
|
||||
layout->addWidget(label);
|
||||
videoDisplayLabel = new QLabel(this);
|
||||
videoDisplayLabel->setFixedSize(labelSize); // 设置QLabel的固定大小
|
||||
layout->addWidget(videoDisplayLabel);
|
||||
|
||||
QPushButton* closeButton = new QPushButton("Close", this);
|
||||
layout->addWidget(closeButton);
|
||||
|
|
|
@ -45,14 +45,10 @@ ClientHandler::ClientHandler(QJsonArray frontBoardOneClickTest, QJsonArray front
|
|||
void ClientHandler::initialize(QTcpSocket* socket)
|
||||
{
|
||||
this->socket = socket;
|
||||
|
||||
// 连接信号槽,将其放在同一线程中处理
|
||||
connect(socket, &QTcpSocket::readyRead, this, &ClientHandler::onDataReceived);
|
||||
connect(socket, &QTcpSocket::disconnected, this, &ClientHandler::onDisconnected);
|
||||
|
||||
// 其他的 socket 操作都将在这个线程中进行
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ClientHandler::~ClientHandler()
|
||||
|
|
|
@ -118,6 +118,7 @@ signals:
|
|||
void startReadTimer(int client_Id);
|
||||
void stopReadTimer(int client_Id);
|
||||
void sendDataToSomeClient(int client_Id, const QByteArray& data);
|
||||
void openFocusWindowRequested(int itemIndex);
|
||||
|
||||
public slots:
|
||||
#if !TEST_TCP_MOVE_TO_MAIN
|
||||
|
|
|
@ -21,7 +21,6 @@ DataHandler::DataHandler(QLabel* videoLabel, QLineEdit* VideoResolutionEdit, QSi
|
|||
backBoardUuidJson(backBoardUuidJson), getPicJson(getPicJson), getVideoJson(getVideoJson),
|
||||
buffer(new QByteArray()), picBuffer(new QByteArray()),
|
||||
ffmpegDecoder(new FFmpegDecoder()) // 初始化FFmpeg解码器
|
||||
|
||||
{
|
||||
ffmpegDecoder->initialize(); // 初始化解码器
|
||||
clearAllRecvData();
|
||||
|
@ -46,7 +45,6 @@ DataHandler::~DataHandler()
|
|||
void DataHandler::handleOpenFocusWindow(int itemIndex)
|
||||
{
|
||||
if (ffmpegDecoder) {
|
||||
qDebug() << "------- handleOpenFocusWindow";
|
||||
ffmpegDecoder->processVideo(itemIndex); // 调用 FFmpegDecoder 的处理函数
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +75,6 @@ void DataHandler::showVideo(const QString& client, const QByteArray& valData)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valData.isEmpty()) {
|
||||
file.write(valData);
|
||||
file.flush(); // 刷新文件缓冲区
|
||||
|
@ -112,8 +109,8 @@ void DataHandler::clearAllRecvData() {
|
|||
|
||||
// 处理接收到的数据
|
||||
void DataHandler::handleData(const QString& client, const QByteArray& recvData, int msg_id,
|
||||
int currentRecvItemIndex, int currentRecvFuncItemIndex,
|
||||
const QString& itemData, const QString& funcItemData, const QJsonArray& jsonArray, int itemJsonIndex)
|
||||
int currentRecvItemIndex, int currentRecvFuncItemIndex, const QString& itemData,
|
||||
const QString& funcItemData, const QJsonArray& jsonArray, int itemJsonIndex)
|
||||
{
|
||||
//qDebug() << "Data received from" << client << ":" << recvData;
|
||||
#if 0
|
||||
|
@ -158,10 +155,8 @@ void DataHandler::handleData(const QString& client, const QByteArray& recvData,
|
|||
//QByteArray data = buffer->mid(10, dataSize);
|
||||
QString hexString = QString::fromUtf8(data.toHex().data());
|
||||
QByteArray actual_data = hexStringToByteArray(hexString);
|
||||
//qDebug() << "---Received hexString:" << hexString;
|
||||
buffer->remove(0, totalSize); // 移除已处理的数据
|
||||
if(msg_id != 0x0040 && msg_id != START_VIDEO && msg_id != GET_IMG) {
|
||||
//if (msg_id != 0x0040) {
|
||||
qDebug() << "--- msg_id:" << msg_id;
|
||||
qDebug() << "--- clientLastMsgId.value(client, 0):" << clientLastMsgId.value(client, 0);
|
||||
// 同一个client仅当 msg_id 不连续为 0x11/0x21 或第一次处理时才执行 emit statusUpdated
|
||||
|
@ -186,7 +181,6 @@ void DataHandler::handleData(const QString& client, const QByteArray& recvData,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void DataHandler::initializeMsgIdToCmdMap() {
|
||||
msgIdToCmdMap[GET_FRONT_V851_VERSION] = "GET_FRONT_V851_VERSION";
|
||||
msgIdToCmdMap[GET_FRONT_MCU_VERSION] = "GET_FRONT_MCU_VERSION";
|
||||
|
|
|
@ -40,12 +40,11 @@ public:
|
|||
QJsonArray backBoardDevInfoJson, QJsonArray backBoardUuidJson,
|
||||
QJsonArray getPicJson, QJsonArray getVideoJson, QObject* parent = nullptr);
|
||||
~DataHandler();
|
||||
|
||||
void handleOpenFocusWindow(int itemIndex);
|
||||
public slots:
|
||||
void handleData(const QString& client, const QByteArray& data, int msg_id, int currentRecvItemIndex,
|
||||
int currentRecvFuncItemIndex, const QString& itemData, const QString& funcItemData,
|
||||
const QJsonArray& jsonArray, int itemJsonIndex);
|
||||
void handleOpenFocusWindow(int itemIndex);
|
||||
signals:
|
||||
void statusUpdated(const QString& clientAddress, int currentItemIndex, int currentFuncItemIndex,
|
||||
bool success, const QString& currentItemLabel, const QString& currentFuncItemLabel,
|
||||
|
|
|
@ -96,26 +96,20 @@ MainWidget::MainWidget(QWidget* parent) :
|
|||
frontBoardDevInfoJson, frontBoardLicenseJson,
|
||||
backBoardOneClickTest, backBoardTest, backBoardFuncConfig, backBoardDevInfoJson,
|
||||
backBoardUuidJson, getPicJson, getVideoJson, clientId, isBackBoardOrAllBoard, nullptr);
|
||||
/*
|
||||
* 一定要先取消父对象,否则报错:QObject::moveToThread: Cannot move objects with a parent
|
||||
* 父对象负责管理子对象的生命周期,如果子对象被移动到其他线程,可能会导致线程安全问题或不一致的对象状态
|
||||
*/
|
||||
// 一定要先取消父对象
|
||||
socket->setParent(nullptr);
|
||||
// 将 socket 移动到新的线程中
|
||||
socket->moveToThread(thread);
|
||||
// 将 socket 传递到 handler
|
||||
handler->initialize(socket);
|
||||
#endif
|
||||
// 将 ClientHandler 移到线程池中的线程
|
||||
handler->moveToThread(thread);
|
||||
|
||||
// 创建 DataHandler 对象并连接信号
|
||||
DataHandler* dataHandler = new DataHandler(videoLabel, VideoResolutionEdit, leftLens_imageLabel->size(), &devInfoLineEdits,
|
||||
frontBoardOneClickTest, frontBoardTest, frontBoardFuncConfig,
|
||||
frontBoardDevInfoJson, frontBoardLicenseJson,
|
||||
backBoardOneClickTest, backBoardTest, backBoardFuncConfig, backBoardDevInfoJson,
|
||||
backBoardUuidJson, getPicJson, getVideoJson, nullptr);
|
||||
// 将 DataHandler 移到线程池中的线程
|
||||
// 将 ClientHandler 和 DataHandler 移到线程池中的线程
|
||||
handler->moveToThread(thread);
|
||||
dataHandler->moveToThread(thread);
|
||||
#if TEST_TCP_MOVE_TO_MAIN
|
||||
// 将sendData信号连接到主线程中的槽上
|
||||
|
@ -464,7 +458,7 @@ void MainWidget::setupUI()
|
|||
mainLayout->addLayout(rightVerticalLayout, 3);
|
||||
|
||||
setLayout(mainLayout);
|
||||
setWindowTitle("SL100 工厂产测工具 - V0.0.4");
|
||||
setWindowTitle("SL100 工厂产测工具 - V0.0.5");
|
||||
resize(1340, 900);
|
||||
|
||||
connect(startServerButton, &QPushButton::clicked, this, &MainWidget::onStartServerClicked);
|
||||
|
@ -1290,7 +1284,11 @@ void MainWidget::onOpenFocusWindowClicked()
|
|||
if (itemIndex == FOCUS_WINDOWS_BUTTON) {
|
||||
for (ClientHandler* handler : clients) {
|
||||
if (handler->getClientId() == handler->preVideoClientId) {
|
||||
emit openFocusWindowRequested(itemIndex); // 发送信号
|
||||
DataHandler* dataHandler = dataHandlers[handler->getClientId()];
|
||||
if (dataHandler) {
|
||||
dataHandler->handleOpenFocusWindow(itemIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ private:
|
|||
void onDisconnectClient(int clientId);
|
||||
void setupTimerForThreadPoolInfo();
|
||||
void sendDataToClient(int clientId, const QByteArray& data);
|
||||
//void FactoryToolSendPostFactoryInfotoHttpServer();
|
||||
// 与服务器的接口
|
||||
void FactoryToolSendPostTestToHttpServer();
|
||||
void FactoryToolSendPostLicenseToHttpServer(const QString& hardware_info, const QString& license_info);
|
||||
void FactoryToolSendPostComfirmToHttpServer(const QString& mac_addr, const QString& uuid);
|
||||
|
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
File diff suppressed because one or more lines are too long
10
README.md
10
README.md
|
@ -3,17 +3,13 @@
|
|||
遇到问题:
|
||||
2024.09.01
|
||||
1. 运行报错:QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
|
||||
问题分析:主线程创建了 QTcpSocket,这个QTcpSocket的读写操作必须在主线程中执行,不能将QTcpSocket对象
|
||||
通过新建的对象传参后到新建对象中对QTcpSocket进行读写操作,所有的QTcpSocket 的操作都在与它关
|
||||
联的线程中执行。
|
||||
问题分析:主线程创建了 QTcpSocket,这个QTcpSocket的读写操作必须在主线程中执行,不能将QTcpSocket对象通过新建的对象传参后到新建对象中对QTcpSocket进行读写操作,所有的QTcpSocket 的操作都在与它关联的线程中执行。
|
||||
问题解决:1. 在主线程中创建 QTcpSocket 并获取连接:
|
||||
继续在主线程中使用 server->nextPendingConnection() 来获取客户端连接。
|
||||
|
||||
2. 将 QTcpSocket 移动到 ClientHandler 所属的新线程:
|
||||
在将 QTcpSocket 传递给 ClientHandler 之前,将 QTcpSocket 移动到新线程中,确保它在新线程
|
||||
中被使用。
|
||||
这里注意不能将有父对象的QTcpSocket 移动到新线程中,因为父对象负责管理子对象的生命周期,
|
||||
如果子对象被移动到其他线程,可能会导致线程安全问题或不一致的对象状态。
|
||||
在将 QTcpSocket 传递给 ClientHandler 之前,将 QTcpSocket 移动到新线程中,确保它在新线程中被使用。
|
||||
这里注意不能将有父对象的QTcpSocket 移动到新线程中,因为父对象负责管理子对象的生命周期,如果子对象被移动到其他线程,可能会导致线程安全问题或不一致的对象状态。
|
||||
运行报错:QObject::moveToThread: Cannot move objects with a parent
|
||||
解决方法:如果 QTcpSocket 已经有父对象,你需要先将其父对象设置为 nullptr,再移动到新的线程。
|
||||
|
||||
|
|
Loading…
Reference in New Issue