diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 6884af1c26..7f61a97167 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -1621,11 +1621,14 @@ void DocumentData::collectLocalData(not_null local) { } _owner->cache().copyIfEmpty(local->cacheKey(), cacheKey()); - const auto localMedia = local->activeMediaView(); - if (!localMedia->bytes().isEmpty()) { - if (const auto media = activeMediaView()) { - media->setBytes(localMedia->bytes()); - } + if (const auto localMedia = local->activeMediaView()) { + const auto media = createMediaView(); + media->collectLocalData(localMedia.get()); + + // Keep DocumentMedia alive for some more time. + // NB! This allows DocumentMedia to outlive Main::Session! + // In case this is a problem this code should be rewritten. + crl::on_main(&session(), [media] {}); } if (!local->_location.inMediaCache() && !local->_location.isEmpty()) { _location = local->_location; diff --git a/Telegram/SourceFiles/data/data_document_media.cpp b/Telegram/SourceFiles/data/data_document_media.cpp index d31aa607b0..61dd9a06d6 100644 --- a/Telegram/SourceFiles/data/data_document_media.cpp +++ b/Telegram/SourceFiles/data/data_document_media.cpp @@ -139,6 +139,9 @@ DocumentMedia::DocumentMedia(not_null owner) : _owner(owner) { } +// NB! Right now DocumentMedia can outlive Main::Session! +// In DocumentData::collectLocalData a shared_ptr is sent on_main. +// In case this is a problem the ~Gif code should be rewritten. DocumentMedia::~DocumentMedia() = default; not_null DocumentMedia::owner() const { @@ -291,6 +294,28 @@ void DocumentMedia::automaticLoad( true); } +void DocumentMedia::collectLocalData(not_null local) { + if (const auto image = local->_goodThumbnail.get()) { + _goodThumbnail = std::make_unique( + std::make_unique(image->original(), "PNG")); + } + if (const auto image = local->_inlineThumbnail.get()) { + _inlineThumbnail = std::make_unique( + std::make_unique(image->original(), "PNG")); + } + if (const auto image = local->_thumbnail.get()) { + _thumbnail = std::make_unique( + std::make_unique(image->original(), "PNG")); + } + if (const auto image = local->_sticker.get()) { + _sticker = std::make_unique( + std::make_unique(image->original(), "PNG")); + } + _bytes = local->_bytes; + _videoThumbnailBytes = local->_videoThumbnailBytes; + _flags = local->_flags; +} + void DocumentMedia::setBytes(const QByteArray &bytes) { if (!bytes.isEmpty()) { _bytes = bytes; diff --git a/Telegram/SourceFiles/data/data_document_media.h b/Telegram/SourceFiles/data/data_document_media.h index 4682fba6b5..1fd8af8cec 100644 --- a/Telegram/SourceFiles/data/data_document_media.h +++ b/Telegram/SourceFiles/data/data_document_media.h @@ -76,6 +76,8 @@ public: void automaticLoad(Data::FileOrigin origin, const HistoryItem *item); + void collectLocalData(not_null local); + // For DocumentData. static void CheckGoodThumbnail(not_null document); @@ -93,6 +95,9 @@ private: [[nodiscard]] bool thumbnailEnoughForSticker() const; + // NB! Right now DocumentMedia can outlive Main::Session! + // In DocumentData::collectLocalData a shared_ptr is sent on_main. + // In case this is a problem the ~Gif code should be rewritten. const not_null _owner; std::unique_ptr _goodThumbnail; mutable std::unique_ptr _inlineThumbnail; diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index b8a4e6e102..7084be9f92 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -85,7 +85,14 @@ Gif::Gif( setStatusSize(FileStatusSizeReady); refreshCaption(); - _data->loadThumbnail(realParent->fullId()); + if ((_dataMedia = _data->activeMediaView())) { + dataMediaCreated(); + } else { + _data->loadThumbnail(realParent->fullId()); + if (!autoplayEnabled()) { + _data->loadVideoThumbnail(realParent->fullId()); + } + } } Gif::~Gif() { @@ -427,7 +434,10 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms } } else { _data->loadThumbnail(_realParent->fullId()); - if (const auto blurred = _dataMedia->thumbnailInline()) { + validateVideoThumbnail(); + if (_videoThumbnailFrame) { + p.drawPixmap(rthumb.topLeft(), _videoThumbnailFrame->pixSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); + } else if (const auto blurred = _dataMedia->thumbnailInline()) { p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); } else if (!isRound) { const auto roundTop = (roundCorners & RectPart::TopLeft); @@ -632,6 +642,20 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms } } +void Gif::validateVideoThumbnail() const { + const auto content = _dataMedia->videoThumbnailContent(); + if (_videoThumbnailFrame || content.isEmpty()) { + return; + } + auto info = ::Media::Clip::PrepareForSending(QString(), content); + _videoThumbnailFrame = std::make_unique( + std::make_unique( + (info.thumbnail.isNull() + ? Image::BlankMedia()->original() + : info.thumbnail), + "PNG")); +} + void Gif::drawCornerStatus(Painter &p, bool selected, QPoint position) const { if (!needCornerStatusDisplay()) { return; @@ -1086,8 +1110,17 @@ void Gif::ensureDataMediaCreated() const { return; } _dataMedia = _data->createMediaView(); + dataMediaCreated(); +} + +void Gif::dataMediaCreated() const { + Expects(_dataMedia != nullptr); + _dataMedia->goodThumbnailWanted(); _dataMedia->thumbnailWanted(_realParent->fullId()); + if (!autoplayEnabled()) { + _dataMedia->videoThumbnailWanted(_realParent->fullId()); + } history()->owner().registerHeavyViewPart(_parent); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index 44a9b69f5a..d71b9941bd 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -112,11 +112,14 @@ public: private: struct Streamed; + void validateVideoThumbnail() const; + float64 dataProgress() const override; bool dataFinished() const override; bool dataLoaded() const override; void ensureDataMediaCreated() const; + void dataMediaCreated() const; void refreshCaption(); [[nodiscard]] bool autoplayEnabled() const; @@ -171,6 +174,7 @@ private: Ui::Text::String _caption; std::unique_ptr _streamed; mutable std::shared_ptr _dataMedia; + mutable std::unique_ptr _videoThumbnailFrame; QString _downloadSize;