diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 429b98e75..10d2bcefd 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -453,6 +453,7 @@ DocumentData::DocumentData(not_null owner, DocumentId id) DocumentData::~DocumentData() { base::take(_thumbnailLoader).reset(); + base::take(_videoThumbnailLoader).reset(); destroyLoader(); unload(); } @@ -672,7 +673,9 @@ bool DocumentData::thumbnailFailed() const { } void DocumentData::loadThumbnail(Data::FileOrigin origin) { - if (_thumbnailLoader || (_flags & Flag::ThumbnailFailed)) { + if (_thumbnailLoader + || (_flags & Flag::ThumbnailFailed) + || !_thumbnailLocation.valid()) { return; } else if (const auto active = activeMediaView()) { if (active->thumbnail()) { @@ -728,7 +731,9 @@ bool DocumentData::videoThumbnailFailed() const { } void DocumentData::loadVideoThumbnail(Data::FileOrigin origin) { - if (_videoThumbnailLoader || (_flags & Flag::VideoThumbnailFailed)) { + if (_videoThumbnailLoader + || (_flags & Flag::VideoThumbnailFailed) + || !_videoThumbnailLocation.valid()) { return; } else if (const auto active = activeMediaView()) { if (!active->videoThumbnailContent().isEmpty()) { diff --git a/Telegram/SourceFiles/data/data_document_media.cpp b/Telegram/SourceFiles/data/data_document_media.cpp index a469795dc..d31aa607b 100644 --- a/Telegram/SourceFiles/data/data_document_media.cpp +++ b/Telegram/SourceFiles/data/data_document_media.cpp @@ -85,6 +85,56 @@ enum class FileType { } // namespace +VideoPreviewState::VideoPreviewState(DocumentMedia *media) +: _media(media) +, _usingThumbnail(media ? media->owner()->hasVideoThumbnail() : false) { +} + +void VideoPreviewState::automaticLoad(Data::FileOrigin origin) const { + Expects(_media != nullptr); + + if (_usingThumbnail) { + _media->videoThumbnailWanted(origin); + } else { + _media->automaticLoad(origin, nullptr); + } +} + +::Media::Clip::ReaderPointer VideoPreviewState::makeAnimation( + Fn callback) const { + Expects(_media != nullptr); + Expects(loaded()); + + return _usingThumbnail + ? ::Media::Clip::MakeReader( + _media->videoThumbnailContent(), + std::move(callback)) + : ::Media::Clip::MakeReader( + _media, + FullMsgId(), + std::move(callback)); +} + +bool VideoPreviewState::usingThumbnail() const { + return _usingThumbnail; +} + +bool VideoPreviewState::loading() const { + return _usingThumbnail + ? _media->owner()->videoThumbnailLoading() + : _media + ? _media->owner()->loading() + : false; +} + +bool VideoPreviewState::loaded() const { + return _usingThumbnail + ? !_media->videoThumbnailContent().isEmpty() + : _media + ? _media->loaded() + : false; +} + DocumentMedia::DocumentMedia(not_null owner) : _owner(owner) { } diff --git a/Telegram/SourceFiles/data/data_document_media.h b/Telegram/SourceFiles/data/data_document_media.h index 73b467c17..4682fba6b 100644 --- a/Telegram/SourceFiles/data/data_document_media.h +++ b/Telegram/SourceFiles/data/data_document_media.h @@ -11,8 +11,34 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL class FileLoader; +namespace Media { +namespace Clip { +enum Notification : int; +class ReaderPointer; +} // namespace Clip +} // namespace Media + namespace Data { +class DocumentMedia; + +class VideoPreviewState final { +public: + explicit VideoPreviewState(DocumentMedia *media); + + void automaticLoad(Data::FileOrigin origin) const; + [[nodiscard]] ::Media::Clip::ReaderPointer makeAnimation( + Fn callback) const; + [[nodiscard]] bool usingThumbnail() const; + [[nodiscard]] bool loading() const; + [[nodiscard]] bool loaded() const; + +private: + DocumentMedia *_media = nullptr; + bool _usingThumbnail = false; + +}; + class DocumentMedia final { public: explicit DocumentMedia(not_null owner); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index a73e125ff..a68ab21d7 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -134,41 +134,28 @@ int Gif::resizeGetHeight(int width) { void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) const { const auto document = getShownDocument(); const auto displayLoading = document->displayLoading(); - const auto useVideoThumbnail = document->hasVideoThumbnail(); ensureDataMediaCreated(document); - if (!useVideoThumbnail) { - _dataMedia->automaticLoad(fileOrigin(), nullptr); - } + const auto preview = Data::VideoPreviewState(_dataMedia.get()); + preview.automaticLoad(fileOrigin()); - const auto loaded = useVideoThumbnail - ? !_dataMedia->videoThumbnailContent().isEmpty() - : _dataMedia->loaded(); - const auto loading = useVideoThumbnail - ? document->videoThumbnailLoading() - : document->loading(); + const auto loaded = preview.loaded(); + const auto loading = preview.loading(); if (loaded && !_gif && !_gif.isBad() && CanPlayInline(document)) { auto that = const_cast(this); - const auto callback = [=](Media::Clip::Notification notification) { + that->_gif = preview.makeAnimation([=]( + Media::Clip::Notification notification) { that->clipCallback(notification); - }; - that->_gif = useVideoThumbnail - ? Media::Clip::MakeReader( - _dataMedia->videoThumbnailContent(), - callback) - : Media::Clip::MakeReader( - _dataMedia.get(), - FullMsgId(), - callback); + }); } const auto animating = (_gif && _gif->started()); if (displayLoading) { ensureAnimation(); if (!_animation->radial.animating()) { - _animation->radial.start(_dataMedia->progress()); // #TODO video_thumbs + _animation->radial.start(_dataMedia->progress()); } } const auto radial = isRadialAnimation(); @@ -192,12 +179,15 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons p.drawPixmap(r.topLeft(), _thumb); } } - if (useVideoThumbnail) { - AssertIsDebug(); + + AssertIsDebug(); + if (preview.usingThumbnail()) { p.fillRect(QRect(r.topLeft(), QSize(20, 20)), Qt::green); } - if (radial || _gif.isBad() || (!_gif && !loaded && !loading)) { + if (radial + || _gif.isBad() + || (!_gif && !loaded && !loading && !preview.usingThumbnail())) { auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.; if (_animation && _animation->_a_over.animating()) { auto over = _animation->_a_over.value(1.); @@ -269,10 +259,11 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) { bool wasactive = (_state & StateFlag::Over); if (active != wasactive) { ensureDataMediaCreated(getShownDocument()); - if (!_dataMedia->loaded()) { // #TODO video_thumbs + const auto preview = Data::VideoPreviewState(_dataMedia.get()); + if (!preview.usingThumbnail() && !preview.loaded()) { ensureAnimation(); auto from = active ? 0. : 1., to = active ? 1. : 0.; - _animation->_a_over.start([this] { update(); }, from, to, st::stickersRowDuration); + _animation->_a_over.start([=] { update(); }, from, to, st::stickersRowDuration); } if (active) { _state |= StateFlag::Over; @@ -369,7 +360,8 @@ bool Gif::isRadialAnimation() const { return true; } else { ensureDataMediaCreated(getShownDocument()); - if (_dataMedia->loaded()) { // #TODO video_thumbs + const auto preview = Data::VideoPreviewState(_dataMedia.get()); + if (preview.usingThumbnail() || preview.loaded()) { _animation = nullptr; } } @@ -382,7 +374,7 @@ void Gif::radialAnimationCallback(crl::time now) const { ensureDataMediaCreated(document); const auto updated = [&] { return _animation->radial.update( - _dataMedia->progress(), // #TODO video_thumbs + _dataMedia->progress(), !document->loading() || _dataMedia->loaded(), now); }(); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index 6e7379893..993d58737 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -275,14 +275,17 @@ bool Result::onChoose(Layout::ItemBase *layout) { _type == Type::Gif)) { if (_type == Type::Gif) { const auto media = _document->activeMediaView(); - if (!media || media->loaded()) { + const auto preview = Data::VideoPreviewState(media.get()); + if (!media || preview.loaded()) { return true; - } else if (_document->loading()) { - _document->cancel(); - } else { - DocumentSaveClickHandler::Save( - Data::FileOriginSavedGifs(), - _document); + } else if (!preview.usingThumbnail()) { + if (preview.loading()) { + _document->cancel(); + } else { + DocumentSaveClickHandler::Save( + Data::FileOriginSavedGifs(), + _document); + } } return false; } diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.h b/Telegram/SourceFiles/media/clip/media_clip_reader.h index 785c315af..fc85b1e10 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.h +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.h @@ -40,13 +40,13 @@ struct FrameRequest { RectParts corners = RectPart::AllCorners; }; -enum ReaderSteps { +enum ReaderSteps : int { WaitingForDimensionsStep = -3, // before ReaderPrivate read the first image and got the original frame size WaitingForRequestStep = -2, // before Reader got the original frame size and prepared the frame request WaitingForFirstFrameStep = -1, // before ReaderPrivate got the frame request and started waiting for the 1-2 delay }; -enum Notification { +enum Notification : int { NotificationReinit, NotificationRepaint, };