From a0b3e484f53f108bd47602ac7658afccabb48e61 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Tue, 29 Jul 2025 16:15:27 -0400 Subject: [PATCH] Send thumbnails when uploading videos NeoChat will now generate thumbnails from the first frame of the video, since we are loading it anyway. This makes the experience of exchanging videos in NeoChat much nicer! --- src/libneochat/neochatroom.cpp | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/libneochat/neochatroom.cpp b/src/libneochat/neochatroom.cpp index 8a857f3ad..9f5b962a5 100644 --- a/src/libneochat/neochatroom.cpp +++ b/src/libneochat/neochatroom.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -245,11 +247,37 @@ QCoro::Task NeoChatRoom::doUploadFile(QUrl url, QString body, std::optiona } else if (mime.name().startsWith("audio/"_L1)) { content = new EventContent::AudioContent(url, fileInfo.size(), mime, fileInfo.fileName()); } else if (mime.name().startsWith("video/"_L1)) { + QVideoSink sink; + QMediaPlayer player; player.setSource(url); + player.setVideoSink(&sink); co_await qCoro(&player, &QMediaPlayer::mediaStatusChanged); - auto resolution = player.metaData().value(QMediaMetaData::Resolution).toSize(); + + // Get the first video frame to use as a thumbnail. + player.play(); + co_await qCoro(&player, &QMediaPlayer::positionChanged); + + QTemporaryFile file; + file.setFileTemplate(QStringLiteral("XXXXXX.jpg")); + file.open(); + + const auto thumbnailImage = sink.videoFrame().toImage(); + Q_UNUSED(thumbnailImage.save(file.fileName())) + player.stop(); // We have to delay the stop() because it will invalidate our image + + const auto thumbnailFileInfo = QFileInfo(file.fileName()); + + // Upload the thumbnail + const auto job = connection()->uploadFile(thumbnailFileInfo.absoluteFilePath()); + co_await qCoro(job.get(), &BaseJob::finished); + + const auto resolution = player.metaData().value(QMediaMetaData::Resolution).toSize(); content = new EventContent::VideoContent(url, fileInfo.size(), mime, resolution, fileInfo.fileName()); + content->thumbnail = EventContent::Thumbnail(job->contentUri(), + thumbnailFileInfo.size(), + QMimeDatabase().mimeTypeForName(QStringLiteral("image/jpeg")), + thumbnailImage.size()); } else { content = new EventContent::FileContent(url, fileInfo.size(), mime, fileInfo.fileName()); }