Fix sending of thumbnailed inline result GIFs.

This commit is contained in:
John Preston 2020-05-22 15:57:13 +04:00
parent 3c9ca2eb94
commit c61f3a0aba
6 changed files with 115 additions and 39 deletions

View file

@ -453,6 +453,7 @@ DocumentData::DocumentData(not_null<Data::Session*> 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()) {

View file

@ -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<void(::Media::Clip::Notification)> 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<DocumentData*> owner)
: _owner(owner) {
}

View file

@ -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<void(::Media::Clip::Notification)> 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<DocumentData*> owner);

View file

@ -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<Gif*>(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);
}();

View file

@ -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;
}

View file

@ -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,
};