From 0126578dbd43759848d02e14896cfbd84cfc3782 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 3 Jul 2020 12:42:09 +0400 Subject: [PATCH] Allow to load video components of photos. --- Telegram/SourceFiles/data/data_document.h | 4 +- Telegram/SourceFiles/data/data_photo.cpp | 55 ++++++++++++++++++- Telegram/SourceFiles/data/data_photo.h | 11 +++- .../SourceFiles/data/data_photo_media.cpp | 19 +++++++ Telegram/SourceFiles/data/data_photo_media.h | 6 ++ Telegram/SourceFiles/data/data_session.cpp | 37 ++++++++++--- Telegram/SourceFiles/data/data_session.h | 6 +- .../ui/image/image_location_factory.cpp | 22 ++++++++ .../ui/image/image_location_factory.h | 4 ++ 9 files changed, 151 insertions(+), 13 deletions(-) diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index f391da7f4..ea6a8528c 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -166,8 +166,8 @@ public: [[nodiscard]] bool videoThumbnailLoading() const; [[nodiscard]] bool videoThumbnailFailed() const; void loadVideoThumbnail(Data::FileOrigin origin); - const ImageLocation &videoThumbnailLocation() const; - int videoThumbnailByteSize() const; + [[nodiscard]] const ImageLocation &videoThumbnailLocation() const; + [[nodiscard]] int videoThumbnailByteSize() const; void updateThumbnails( const QByteArray &inlineThumbnailBytes, diff --git a/Telegram/SourceFiles/data/data_photo.cpp b/Telegram/SourceFiles/data/data_photo.cpp index 33aaa52cd..eef46f7a8 100644 --- a/Telegram/SourceFiles/data/data_photo.cpp +++ b/Telegram/SourceFiles/data/data_photo.cpp @@ -39,6 +39,7 @@ PhotoData::~PhotoData() { for (auto &image : _images) { base::take(image.loader).reset(); } + base::take(_video.loader).reset(); } Data::Session &PhotoData::owner() const { @@ -294,7 +295,8 @@ void PhotoData::updateImages( const QByteArray &inlineThumbnailBytes, const ImageWithLocation &small, const ImageWithLocation &thumbnail, - const ImageWithLocation &large) { + const ImageWithLocation &large, + const ImageWithLocation &video) { if (!inlineThumbnailBytes.isEmpty() && _inlineThumbnailBytes.isEmpty()) { _inlineThumbnailBytes = inlineThumbnailBytes; @@ -315,6 +317,13 @@ void PhotoData::updateImages( update(PhotoSize::Small, small); update(PhotoSize::Thumbnail, thumbnail); update(PhotoSize::Large, large); + + Data::UpdateCloudFile( + _video, + video, + owner().cache(), + Data::kAnimationCacheTag, + [&](Data::FileOrigin origin) { loadVideo(origin); }); } int PhotoData::width() const { @@ -325,6 +334,50 @@ int PhotoData::height() const { return _images[PhotoSizeIndex(PhotoSize::Large)].location.height(); } +bool PhotoData::hasVideo() const { + return _video.location.valid(); +} + +bool PhotoData::videoLoading() const { + return _video.loader != nullptr; +} + +bool PhotoData::videoFailed() const { + return (_video.flags & Data::CloudFile::Flag::Failed); +} + +void PhotoData::loadVideo(Data::FileOrigin origin) { + const auto autoLoading = false; + const auto finalCheck = [=] { + if (const auto active = activeMediaView()) { + return active->videoContent().isEmpty(); + } + return true; + }; + const auto done = [=](QByteArray result) { + if (const auto active = activeMediaView()) { + active->setVideo(std::move(result)); + } + }; + Data::LoadCloudFile( + &session(), + _video, + origin, + LoadFromCloudOrLocal, + autoLoading, + Data::kAnimationCacheTag, + finalCheck, + done); +} + +const ImageLocation &PhotoData::videoLocation() const { + return _video.location; +} + +int PhotoData::videoByteSize() const { + return _video.byteSize; +} + PhotoClickHandler::PhotoClickHandler( not_null photo, FullMsgId context, diff --git a/Telegram/SourceFiles/data/data_photo.h b/Telegram/SourceFiles/data/data_photo.h index eaf666d45..f048d821d 100644 --- a/Telegram/SourceFiles/data/data_photo.h +++ b/Telegram/SourceFiles/data/data_photo.h @@ -82,7 +82,8 @@ public: const QByteArray &inlineThumbnailBytes, const ImageWithLocation &small, const ImageWithLocation &thumbnail, - const ImageWithLocation &large); + const ImageWithLocation &large, + const ImageWithLocation &video); [[nodiscard]] int validSizeIndex(Data::PhotoSize size) const; [[nodiscard]] QByteArray inlineThumbnailBytes() const { @@ -111,6 +112,13 @@ public: [[nodiscard]] std::optional size(Data::PhotoSize size) const; [[nodiscard]] int imageByteSize(Data::PhotoSize size) const; + [[nodiscard]] bool hasVideo() const; + [[nodiscard]] bool videoLoading() const; + [[nodiscard]] bool videoFailed() const; + void loadVideo(Data::FileOrigin origin); + [[nodiscard]] const ImageLocation &videoLocation() const; + [[nodiscard]] int videoByteSize() const; + // For now they return size of the 'large' image. int width() const; int height() const; @@ -127,6 +135,7 @@ public: private: QByteArray _inlineThumbnailBytes; std::array _images; + Data::CloudFile _video; int32 _dc = 0; uint64 _access = 0; diff --git a/Telegram/SourceFiles/data/data_photo_media.cpp b/Telegram/SourceFiles/data/data_photo_media.cpp index f18c69ee3..d636d5ac2 100644 --- a/Telegram/SourceFiles/data/data_photo_media.cpp +++ b/Telegram/SourceFiles/data/data_photo_media.cpp @@ -85,6 +85,25 @@ void PhotoMedia::set(PhotoSize size, QImage image) { _owner->session().notifyDownloaderTaskFinished(); } +QByteArray PhotoMedia::videoContent() const { + return _videoBytes; +} + +QSize PhotoMedia::videoSize() const { + const auto &location = _owner->videoLocation(); + return { location.width(), location.height() }; +} + +void PhotoMedia::videoWanted(Data::FileOrigin origin) { + if (_videoBytes.isEmpty()) { + _owner->loadVideo(origin); + } +} + +void PhotoMedia::setVideo(QByteArray content) { + _videoBytes = std::move(content); +} + bool PhotoMedia::loaded() const { const auto index = PhotoSizeIndex(PhotoSize::Large); return (_images[index] != nullptr); diff --git a/Telegram/SourceFiles/data/data_photo_media.h b/Telegram/SourceFiles/data/data_photo_media.h index 09d2f9c2e..4898b5028 100644 --- a/Telegram/SourceFiles/data/data_photo_media.h +++ b/Telegram/SourceFiles/data/data_photo_media.h @@ -28,6 +28,11 @@ public: void wanted(PhotoSize size, Data::FileOrigin origin); void set(PhotoSize size, QImage image); + [[nodiscard]] QByteArray videoContent() const; + [[nodiscard]] QSize videoSize() const; + void videoWanted(Data::FileOrigin origin); + void setVideo(QByteArray content); + [[nodiscard]] bool loaded() const; [[nodiscard]] float64 progress() const; @@ -42,6 +47,7 @@ private: const not_null _owner; mutable std::unique_ptr _inlineThumbnail; std::array, kPhotoSizeCount> _images; + QByteArray _videoBytes; }; diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index b9d21b25a..994ebf66a 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -2157,7 +2157,8 @@ not_null Session::processPhoto( QByteArray(), small, thumbnail, - large); + large, + ImageWithLocation{}); }, [&](const MTPDphotoEmpty &data) { return photo(data.vid().v); }); @@ -2173,7 +2174,8 @@ not_null Session::photo( const QByteArray &inlineThumbnailBytes, const ImageWithLocation &small, const ImageWithLocation &thumbnail, - const ImageWithLocation &large) { + const ImageWithLocation &large, + const ImageWithLocation &video) { const auto result = photo(id); photoApplyFields( result, @@ -2185,7 +2187,8 @@ not_null Session::photo( inlineThumbnailBytes, small, thumbnail, - large); + large, + video); return result; } @@ -2233,7 +2236,8 @@ PhotoData *Session::photoFromWeb( QByteArray(), ImageWithLocation{}, ImageWithLocation{ .location = thumbnailLocation }, - ImageWithLocation{ .location = large }); + ImageWithLocation{ .location = large }, + ImageWithLocation{}); } void Session::photoApplyFields( @@ -2271,6 +2275,22 @@ void Session::photoApplyFields( ? ImageWithLocation() : Images::FromPhotoSize(_session, data, *i); }; + const auto video = [&] { + const auto sizes = data.vvideo_sizes(); + if (!sizes || sizes->v.isEmpty()) { + return ImageWithLocation(); + } + const auto area = [](const MTPVideoSize &size) { + return size.match([](const MTPDvideoSize &data) { + return data.vw().v * data.vh().v; + }); + }; + const auto max = ranges::max_element( + sizes->v, + std::greater<>(), + area); + return Images::FromVideoSize(_session, data, *max); + }; const auto large = image(LargeLevels); if (large.location.valid()) { photoApplyFields( @@ -2283,7 +2303,8 @@ void Session::photoApplyFields( FindPhotoInlineThumbnail(data), image(SmallLevels), image(ThumbnailLevels), - large); + large, + video()); } } @@ -2297,7 +2318,8 @@ void Session::photoApplyFields( const QByteArray &inlineThumbnailBytes, const ImageWithLocation &small, const ImageWithLocation &thumbnail, - const ImageWithLocation &large) { + const ImageWithLocation &large, + const ImageWithLocation &video) { if (!date) { return; } @@ -2308,7 +2330,8 @@ void Session::photoApplyFields( inlineThumbnailBytes, small, thumbnail, - large); + large, + video); } not_null Session::document(DocumentId id) { diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index 02061e138..ae80d386b 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -403,7 +403,8 @@ public: const QByteArray &inlineThumbnailBytes, const ImageWithLocation &small, const ImageWithLocation &thumbnail, - const ImageWithLocation &large); + const ImageWithLocation &large, + const ImageWithLocation &video); void photoConvert( not_null original, const MTPPhoto &data); @@ -671,7 +672,8 @@ private: const QByteArray &inlineThumbnailBytes, const ImageWithLocation &small, const ImageWithLocation &thumbnail, - const ImageWithLocation &large); + const ImageWithLocation &large, + const ImageWithLocation &video); void documentApplyFields( not_null document, diff --git a/Telegram/SourceFiles/ui/image/image_location_factory.cpp b/Telegram/SourceFiles/ui/image/image_location_factory.cpp index 955eafd8e..1f2d97415 100644 --- a/Telegram/SourceFiles/ui/image/image_location_factory.cpp +++ b/Telegram/SourceFiles/ui/image/image_location_factory.cpp @@ -268,4 +268,26 @@ ImageWithLocation FromVideoSize( }); } +ImageWithLocation FromVideoSize( + not_null session, + const MTPDphoto &photo, + const MTPVideoSize &size) { + return size.match([&](const MTPDvideoSize &data) { + return ImageWithLocation{ + .location = ImageLocation( + DownloadLocation{ StorageFileLocation( + photo.vdc_id().v, + session->userId(), + MTP_inputPhotoFileLocation( + photo.vid(), + photo.vaccess_hash(), + photo.vfile_reference(), + data.vtype())) }, + data.vw().v, + data.vh().v), + .bytesCount = data.vsize().v + }; + }); +} + } // namespace Images diff --git a/Telegram/SourceFiles/ui/image/image_location_factory.h b/Telegram/SourceFiles/ui/image/image_location_factory.h index a60ab8b69..229a522e5 100644 --- a/Telegram/SourceFiles/ui/image/image_location_factory.h +++ b/Telegram/SourceFiles/ui/image/image_location_factory.h @@ -31,6 +31,10 @@ namespace Images { not_null session, const MTPDdocument &document, const MTPVideoSize &size); +[[nodiscard]] ImageWithLocation FromVideoSize( + not_null session, + const MTPDphoto &photo, + const MTPVideoSize &size); [[nodiscard]] ImageWithLocation FromImageInMemory( const QImage &image, const char *format);