From 33f49462422293ccf10232006aa0aa701aa5210b Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 9 Apr 2020 16:27:53 +0400 Subject: [PATCH] Start using document bytes from DocumentMedia. --- Telegram/SourceFiles/app.h | 14 +--- .../SourceFiles/boxes/edit_caption_box.cpp | 3 +- Telegram/SourceFiles/boxes/edit_caption_box.h | 2 + .../SourceFiles/boxes/sticker_set_box.cpp | 2 +- Telegram/SourceFiles/boxes/stickers_box.cpp | 4 +- Telegram/SourceFiles/boxes/stickers_box.h | 4 +- .../chat_helpers/field_autocomplete.cpp | 2 +- .../SourceFiles/chat_helpers/stickers.cpp | 27 ++++---- Telegram/SourceFiles/chat_helpers/stickers.h | 12 ++-- .../chat_helpers/stickers_list_widget.cpp | 6 +- .../SourceFiles/data/data_cloud_themes.cpp | 17 +++-- Telegram/SourceFiles/data/data_cloud_themes.h | 7 +- Telegram/SourceFiles/data/data_document.cpp | 68 +++++++------------ Telegram/SourceFiles/data/data_document.h | 5 +- .../SourceFiles/data/data_document_media.cpp | 25 +++++-- .../SourceFiles/data/data_document_media.h | 6 ++ .../view/media/history_view_document.cpp | 4 +- .../view/media/history_view_sticker.cpp | 4 +- .../inline_bot_layout_internal.cpp | 22 ++++-- .../inline_bots/inline_bot_layout_internal.h | 2 +- .../SourceFiles/media/audio/media_audio.cpp | 49 ++++--------- .../media/clip/media_clip_reader.cpp | 12 +++- .../media/clip/media_clip_reader.h | 6 +- .../media/view/media_view_overlay_widget.cpp | 15 ++-- Telegram/SourceFiles/storage/file_download.h | 5 +- .../SourceFiles/storage/localimageloader.cpp | 2 +- Telegram/SourceFiles/storage/localstorage.cpp | 20 +++--- Telegram/SourceFiles/storage/localstorage.h | 3 +- .../themes/window_themes_cloud_list.cpp | 6 +- .../window/themes/window_themes_cloud_list.h | 1 + .../window/window_media_preview.cpp | 4 +- 31 files changed, 190 insertions(+), 169 deletions(-) diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 5f828d675..6d1543889 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -11,23 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rect_part.h" enum class ImageRoundRadius; -class MainWindow; -class MainWidget; -class HistoryItem; -class History; + namespace HistoryView { class Element; } // namespace HistoryView -namespace Media { -namespace Clip { -class Reader; -} // namespace Clip -} // namespace Media - -using HistoryItemsMap = base::flat_set>; -using GifItems = QHash; - enum RoundCorners : int { SmallMaskCorners = 0x00, // for images LargeMaskCorners, diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.cpp b/Telegram/SourceFiles/boxes/edit_caption_box.cpp index 811cb455d..0d0c863d6 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_caption_box.cpp @@ -315,9 +315,10 @@ void EditCaptionBox::prepareGifPreview(DocumentData* document) { const auto callback = [=](Media::Clip::Notification notification) { clipCallback(notification); }; + _gifMedia = document ? document->createMediaView() : nullptr; if (document && document->isAnimation() && document->loaded()) { _gifPreview = Media::Clip::MakeReader( - document, + _gifMedia.get(), _msgId, callback); } else if (!isListEmpty) { diff --git a/Telegram/SourceFiles/boxes/edit_caption_box.h b/Telegram/SourceFiles/boxes/edit_caption_box.h index d5136afb4..0e7a80b0c 100644 --- a/Telegram/SourceFiles/boxes/edit_caption_box.h +++ b/Telegram/SourceFiles/boxes/edit_caption_box.h @@ -23,6 +23,7 @@ class SessionController; namespace Data { class Media; +class DocumentMedia; } // namespace Data namespace Ui { @@ -94,6 +95,7 @@ private: bool _doc = false; QPixmap _thumb; + std::shared_ptr _gifMedia; Media::Clip::ReaderPointer _gifPreview; object_ptr _field = { nullptr }; diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index 37d63cc65..24036d519 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -604,7 +604,7 @@ void StickerSetBox::Inner::setupLottie(int index) { element.animated = Stickers::LottieAnimationFromDocument( getLottiePlayer(), - document, + element.documentMedia.get(), Stickers::LottieSize::StickerSet, boundingBoxSize() * cIntRetinaFactor()); } diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index 5ffdfc131..69e48c12e 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -642,6 +642,7 @@ StickersBox::Inner::Row::Row( , accessHash(accessHash) , thumbnail(thumbnail) , sticker(sticker) +, stickerMedia(sticker ? sticker->createMediaView() : nullptr) , count(count) , title(title) , titleWidth(titleWidth) @@ -947,7 +948,7 @@ void StickersBox::Inner::validateLottieAnimation(not_null set) { } auto player = Stickers::LottieThumbnail( set->thumbnail, - set->sticker, + set->stickerMedia.get(), Stickers::LottieSize::SetsListThumbnail, QSize( st::contactsPhotoSize, @@ -1645,6 +1646,7 @@ void StickersBox::Inner::updateRows() { } row->thumbnail = thumbnail; row->sticker = sticker; + row->stickerMedia = sticker->createMediaView(); row->pixw = pixw; row->pixh = pixh; } diff --git a/Telegram/SourceFiles/boxes/stickers_box.h b/Telegram/SourceFiles/boxes/stickers_box.h index 3cdd90a18..cdc4af51e 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.h +++ b/Telegram/SourceFiles/boxes/stickers_box.h @@ -233,15 +233,17 @@ private: bool removed, int32 pixw, int32 pixh); + ~Row(); + bool isRecentSet() const { return (id == Stickers::CloudRecentSetId); } - ~Row(); uint64 id = 0; uint64 accessHash = 0; ImagePtr thumbnail; DocumentData *sticker = nullptr; + std::shared_ptr stickerMedia; int32 count = 0; QString title; int titleWidth = 0; diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index d14f92a8f..aa3d29535 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -1008,7 +1008,7 @@ auto FieldAutocompleteInner::getLottieRenderer() void FieldAutocompleteInner::setupLottie(StickerSuggestion &suggestion) { const auto document = suggestion.document; suggestion.animated = Stickers::LottiePlayerFromDocument( - document, + suggestion.documentMedia.get(), Stickers::LottieSize::InlineResults, stickerBoundingBox() * cIntRetinaFactor(), Lottie::Quality::Default, diff --git a/Telegram/SourceFiles/chat_helpers/stickers.cpp b/Telegram/SourceFiles/chat_helpers/stickers.cpp index bfe0d206a..06ef194d6 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "stickers.h" #include "data/data_document.h" +#include "data/data_document_media.h" #include "data/data_session.h" #include "data/data_file_origin.h" #include "boxes/stickers_box.h" @@ -1146,10 +1147,11 @@ auto LottieCachedFromContent( template auto LottieFromDocument( Method &&method, - not_null document, + not_null media, uint8 keyShift, QSize box) { - const auto data = document->data(); + const auto document = media->owner(); + const auto data = media->bytes(); const auto filepath = document->filepath(); if (box.width() * box.height() > kDontCacheLottieAfterArea) { // Don't use frame caching for large stickers. @@ -1172,13 +1174,13 @@ auto LottieFromDocument( } std::unique_ptr LottiePlayerFromDocument( - not_null document, + not_null media, LottieSize sizeTag, QSize box, Lottie::Quality quality, std::shared_ptr renderer) { return LottiePlayerFromDocument( - document, + media, nullptr, sizeTag, box, @@ -1187,7 +1189,7 @@ std::unique_ptr LottiePlayerFromDocument( } std::unique_ptr LottiePlayerFromDocument( - not_null document, + not_null media, const Lottie::ColorReplacements *replacements, LottieSize sizeTag, QSize box, @@ -1202,18 +1204,18 @@ std::unique_ptr LottiePlayerFromDocument( }; const auto tag = replacements ? replacements->tag : uint8(0); const auto keyShift = ((tag << 4) & 0xF0) | (uint8(sizeTag) & 0x0F); - return LottieFromDocument(method, document, uint8(keyShift), box); + return LottieFromDocument(method, media, uint8(keyShift), box); } not_null LottieAnimationFromDocument( not_null player, - not_null document, + not_null media, LottieSize sizeTag, QSize box) { const auto method = [&](auto &&...args) { return player->append(std::forward(args)...); }; - return LottieFromDocument(method, document, uint8(sizeTag), box); + return LottieFromDocument(method, media, uint8(sizeTag), box); } bool HasLottieThumbnail( @@ -1243,19 +1245,20 @@ bool HasLottieThumbnail( std::unique_ptr LottieThumbnail( ImagePtr thumbnail, - not_null sticker, + not_null media, LottieSize sizeTag, QSize box, std::shared_ptr renderer) { + const auto document = media->owner(); const auto baseKey = thumbnail ? thumbnail->location().file().bigFileBaseCacheKey() - : sticker->bigFileBaseCacheKey(); + : document->bigFileBaseCacheKey(); if (!baseKey) { return nullptr; } const auto content = (thumbnail ? thumbnail->bytesForCache() - : Lottie::ReadContent(sticker->data(), sticker->filepath())); + : Lottie::ReadContent(media->bytes(), document->filepath())); if (content.isEmpty()) { return nullptr; } @@ -1267,7 +1270,7 @@ std::unique_ptr LottieThumbnail( method, *baseKey, uint8(sizeTag), - &sticker->session(), + &document->session(), content, box); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers.h b/Telegram/SourceFiles/chat_helpers/stickers.h index 3a4ac0925..d0b8fd03b 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers.h +++ b/Telegram/SourceFiles/chat_helpers/stickers.h @@ -12,6 +12,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class DocumentData; +namespace Data { +class DocumentMedia; +} // namespace Data + namespace Main { class Session; } // namespace Main @@ -136,13 +140,13 @@ enum class LottieSize : uchar { }; [[nodiscard]] std::unique_ptr LottiePlayerFromDocument( - not_null document, + not_null media, LottieSize sizeTag, QSize box, Lottie::Quality quality = Lottie::Quality(), std::shared_ptr renderer = nullptr); [[nodiscard]] std::unique_ptr LottiePlayerFromDocument( - not_null document, + not_null media, const Lottie::ColorReplacements *replacements, LottieSize sizeTag, QSize box, @@ -150,7 +154,7 @@ enum class LottieSize : uchar { std::shared_ptr renderer = nullptr); [[nodiscard]] not_null LottieAnimationFromDocument( not_null player, - not_null document, + not_null media, LottieSize sizeTag, QSize box); @@ -159,7 +163,7 @@ enum class LottieSize : uchar { not_null sticker); [[nodiscard]] std::unique_ptr LottieThumbnail( ImagePtr thumbnail, - not_null sticker, + not_null media, LottieSize sizeTag, QSize box, std::shared_ptr renderer = nullptr); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index bca37ad63..c0ac90ba2 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -67,6 +67,7 @@ struct StickerIcon { : setId(setId) , thumbnail(thumbnail) , sticker(sticker) + , stickerMedia(sticker ? sticker->createMediaView() : nullptr) , pixw(pixw) , pixh(pixh) { } @@ -74,6 +75,7 @@ struct StickerIcon { ImagePtr thumbnail; mutable Lottie::SinglePlayer *lottie = nullptr; DocumentData *sticker = nullptr; + std::shared_ptr stickerMedia; ChannelData *megagroup = nullptr; int pixw = 0; int pixh = 0; @@ -704,7 +706,7 @@ void StickersListWidget::Footer::validateIconLottieAnimation( } auto player = Stickers::LottieThumbnail( icon.thumbnail, - icon.sticker, + icon.stickerMedia.get(), Stickers::LottieSize::StickersFooter, QSize( st::stickerIconWidth - 2 * st::stickerIconPadding, @@ -1692,7 +1694,7 @@ void StickersListWidget::setupLottie(Set &set, int section, int index) { ensureLottiePlayer(set); sticker.animated = Stickers::LottieAnimationFromDocument( set.lottiePlayer, - document, + sticker.documentMedia.get(), Stickers::LottieSize::StickersPanel, boundingBoxSize() * cIntRetinaFactor()); _lottieData[set.id].items.emplace( diff --git a/Telegram/SourceFiles/data/data_cloud_themes.cpp b/Telegram/SourceFiles/data/data_cloud_themes.cpp index 25de1ff0f..106ecb682 100644 --- a/Telegram/SourceFiles/data/data_cloud_themes.cpp +++ b/Telegram/SourceFiles/data/data_cloud_themes.cpp @@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "data/data_document.h" #include "data/data_file_origin.h" +#include "data/data_document_media.h" #include "main/main_session.h" #include "boxes/confirm_box.h" #include "core/application.h" // Core::App().showTheme. @@ -178,9 +179,11 @@ void CloudThemes::showPreview(const CloudTheme &cloud) { void CloudThemes::applyFromDocument(const CloudTheme &cloud) { const auto document = _session->data().document(cloud.documentId); - loadDocumentAndInvoke(_updatingFrom, cloud, document, [=] { + loadDocumentAndInvoke(_updatingFrom, cloud, document, [=]( + std::shared_ptr media) { + const auto document = media->owner(); auto preview = Window::Theme::PreviewFromFile( - document->data(), + media->bytes(), document->location().name(), cloud); if (preview) { @@ -192,7 +195,9 @@ void CloudThemes::applyFromDocument(const CloudTheme &cloud) { void CloudThemes::previewFromDocument(const CloudTheme &cloud) { const auto document = _session->data().document(cloud.documentId); - loadDocumentAndInvoke(_previewFrom, cloud, document, [=] { + loadDocumentAndInvoke(_previewFrom, cloud, document, [=]( + std::shared_ptr media) { + const auto document = media->owner(); Core::App().showTheme(document, cloud); }); } @@ -201,12 +206,13 @@ void CloudThemes::loadDocumentAndInvoke( LoadingDocument &value, const CloudTheme &cloud, not_null document, - Fn callback) { + Fn)> callback) { const auto alreadyWaiting = (value.document != nullptr); if (alreadyWaiting) { value.document->cancel(); } value.document = document; + value.documentMedia = document->createMediaView(); value.document->save( Data::FileOriginTheme(cloud.id, cloud.accessHash), QString()); @@ -228,8 +234,9 @@ void CloudThemes::loadDocumentAndInvoke( void CloudThemes::invokeForLoaded(LoadingDocument &value) { const auto onstack = std::move(value.callback); + auto media = std::move(value.documentMedia); value = LoadingDocument(); - onstack(); + onstack(std::move(media)); } void CloudThemes::scheduleReload() { diff --git a/Telegram/SourceFiles/data/data_cloud_themes.h b/Telegram/SourceFiles/data/data_cloud_themes.h index e9e8aa81b..2e3e2af9f 100644 --- a/Telegram/SourceFiles/data/data_cloud_themes.h +++ b/Telegram/SourceFiles/data/data_cloud_themes.h @@ -17,6 +17,8 @@ class Session; namespace Data { +class DocumentMedia; + struct CloudTheme { uint64 id = 0; uint64 accessHash = 0; @@ -54,8 +56,9 @@ private: struct LoadingDocument { CloudTheme theme; DocumentData *document = nullptr; + std::shared_ptr documentMedia; rpl::lifetime subscription; - Fn callback; + Fn)> callback; }; void parseThemes(const QVector &list); @@ -71,7 +74,7 @@ private: LoadingDocument &value, const CloudTheme &cloud, not_null document, - Fn callback); + Fn)> callback); void invokeForLoaded(LoadingDocument &value); const not_null _session; diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 2e33c18a2..ff6f6ee89 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -587,7 +587,10 @@ void DocumentData::validateLottieSticker() { } void DocumentData::setDataAndCache(const QByteArray &data) { - setData(data); + _data = data; + if (const auto media = activeMediaView()) { + media->setBytes(data); + } if (saveToCache() && data.size() <= Storage::kMaxFileInMemory) { owner().cache().put( cacheKey(), @@ -734,11 +737,12 @@ auto DocumentData::bigFileBaseCacheKey() const } bool DocumentData::saveToCache() const { - return (type == StickerDocument && size < Storage::kMaxStickerInMemory) - || (isAnimation() && size < Storage::kMaxAnimationInMemory) - || (isVoiceMessage() && size < Storage::kMaxVoiceInMemory) - || (type == WallPaperDocument) - || (isTheme() && size < Storage::kMaxFileInMemory); + return (size < Storage::kMaxFileInMemory) + && ((type == StickerDocument) + || isAnimation() + || isVoiceMessage() + || (type == WallPaperDocument) + || isTheme()); } void DocumentData::unload() { @@ -814,6 +818,7 @@ bool DocumentData::loaded(FilePathResolve resolve) const { that->setGoodThumbnailDataReady(); if (const auto media = activeMediaView()) { + media->setBytes(_loader->bytes()); media->checkStickerLarge(_loader.get()); } destroyLoader(); @@ -824,7 +829,7 @@ bool DocumentData::loaded(FilePathResolve resolve) const { } _owner->notifyDocumentLayoutChanged(this); } - return !data().isEmpty() || !filepath(resolve).isEmpty(); + return !rawBytes().isEmpty() || !filepath(resolve).isEmpty(); } void DocumentData::destroyLoader() const { @@ -918,10 +923,10 @@ void DocumentData::save( if (loaded(FilePathResolve::Checked)) { auto &l = location(true); if (!toFile.isEmpty()) { - if (!_data.isEmpty()) { + if (!rawBytes().isEmpty()) { QFile f(toFile); f.open(QIODevice::WriteOnly); - f.write(_data); + f.write(rawBytes()); f.close(); setLocation(FileLocation(toFile)); @@ -1085,7 +1090,7 @@ QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform) { return result; } -QByteArray DocumentData::data() const { +QByteArray DocumentData::rawBytes() const { if (!_data.isEmpty()) { ActiveCache().up(const_cast(this)); } @@ -1115,8 +1120,10 @@ void DocumentData::setLocation(const FileLocation &loc) { QString DocumentData::filepath(FilePathResolve resolve) const { bool check = (resolve != FilePathResolve::Cached); - QString result = (check && _location.name().isEmpty()) ? QString() : location(check).name(); - bool saveFromData = result.isEmpty() && !data().isEmpty(); + QString result = (check && _location.name().isEmpty()) + ? QString() + : location(check).name(); + bool saveFromData = result.isEmpty() && !rawBytes().isEmpty(); if (saveFromData) { if (resolve != FilePathResolve::SaveFromData && resolve != FilePathResolve::SaveFromDataSilent) { @@ -1131,7 +1138,7 @@ QString DocumentData::filepath(FilePathResolve resolve) const { if (!filename.isEmpty()) { QFile f(filename); if (f.open(QIODevice::WriteOnly)) { - if (f.write(data()) == data().size()) { + if (f.write(rawBytes()) == rawBytes().size()) { f.close(); const_cast(this)->_location = FileLocation(filename); Local::writeFileLocation(mediaKey(), _location); @@ -1263,8 +1270,8 @@ auto DocumentData::createStreamingLoader( } if (!forceRemoteLoader) { const auto &location = this->location(true); - if (!data().isEmpty()) { - return Media::Streaming::MakeBytesLoader(data()); + if (!rawBytes().isEmpty()) { + return Media::Streaming::MakeBytesLoader(rawBytes()); } else if (!location.isEmpty() && location.accessEnable()) { auto result = Media::Streaming::MakeFileLoader(location.name()); location.accessDisable(); @@ -1545,6 +1552,9 @@ void DocumentData::collectLocalData(not_null local) { if (!local->_data.isEmpty()) { ActiveCache().decrement(_data.size()); _data = local->_data; + if (const auto media = activeMediaView()) { + media->setBytes(local->_data); + } ActiveCache().increment(_data.size()); if (!_data.isEmpty()) { ActiveCache().up(this); @@ -1642,7 +1652,7 @@ base::binary_guard ReadImageAsync( FnMut done) { auto result = base::binary_guard(); crl::async([ - bytes = document->data(), + bytes = document->rawBytes(), path = document->filepath(), postprocess = std::move(postprocess), guard = result.make_guard(), @@ -1672,30 +1682,4 @@ base::binary_guard ReadImageAsync( return result; } -//void HandleUnsupportedMedia( -// not_null document, -// FullMsgId contextId) { -// using Error = ::Media::Streaming::Error; -// -// document->setInappPlaybackFailed(); -// const auto filepath = document->filepath( -// DocumentData::FilePathResolve::SaveFromData); -// if (filepath.isEmpty()) { -// const auto save = [=] { -// Ui::hideLayer(); -// DocumentSaveClickHandler::Save( -// (contextId ? contextId : Data::FileOrigin()), -// document, -// document->owner().message(contextId)); -// }; -// Ui::show(Box( -// tr::lng_player_cant_stream(tr::now), -// tr::lng_player_download(tr::now), -// tr::lng_cancel(tr::now), -// save)); -// } else if (IsValidMediaFile(filepath)) { -// File::Launch(filepath); -// } -//} - } // namespace Data diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index cb0e54463..41a110ca1 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -127,7 +127,7 @@ public: void setWaitingForAlbum(); [[nodiscard]] bool waitingForAlbum() const; - [[nodiscard]] QByteArray data() const; + [[nodiscard]] QByteArray rawBytes() const; [[nodiscard]] const FileLocation &location(bool check = false) const; void setLocation(const FileLocation &loc); @@ -163,9 +163,6 @@ public: void recountIsImage(); [[nodiscard]] bool supportsStreaming() const; void setNotSupportsStreaming(); - void setData(const QByteArray &data) { - _data = data; - } void setDataAndCache(const QByteArray &data); bool checkWallPaperProperties(); [[nodiscard]] bool isWallPaper() const; diff --git a/Telegram/SourceFiles/data/data_document_media.cpp b/Telegram/SourceFiles/data/data_document_media.cpp index 2e1ab3410..49b1de4c1 100644 --- a/Telegram/SourceFiles/data/data_document_media.cpp +++ b/Telegram/SourceFiles/data/data_document_media.cpp @@ -82,11 +82,16 @@ enum class FileType { } // namespace DocumentMedia::DocumentMedia(not_null owner) -: _owner(owner) { +: _owner(owner) +, _bytes(owner->rawBytes()) { } DocumentMedia::~DocumentMedia() = default; +not_null DocumentMedia::owner() const { + return _owner; +} + void DocumentMedia::goodThumbnailWanted() { _flags |= Flag::GoodThumbnailWanted; } @@ -135,7 +140,7 @@ void DocumentMedia::checkStickerLarge() { if (data->animated || !_owner->loaded()) { return; } - const auto bytes = _owner->data(); + const auto bytes = _owner->rawBytes(); if (bytes.isEmpty()) { const auto &loc = _owner->location(true); if (loc.accessEnable()) { @@ -155,6 +160,16 @@ void DocumentMedia::checkStickerLarge() { } } +void DocumentMedia::setBytes(const QByteArray &bytes) { + if (!bytes.isEmpty()) { + _bytes = bytes; + } +} + +QByteArray DocumentMedia::bytes() const { + return _bytes; +} + void DocumentMedia::checkStickerSmall() { const auto data = _owner->sticker(); if ((data && data->animated) || _owner->thumbnailEnoughForSticker()) { @@ -184,18 +199,18 @@ void DocumentMedia::checkStickerLarge(not_null loader) { if (_owner->sticker() && !_sticker && !loader->imageData().isNull() - && !_owner->data().isEmpty()) { + && !_owner->rawBytes().isEmpty()) { _sticker = std::make_unique( std::make_unique( QString(), - _owner->data(), + _owner->rawBytes(), loader->imageFormat(), loader->imageData())); } } void DocumentMedia::GenerateGoodThumbnail(not_null document) { - const auto data = document->data(); + const auto data = document->rawBytes(); const auto type = document->isWallPaper() ? FileType::WallPaper : document->isTheme() diff --git a/Telegram/SourceFiles/data/data_document_media.h b/Telegram/SourceFiles/data/data_document_media.h index e2d907baa..7301006e3 100644 --- a/Telegram/SourceFiles/data/data_document_media.h +++ b/Telegram/SourceFiles/data/data_document_media.h @@ -18,6 +18,8 @@ public: explicit DocumentMedia(not_null owner); ~DocumentMedia(); + [[nodiscard]] not_null owner() const; + void goodThumbnailWanted(); [[nodiscard]] Image *goodThumbnail() const; void setGoodThumbnail(QImage thumbnail); @@ -30,6 +32,9 @@ public: [[nodiscard]] Image *getStickerLarge(); void checkStickerLarge(not_null loader); + void setBytes(const QByteArray &bytes); + [[nodiscard]] QByteArray bytes() const; + // For DocumentData. static void CheckGoodThumbnail(not_null document); @@ -47,6 +52,7 @@ private: std::unique_ptr _goodThumbnail; mutable std::unique_ptr _inlineThumbnail; std::unique_ptr _sticker; + QByteArray _bytes; Flags _flags; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 87cc280d2..a6ea13324 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -386,6 +386,8 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti auto voiceStatusOverride = QString(); if (const auto voice = Get()) { + ensureDataMediaCreated(); + const VoiceWaveform *wf = nullptr; uchar norm_value = 0; if (const auto voiceData = _data->voice()) { @@ -393,7 +395,7 @@ void Document::draw(Painter &p, const QRect &r, TextSelection selection, crl::ti if (wf->isEmpty()) { wf = nullptr; if (loaded) { - Local::countVoiceWaveform(_data); + Local::countVoiceWaveform(_dataMedia.get()); } } else if (wf->at(0) < 0) { wf = nullptr; diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp index 98491f9da..e72729b42 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp @@ -271,8 +271,10 @@ void Sticker::setDiceIndex(const QString &emoji, int index) { } void Sticker::setupLottie() { + Expects(_dataMedia != nullptr); + _lottie = Stickers::LottiePlayerFromDocument( - _data, + _dataMedia.get(), _replacements, Stickers::LottieSize::MessageHistory, _size * cIntRetinaFactor(), diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index 5f9e6dc55..29b242962 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -146,6 +146,9 @@ int Gif::resizeGetHeight(int width) { void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) const { const auto document = getShownDocument(); + if (document) { + ensureDataMediaCreated(document); + } document->automaticLoad(fileOrigin(), nullptr); bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading(); @@ -154,7 +157,7 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons && !_gif.isBad() && CanPlayInline(document)) { auto that = const_cast(this); - that->_gif = Media::Clip::MakeReader(document, FullMsgId(), [that](Media::Clip::Notification notification) { + that->_gif = Media::Clip::MakeReader(_dataMedia.get(), FullMsgId(), [that](Media::Clip::Notification notification) { that->clipCallback(notification); }); if (_gif) _gif->setAutoplay(); @@ -508,9 +511,11 @@ QSize Sticker::getThumbSize() const { return QSize(qMax(w, 1), qMax(h, 1)); } -void Sticker::setupLottie(not_null document) const { +void Sticker::setupLottie() const { + Expects(_dataMedia != nullptr); + _lottie = Stickers::LottiePlayerFromDocument( - document, + _dataMedia.get(), Stickers::LottieSize::InlineResults, QSize( st::stickerPanSize.width() - st::buttonRadius * 2, @@ -530,7 +535,7 @@ void Sticker::prepareThumbnail() const { && document->sticker() && document->sticker()->animated && document->loaded()) { - setupLottie(document); + setupLottie(); } _dataMedia->checkStickerSmall(); if (const auto sticker = _dataMedia->getStickerSmall()) { @@ -1318,7 +1323,10 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con // Gif thumb auto thumbDisplayed = false, radial = false; - auto document = getResultDocument(); + const auto document = getResultDocument(); + if (document) { + ensureDataMediaCreated(document); + } auto animatedThumb = document && document->isAnimation(); if (animatedThumb) { document->automaticLoad(fileOrigin(), nullptr); @@ -1326,7 +1334,7 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading(); if (loaded && !_gif && !_gif.isBad()) { auto that = const_cast(this); - that->_gif = Media::Clip::MakeReader(document, FullMsgId(), [that](Media::Clip::Notification notification) { + that->_gif = Media::Clip::MakeReader(_dataMedia.get(), FullMsgId(), [that](Media::Clip::Notification notification) { that->clipCallback(notification); }); if (_gif) _gif->setAutoplay(); @@ -1403,7 +1411,7 @@ void Game::prepareThumbnail(QSize size) const { validateThumbnail(photo->thumbnail(), size, true); validateThumbnail(photo->thumbnailInline(), size, false); } else if (const auto document = getResultDocument()) { - ensureDataMediaCreated(document); + Assert(_dataMedia != nullptr); validateThumbnail(document->thumbnail(), size, true); validateThumbnail(_dataMedia->thumbnailInline(), size, false); } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h index fe2d7a1de..30020341a 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.h @@ -193,7 +193,7 @@ public: private: void ensureDataMediaCreated(not_null document) const; - void setupLottie(not_null document) const; + void setupLottie() const; QSize getThumbSize() const; void prepareThumbnail() const; diff --git a/Telegram/SourceFiles/media/audio/media_audio.cpp b/Telegram/SourceFiles/media/audio/media_audio.cpp index 9c405c00c..9a86955bd 100644 --- a/Telegram/SourceFiles/media/audio/media_audio.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio.cpp @@ -761,7 +761,6 @@ void Mixer::play( auto type = audio.type(); AudioMsgId stopped; - auto notLoadedYet = false; { QMutexLocker lock(&AudioMutex); Audio::AttachToDevice(); @@ -799,42 +798,18 @@ void Mixer::play( current->state.id = audio; current->lastUpdateWhen = 0; current->lastUpdatePosition = 0; - if (externalData) { - current->setExternalData(std::move(externalData)); - } else { - current->setExternalData(nullptr); - current->file = audio.audio()->location(true); - current->data = audio.audio()->data(); - notLoadedYet = (current->file.isEmpty() && current->data.isEmpty()); - } - if (notLoadedYet) { - auto newState = (type == AudioMsgId::Type::Song) - ? State::Stopped - : State::StoppedAtError; - setStoppedState(current, newState); - } else { - current->state.position = (positionMs * current->state.frequency) - / 1000LL; - current->state.state = current->externalData - ? State::Paused - : fadedStart - ? State::Starting - : State::Playing; - current->loading = true; - emit loaderOnStart(current->state.id, positionMs); - if (type == AudioMsgId::Type::Voice) { - emit suppressSong(); - } - } - } - if (notLoadedYet) { - if (type == AudioMsgId::Type::Song || type == AudioMsgId::Type::Video) { - DocumentOpenClickHandler::Open( - audio.contextId(), - audio.audio(), - Auth().data().message(audio.contextId())); - } else { - onError(audio); + current->setExternalData(std::move(externalData)); + current->state.position = (positionMs * current->state.frequency) + / 1000LL; + current->state.state = current->externalData + ? State::Paused + : fadedStart + ? State::Starting + : State::Playing; + current->loading = true; + emit loaderOnStart(current->state.id, positionMs); + if (type == AudioMsgId::Type::Voice) { + emit suppressSong(); } } if (stopped) { diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp index 2b063b6b2..84b57b9a6 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/clip/media_clip_reader.h" #include "data/data_document.h" +#include "data/data_document_media.h" #include "storage/file_download.h" #include "media/clip/media_clip_ffmpeg.h" #include "media/clip/media_clip_check_streaming.h" @@ -91,15 +92,20 @@ Reader::Reader(const QString &filepath, Callback &&callback, Mode mode, crl::tim init(FileLocation(filepath), QByteArray()); } -Reader::Reader(not_null document, FullMsgId msgId, Callback &&callback, Mode mode, crl::time seekMs) +Reader::Reader( + not_null media, + FullMsgId msgId, + Callback &&callback, + Mode mode, + crl::time seekMs) : _callback(std::move(callback)) , _mode(mode) , _audioMsgId( - document, + media->owner(), msgId, (mode == Mode::Video) ? AudioMsgId::CreateExternalPlayId() : 0) , _seekPositionMs(seekMs) { - init(document->location(), document->data()); + init(media->owner()->location(), media->bytes()); } Reader::Reader(const QByteArray &data, Callback &&callback, Mode mode, crl::time seekMs) diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.h b/Telegram/SourceFiles/media/clip/media_clip_reader.h index 0f62f650b..f1d927f41 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.h +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.h @@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class FileLocation; +namespace Data { +class DocumentMedia; +} // namespace Data + namespace Media { namespace Clip { @@ -56,8 +60,8 @@ public: Video, }; + Reader(not_null media, FullMsgId msgId, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0); Reader(const QString &filepath, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0); - Reader(not_null document, FullMsgId msgId, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0); Reader(const QByteArray &data, Callback &&callback, Mode mode = Mode::Gif, crl::time seekMs = 0); // Reader can be already deleted. diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index ed933f2d2..443f714e8 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1220,8 +1220,9 @@ void OverlayWidget::notifyFileDialogShown(bool shown) { void OverlayWidget::onSaveAs() { QString file; if (_doc) { - const FileLocation &location(_doc->location(true)); - if (!_doc->data().isEmpty() || location.accessEnable()) { + const auto &location = _doc->location(true); + const auto bytes = _docMedia->bytes(); + if (!bytes.isEmpty() || location.accessEnable()) { QFileInfo alreadyInfo(location.name()); QDir alreadyDir(alreadyInfo.dir()); QString name = alreadyInfo.fileName(), filter; @@ -1240,17 +1241,19 @@ void OverlayWidget::onSaveAs() { file = FileNameForSave(tr::lng_save_file(tr::now), filter, qsl("doc"), name, true, alreadyDir); if (!file.isEmpty() && file != location.name()) { - if (_doc->data().isEmpty()) { + if (bytes.isEmpty()) { QFile(file).remove(); QFile(location.name()).copy(file); } else { QFile f(file); f.open(QIODevice::WriteOnly); - f.write(_doc->data()); + f.write(bytes); } } - if (_doc->data().isEmpty()) location.accessDisable(); + if (bytes.isEmpty()) { + location.accessDisable(); + } } else { DocumentSaveClickHandler::Save( fileOrigin(), @@ -2330,7 +2333,7 @@ void OverlayWidget::initThemePreview() { Assert(_doc && _doc->isTheme()); - const auto bytes = _doc->data(); + const auto bytes = _docMedia->bytes(); auto &location = _doc->location(); if (bytes.isEmpty() && (location.isEmpty() || !location.accessEnable())) { diff --git a/Telegram/SourceFiles/storage/file_download.h b/Telegram/SourceFiles/storage/file_download.h index d68b81352..b97505507 100644 --- a/Telegram/SourceFiles/storage/file_download.h +++ b/Telegram/SourceFiles/storage/file_download.h @@ -30,11 +30,8 @@ struct Key; // This value is used in local cache database settings! constexpr auto kMaxFileInMemory = 10 * 1024 * 1024; -// 2 MB audio is hold in memory and auto loaded -constexpr auto kMaxVoiceInMemory = 2 * 1024 * 1024; - // 2 MB stickers hold in memory, auto loaded and displayed inline -constexpr auto kMaxStickerInMemory = 2 * 1024 * 1024; +constexpr auto kMaxStickerBytesSize = 2 * 1024 * 1024; // 10 MB GIF and mp4 animations held in memory while playing constexpr auto kMaxWallPaperInMemory = kMaxFileInMemory; diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp index 28732edeb..5098e8775 100644 --- a/Telegram/SourceFiles/storage/localimageloader.cpp +++ b/Telegram/SourceFiles/storage/localimageloader.cpp @@ -836,7 +836,7 @@ void FileLoadTask::process() { && (h > 0) && (w <= StickerMaxSize) && (h <= StickerMaxSize) - && (filesize < Storage::kMaxStickerInMemory); + && (filesize < Storage::kMaxStickerBytesSize); if (isSticker) { attributes.push_back(MTP_documentAttributeSticker( MTP_flags(0), diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index d0b80ffac..55b4c7eb4 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "chat_helpers/stickers.h" #include "data/data_drafts.h" #include "data/data_user.h" +#include "data/data_session.h" +#include "data/data_document_media.h" #include "boxes/send_files_box.h" #include "base/flags.h" #include "base/platform/base_platform_file_utilities.h" @@ -37,7 +39,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" #include "window/themes/window_theme.h" #include "window/window_session_controller.h" -#include "data/data_session.h" #include "history/history.h" #include "facades.h" @@ -3358,11 +3359,11 @@ Storage::Cache::Database::Settings cacheBigFileSettings() { class CountWaveformTask : public Task { public: - CountWaveformTask(DocumentData *doc) - : _doc(doc) - , _loc(doc->location(true)) - , _data(doc->data()) - , _wavemax(0) { + CountWaveformTask(not_null media) + : _doc(media->owner()) + , _loc(_doc->location(true)) + , _data(media->bytes()) + , _wavemax(0) { if (_data.isEmpty() && !_loc.accessEnable()) { _doc = nullptr; } @@ -3399,7 +3400,7 @@ public: } protected: - DocumentData *_doc; + DocumentData *_doc = nullptr; FileLocation _loc; QByteArray _data; VoiceWaveform _waveform; @@ -3407,13 +3408,14 @@ protected: }; -void countVoiceWaveform(DocumentData *document) { +void countVoiceWaveform(not_null media) { + const auto document = media->owner(); if (const auto voice = document->voice()) { if (_localLoader) { voice->waveform.resize(1 + sizeof(TaskId)); voice->waveform[0] = -1; // counting TaskId taskId = _localLoader->addTask( - std::make_unique(document)); + std::make_unique(media)); memcpy(voice->waveform.data() + 1, &taskId, sizeof(taskId)); } } diff --git a/Telegram/SourceFiles/storage/localstorage.h b/Telegram/SourceFiles/storage/localstorage.h index d75ce8a75..34918bed5 100644 --- a/Telegram/SourceFiles/storage/localstorage.h +++ b/Telegram/SourceFiles/storage/localstorage.h @@ -18,6 +18,7 @@ class History; namespace Data { class WallPaper; +class DocumentMedia; } // namespace Data namespace Lang { @@ -129,7 +130,7 @@ Storage::EncryptionKey cacheBigFileKey(); QString cacheBigFilePath(); Storage::Cache::Database::Settings cacheBigFileSettings(); -void countVoiceWaveform(DocumentData *document); +void countVoiceWaveform(not_null media); void cancelTask(TaskId id); diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp index f827cab3f..6b79f2a59 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp @@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_cloud_themes.h" #include "data/data_file_origin.h" #include "data/data_document.h" +#include "data/data_document_media.h" #include "data/data_session.h" #include "ui/image/image_prepare.h" #include "ui/widgets/popup_menu.h" @@ -560,6 +561,7 @@ void CloudList::refreshColors(Element &element) { && (!document || !document->isTheme()))) { element.check->setColors(ColorsFromCurrentTheme()); } else if (document) { + element.media = document ? document->createMediaView() : nullptr; document->save( Data::FileOriginTheme(theme.id, theme.accessHash), QString()); @@ -639,7 +641,9 @@ void CloudList::refreshColorsFromDocument( not_null document) { const auto id = element.id(); const auto path = document->filepath(); - const auto data = document->data(); + const auto data = element.media + ? base::take(element.media)->bytes() + : QByteArray(); crl::async([=, guard = element.generating.make_guard()]() mutable { crl::on_main(std::move(guard), [ =, diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h index 10fd9ade3..c647fd5db 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.h @@ -88,6 +88,7 @@ private: Data::CloudTheme theme; not_null check; std::unique_ptr button; + std::shared_ptr media; base::binary_guard generating; bool waiting = false; diff --git a/Telegram/SourceFiles/window/window_media_preview.cpp b/Telegram/SourceFiles/window/window_media_preview.cpp index 7915b68ae..50a540b42 100644 --- a/Telegram/SourceFiles/window/window_media_preview.cpp +++ b/Telegram/SourceFiles/window/window_media_preview.cpp @@ -226,7 +226,7 @@ void MediaPreviewWidget::setupLottie() { Expects(_document != nullptr); _lottie = std::make_unique( - Lottie::ReadContent(_document->data(), _document->filepath()), + Lottie::ReadContent(_documentMedia->bytes(), _document->filepath()), Lottie::FrameRequest{ currentDimensions() * cIntRetinaFactor() }, Lottie::Quality::High); @@ -266,7 +266,7 @@ QPixmap MediaPreviewWidget::currentImage() const { if (_document->loaded()) { if (!_gif && !_gif.isBad()) { auto that = const_cast(this); - that->_gif = Media::Clip::MakeReader(_document, FullMsgId(), [=](Media::Clip::Notification notification) { + that->_gif = Media::Clip::MakeReader(_documentMedia.get(), FullMsgId(), [=](Media::Clip::Notification notification) { that->clipCallback(notification); }); if (_gif) _gif->setAutoplay();