From 203ae61edae89ef93285e46205d5bad03d24b53c Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 1 Oct 2026 19:12:25 +0300 Subject: [PATCH] Share bounded thumbnail workers and keep PM downloads in DM transport --- tools/chatgui/src/inputbar.h | 1 - tools/chatgui/src/messagelist.cpp | 42 ++++++++++++++++++------------- tools/chatgui/src/messagelist.h | 6 ++++- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/tools/chatgui/src/inputbar.h b/tools/chatgui/src/inputbar.h index 61e9c6d3..7abe87a0 100644 --- a/tools/chatgui/src/inputbar.h +++ b/tools/chatgui/src/inputbar.h @@ -67,7 +67,6 @@ private: QPushButton *m_attachClearBtn = nullptr; bool m_pttActive = false; bool m_dmMode = false; - QString m_voiceFilePath; QString m_mediaDirBase; QString m_channelIdForRecord; QString m_recordTarget; diff --git a/tools/chatgui/src/messagelist.cpp b/tools/chatgui/src/messagelist.cpp index 9277a59a..a5e3ab54 100644 --- a/tools/chatgui/src/messagelist.cpp +++ b/tools/chatgui/src/messagelist.cpp @@ -965,23 +965,27 @@ void MessageList::onAttachmentDownloaded(const QString& chId, int64_t msgId) { } } - if (m.contentType == "video/mp4") { - QString fp = item->data(MsgVoiceFileRole).toString(); - QString thumbPath = fp + ".jpg"; - if (!fp.isEmpty() && QFile::exists(fp) && !QFile::exists(thumbPath)) { - QPointer self(this); - std::thread([self, fp, thumbPath]() { - int rc = video_extract_thumbnail(fp.toUtf8().constData(), - thumbPath.toUtf8().constData(), 320); - DEBUG_DEBUG(DEBUG_CATEGORY_VIDEO, "MessageList: thumbnail %s rc=%d", - qPrintable(thumbPath), rc); - if (self) { - QMetaObject::invokeMethod(self, [self]() { self->m_view->viewport()->update(); }, - Qt::QueuedConnection); - } - }).detach(); - } - } + if (m.contentType == "video/mp4") prepareVideoThumbnail(item->data(MsgVoiceFileRole).toString()); +} + +/* Общие превью для каналов/PM; не более двух decoder workers, без запуска из paint. */ +void MessageList::prepareVideoThumbnail(const QString& path) { + if (path.isEmpty() || m_thumbnailJobs.contains(path) || !QFile::exists(path) || QFile::exists(path + ".jpg")) return; + m_thumbnailPool.setMaxThreadCount(2); + m_thumbnailJobs.insert(path); + QPointer self(this); + QObject* dispatcher = QCoreApplication::instance(); + m_thumbnailPool.start([self, dispatcher, path]() { + QString output = path + ".jpg"; + int rc = video_extract_thumbnail(path.toUtf8().constData(), output.toUtf8().constData(), 320); + if (rc) DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "thumbnail failed path=%s error=%d", qPrintable(path), rc); + else DEBUG_DEBUG(DEBUG_CATEGORY_VIDEO, "thumbnail ready path=%s", qPrintable(output)); + QMetaObject::invokeMethod(dispatcher, [self, path]() { + if (!self) return; + self->m_thumbnailJobs.remove(path); + self->m_view->viewport()->update(); + }, Qt::QueuedConnection); + }); } void MessageList::onMessageContextMenu(const QPoint& pos) { @@ -992,6 +996,7 @@ void MessageList::onMessageContextMenu(const QPoint& pos) { bool isVideo = (ct == "video/mp4"); bool isImage = ct.startsWith("image/"); bool isDmFile = isDmChannel(idx.data(MsgChannelIdRole).toString()) && ct == "application/octet-stream"; + bool isDm = isDmChannel(idx.data(MsgChannelIdRole).toString()); if (!isVideo && !isImage && !isDmFile) return; QString filePath = idx.data(MsgVoiceFileRole).toString(); @@ -1002,7 +1007,7 @@ void MessageList::onMessageContextMenu(const QPoint& pos) { QAction* saveAct = menu.addAction(QString::fromUtf8("Сохранить в файл")); saveAct->setEnabled(downloaded); QAction* dlAct = nullptr; - if (!downloaded && !isDmFile) dlAct = menu.addAction(QString::fromUtf8("Скачать")); + if (!downloaded && !isDm) dlAct = menu.addAction(QString::fromUtf8("Скачать")); QAction* chosen = menu.exec(m_view->viewport()->mapToGlobal(pos)); @@ -1137,6 +1142,7 @@ void MessageList::onDmMessages(const uint8_t* data, int len) { item->setData(duration, MsgVideoDurationMsRole); item->setData(message.value("width").toInt(), MsgVideoWidthRole); item->setData(message.value("height").toInt(), MsgVideoHeightRole); + prepareVideoThumbnail(path); } } m_model->appendRow(item); diff --git a/tools/chatgui/src/messagelist.h b/tools/chatgui/src/messagelist.h index 883e5d4b..151f42d4 100644 --- a/tools/chatgui/src/messagelist.h +++ b/tools/chatgui/src/messagelist.h @@ -4,10 +4,11 @@ #include #include #include +#include +#include class ChatView; class InputBar; -class InputBar; class EmojiPanel; class DbManager; class ChannelList; @@ -60,12 +61,15 @@ private: QPushButton* m_radioBtn = nullptr; /* шапка: переключатель рации */ QPushButton* m_pttBtn = nullptr; /* плавающая кнопка PTT поверх чата */ bool m_radioOn = false; + QThreadPool m_thumbnailPool; + QSet m_thumbnailJobs; QString authorName(quint64 nodeId) const; void restoreScrollPosition(const QString& channelId); void updateReadPosition(); void onMessageContextMenu(const QPoint& pos); void requestDmMessages(const QString& channelId); + void prepareVideoThumbnail(const QString& path); void onRadioToggled(bool on); void updateRadioUi(); void layoutPttButton();