chatgui: воспроизведение видео — FFmpeg-плеер + frameless окно
- videoplayer_engine: декод в worker-потоке (FFmpeg), A/V sync по аудио-курсору, seek с epoch-защитой от устаревших кадров - videoplayer_window: окно без рамки, drag-перенос, dblclick/Alt+Enter fullscreen, Esc закрытие, timeline + play/pause/close, авто-скрытие контролов - видео-баббл в списке: превью-кадр (jpg), play-оверлей, длительность, прогресс - превью извлекается после скачивания (video_extract_thumbnail) в фоне - mainwindow: синглтон-плеер, openVideoRequested → openVideo - CMake: HAVE_FFMPEG для vibechat
This commit is contained in:
1 parent
e264b8aaa7
commit
6542618927
11 files changed
+1168
-1
No files matched your search
@@ -24,12 +24,14 @@
|
||||
#include <QFile>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
static std::vector<std::unique_ptr<LottieIcon>> s_icons;
|
||||
|
||||
extern "C" {
|
||||
#include "../transport/gui_bridge.h"
|
||||
#include "chat/chat_core.h"
|
||||
#include "video/video.h"
|
||||
#include "../../lib/u_async.h"
|
||||
#include "../../lib/mem.h"
|
||||
#include "../../lib/debug_config.h"
|
||||
@@ -195,6 +197,42 @@ static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
|
||||
}
|
||||
item->setData(dlState, MsgFileDownloadStateRole);
|
||||
}
|
||||
if (ct == "video/mp4") {
|
||||
QString raw = QString::fromUtf8(body);
|
||||
int pipePos = raw.indexOf('|');
|
||||
QString fname = (pipePos > 0) ? raw.left(pipePos) : raw;
|
||||
item->setData(fname, MsgFileDisplayNameRole);
|
||||
|
||||
if (pipePos > 0) {
|
||||
QString meta = raw.mid(pipePos + 1);
|
||||
QStringList parts = meta.split('|');
|
||||
if (parts.size() >= 1)
|
||||
item->setData(parts[0].toULongLong(), MsgFileSizeRole);
|
||||
if (parts.size() >= 3)
|
||||
item->setData(parts[2].toUInt(), MsgMediaNumBlocksRole);
|
||||
/* dur/w/h в хвосте: |dur=<ms>|w=<w>|h=<h> */
|
||||
for (const QString& p : parts) {
|
||||
if (p.startsWith("dur=")) {
|
||||
qint64 durMs = p.mid(4).toLongLong();
|
||||
if (durMs > 0) {
|
||||
QString d = QString::number(durMs / 1000.0, 'f', 0) + "s";
|
||||
item->setData(d, MsgVoiceDurationRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject la = QJsonDocument::fromJson(localAttrs).object();
|
||||
QString st = la.value("st").toString();
|
||||
QString fp = la.value("fp").toString();
|
||||
int dlState = 0;
|
||||
if (st == "fl" && !fp.isEmpty()) {
|
||||
dlState = 2;
|
||||
QString fullPath = mediaDirBase + "/" + channelId + "/" + fp;
|
||||
item->setData(fullPath, MsgVoiceFileRole);
|
||||
}
|
||||
item->setData(dlState, MsgFileDownloadStateRole);
|
||||
}
|
||||
}
|
||||
|
||||
static void setMsg(QStandardItem *item,
|
||||
@@ -230,7 +268,11 @@ MessageList::MessageList(DbManager* db, AudioRecorder* recorder, QWidget *parent
|
||||
layout->setSpacing(0);
|
||||
|
||||
m_view->setModel(m_model);
|
||||
m_view->setItemDelegate(new MessageDelegate(this));
|
||||
auto* msgDelegate = new MessageDelegate(this);
|
||||
msgDelegate->setVideoOpenCallback([this](const QString& path) {
|
||||
emit openVideoRequested(path);
|
||||
});
|
||||
m_view->setItemDelegate(msgDelegate);
|
||||
m_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_view->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
@@ -702,4 +744,19 @@ 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)) {
|
||||
std::thread([this, 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);
|
||||
QMetaObject::invokeMethod(this, [this]() { m_view->viewport()->update(); },
|
||||
Qt::QueuedConnection);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user