Use streamed video for GIFs in History.

This commit is contained in:
John Preston 2019-07-30 17:46:13 +02:00
parent b73f1be856
commit 8e8c356659
9 changed files with 279 additions and 158 deletions

View File

@ -3199,25 +3199,30 @@ void Session::unregisterContactItem(
} }
} }
void Session::registerAutoplayAnimation( void Session::registerPlayingVideoFile(not_null<ViewElement*> view) {
not_null<::Media::Clip::Reader*> reader, _playingVideoFiles.emplace(view);
not_null<ViewElement*> view) {
_autoplayAnimations.emplace(reader, view);
} }
void Session::unregisterAutoplayAnimation( void Session::unregisterPlayingVideoFile(not_null<ViewElement*> view) {
not_null<::Media::Clip::Reader*> reader) { _playingVideoFiles.remove(view);
_autoplayAnimations.remove(reader);
} }
void Session::stopAutoplayAnimations() { void Session::stopPlayingVideoFiles() {
for (const auto [reader, view] : base::take(_autoplayAnimations)) { for (const auto view : base::take(_playingVideoFiles)) {
if (const auto media = view->media()) { if (const auto media = view->media()) {
media->stopAnimation(); media->stopAnimation();
} }
} }
} }
void Session::checkPlayingVideoFiles() {
for (const auto view : base::take(_playingVideoFiles)) {
if (const auto media = view->media()) {
media->checkAnimation();
}
}
}
HistoryItem *Session::findWebPageItem(not_null<WebPageData*> page) const { HistoryItem *Session::findWebPageItem(not_null<WebPageData*> page) const {
const auto i = _webpageItems.find(page); const auto i = _webpageItems.find(page);
if (i != _webpageItems.end()) { if (i != _webpageItems.end()) {

View File

@ -610,11 +610,11 @@ public:
void unregisterContactItem( void unregisterContactItem(
UserId contactId, UserId contactId,
not_null<HistoryItem*> item); not_null<HistoryItem*> item);
void registerAutoplayAnimation(
not_null<::Media::Clip::Reader*> reader, void registerPlayingVideoFile(not_null<ViewElement*> view);
not_null<ViewElement*> view); void unregisterPlayingVideoFile(not_null<ViewElement*> view);
void unregisterAutoplayAnimation( void checkPlayingVideoFiles();
not_null<::Media::Clip::Reader*> reader); void stopPlayingVideoFiles();
HistoryItem *findWebPageItem(not_null<WebPageData*> page) const; HistoryItem *findWebPageItem(not_null<WebPageData*> page) const;
QString findContactPhone(not_null<UserData*> contact) const; QString findContactPhone(not_null<UserData*> contact) const;
@ -626,8 +626,6 @@ public:
bool hasPendingWebPageGamePollNotification() const; bool hasPendingWebPageGamePollNotification() const;
void sendWebPageGamePollNotifications(); void sendWebPageGamePollNotifications();
void stopAutoplayAnimations();
void registerItemView(not_null<ViewElement*> view); void registerItemView(not_null<ViewElement*> view);
void unregisterItemView(not_null<ViewElement*> view); void unregisterItemView(not_null<ViewElement*> view);
@ -949,9 +947,7 @@ private:
std::unordered_map< std::unordered_map<
UserId, UserId,
base::flat_set<not_null<ViewElement*>>> _contactViews; base::flat_set<not_null<ViewElement*>>> _contactViews;
base::flat_map< base::flat_set<not_null<ViewElement*>> _playingVideoFiles;
not_null<::Media::Clip::Reader*>,
not_null<ViewElement*>> _autoplayAnimations;
base::flat_set<not_null<WebPageData*>> _webpagesUpdated; base::flat_set<not_null<WebPageData*>> _webpagesUpdated;
base::flat_set<not_null<GameData*>> _gamesUpdated; base::flat_set<not_null<GameData*>> _gamesUpdated;

View File

@ -1707,7 +1707,7 @@ void HistoryWidget::showHistory(
} }
if (!session().settings().autoplayGifs()) { if (!session().settings().autoplayGifs()) {
session().data().stopAutoplayAnimations(); session().data().stopPlayingVideoFiles();
} }
clearReplyReturns(); clearReplyReturns();
clearAllLoadRequests(); clearAllLoadRequests();

View File

@ -56,6 +56,9 @@ public:
void stopAnimation() override { void stopAnimation() override {
if (_attach) _attach->stopAnimation(); if (_attach) _attach->stopAnimation();
} }
void checkAnimation() override {
if (_attach) _attach->checkAnimation();
}
not_null<GameData*> game() { not_null<GameData*> game() {
return _data; return _data;

View File

@ -44,6 +44,21 @@ int gifMaxStatusWidth(DocumentData *document) {
} // namespace } // namespace
struct Gif::Streamed {
Streamed(
not_null<Data::Session*> owner,
std::shared_ptr<::Media::Streaming::Reader> reader);
::Media::Streaming::Player player;
::Media::Streaming::Information info;
};
Gif::Streamed::Streamed(
not_null<Data::Session*> owner,
std::shared_ptr<::Media::Streaming::Reader> reader)
: player(owner, std::move(reader)) {
}
Gif::Gif( Gif::Gif(
not_null<Element*> parent, not_null<Element*> parent,
not_null<DocumentData*> document) not_null<DocumentData*> document)
@ -59,6 +74,10 @@ Gif::Gif(
_data->loadThumbnail(item->fullId()); _data->loadThumbnail(item->fullId());
} }
Gif::~Gif() {
setStreamed(nullptr);
}
QSize Gif::countOptimalSize() { QSize Gif::countOptimalSize() {
if (_parent->media() != this) { if (_parent->media() != this) {
_caption = Ui::Text::String(); _caption = Ui::Text::String();
@ -67,12 +86,6 @@ QSize Gif::countOptimalSize() {
_parent->skipBlockWidth(), _parent->skipBlockWidth(),
_parent->skipBlockHeight()); _parent->skipBlockHeight());
} }
if (_gif && _gif->state() == ::Media::Clip::State::Error) {
if (!_gif->autoplay()) {
Ui::show(Box<InformBox>(tr::lng_gif_error(tr::now)));
}
setClipReader(::Media::Clip::ReaderPointer::Bad());
}
const auto maxSize = _data->isVideoMessage() const auto maxSize = _data->isVideoMessage()
? st::maxVideoMessageSize ? st::maxVideoMessageSize
@ -96,7 +109,7 @@ QSize Gif::countOptimalSize() {
auto maxWidth = qMax(tw, st::minPhotoSize); auto maxWidth = qMax(tw, st::minPhotoSize);
auto minHeight = qMax(th, st::minPhotoSize); auto minHeight = qMax(th, st::minPhotoSize);
accumulate_max(maxWidth, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); accumulate_max(maxWidth, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()));
if (!currentReader() && !activeRoundPlayer()) { if (!activeCurrentPlayer()) {
accumulate_max(maxWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); accumulate_max(maxWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()));
} }
if (_parent->hasBubble()) { if (_parent->hasBubble()) {
@ -151,34 +164,33 @@ QSize Gif::countCurrentSize(int newWidth) {
newWidth = qMax(tw, st::minPhotoSize); newWidth = qMax(tw, st::minPhotoSize);
auto newHeight = qMax(th, st::minPhotoSize); auto newHeight = qMax(th, st::minPhotoSize);
accumulate_max(newWidth, _parent->infoWidth() + 2 * st::msgDateImgDelta + st::msgDateImgPadding.x()); accumulate_max(newWidth, _parent->infoWidth() + 2 * st::msgDateImgDelta + st::msgDateImgPadding.x());
const auto reader = activeRoundPlayer() ? nullptr : currentReader(); if (!activeCurrentPlayer()) {
if (reader) { //const auto own = (reader->mode() == ::Media::Clip::Reader::Mode::Gif);
const auto own = (reader->mode() == ::Media::Clip::Reader::Mode::Gif); //if (own && !reader->started()) {
if (own && !reader->started()) { // auto isRound = _data->isVideoMessage();
auto isRound = _data->isVideoMessage(); // auto inWebPage = (_parent->media() != this);
auto inWebPage = (_parent->media() != this); // auto roundRadius = isRound
auto roundRadius = isRound // ? ImageRoundRadius::Ellipse
? ImageRoundRadius::Ellipse // : inWebPage
: inWebPage // ? ImageRoundRadius::Small
? ImageRoundRadius::Small // : ImageRoundRadius::Large;
: ImageRoundRadius::Large; // auto roundCorners = (isRound || inWebPage)
auto roundCorners = (isRound || inWebPage) // ? RectPart::AllCorners
? RectPart::AllCorners // : ((isBubbleTop()
: ((isBubbleTop() // ? (RectPart::TopLeft | RectPart::TopRight)
? (RectPart::TopLeft | RectPart::TopRight) // : RectPart::None)
: RectPart::None) // | ((isBubbleBottom() && _caption.isEmpty())
| ((isBubbleBottom() && _caption.isEmpty()) // ? (RectPart::BottomLeft | RectPart::BottomRight)
? (RectPart::BottomLeft | RectPart::BottomRight) // : RectPart::None));
: RectPart::None)); // reader->start(
reader->start( // _thumbw,
_thumbw, // _thumbh,
_thumbh, // newWidth,
newWidth, // newHeight,
newHeight, // roundRadius,
roundRadius, // roundCorners);
roundCorners); //}
} // #TODO video
} else {
accumulate_max(newWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); accumulate_max(newWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()));
} }
if (_parent->hasBubble()) { if (_parent->hasBubble()) {
@ -213,10 +225,8 @@ QSize Gif::countCurrentSize(int newWidth) {
} }
QSize Gif::videoSize() const { QSize Gif::videoSize() const {
if (const auto player = activeRoundPlayer()) { if (const auto player = activeCurrentPlayer()) {
return player->videoSize(); return player->videoSize();
} else if (const auto reader = currentReader()) {
return QSize(reader->width(), reader->height());
} else if (!_data->dimensions.isEmpty()) { } else if (!_data->dimensions.isEmpty()) {
return _data->dimensions; return _data->dimensions;
} else if (const auto thumbnail = _data->thumbnail()) { } else if (const auto thumbnail = _data->thumbnail()) {
@ -226,6 +236,7 @@ QSize Gif::videoSize() const {
} }
} }
bool Gif::autoplayEnabled() const { bool Gif::autoplayEnabled() const {
return history()->session().settings().autoplayGifs(); return history()->session().settings().autoplayGifs();
} }
@ -234,15 +245,14 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return; if (width() < st::msgPadding.left() + st::msgPadding.right() + 1) return;
const auto item = _parent->data(); const auto item = _parent->data();
_data->automaticLoad(_realParent->fullId(), item); //_data->automaticLoad(_realParent->fullId(), item);
auto loaded = _data->loaded(); //auto loaded = _data->loaded();
auto displayLoading = (item->id < 0) || _data->displayLoading(); auto displayLoading = (item->id < 0) || _data->displayLoading();
auto selected = (selection == FullSelection); auto selected = (selection == FullSelection);
if (loaded if (autoplayEnabled()
&& autoplayEnabled() && !_streamed
&& !_gif && _data->canBePlayed()
&& !_gif.isBad()
&& !activeRoundPlayer()) { && !activeRoundPlayer()) {
_parent->delegate()->elementAnimationAutoplayAsync(_parent); _parent->delegate()->elementAnimationAutoplayAsync(_parent);
} }
@ -256,11 +266,9 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
const auto isRound = _data->isVideoMessage(); const auto isRound = _data->isVideoMessage();
auto displayMute = false; auto displayMute = false;
const auto player = activeRoundPlayer(); const auto player = activeCurrentPlayer();
const auto reader = player ? nullptr : currentReader();
const auto animating = player || (reader && reader->started());
if ((!animating || item->id < 0) && displayLoading) { if ((!player || item->id < 0) && displayLoading) {
ensureAnimation(); ensureAnimation();
if (!_animation->radial.animating()) { if (!_animation->radial.animating()) {
_animation->radial.start(dataProgress()); _animation->radial.start(dataProgress());
@ -298,25 +306,23 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
auto roundRadius = isRound ? ImageRoundRadius::Ellipse : inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundRadius = isRound ? ImageRoundRadius::Ellipse : inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
auto roundCorners = (isRound || inWebPage) ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None) auto roundCorners = (isRound || inWebPage) ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
| ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None)); | ((isBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
if (animating) { if (player) {
auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any); auto paused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
if (isRound) { if (isRound) {
if (player) { if (activeRoundPlayer()) {
paused = false; paused = false;
} else { } else {
displayMute = true; displayMute = true;
} }
} }
if (player) { // #TODO video
auto request = ::Media::Streaming::FrameRequest(); // paused?..
request.outer = QSize(usew, painth) * cIntRetinaFactor(); auto request = ::Media::Streaming::FrameRequest();
request.resize = QSize(_thumbw, _thumbh) * cIntRetinaFactor(); request.outer = QSize(usew, painth) * cIntRetinaFactor();
request.corners = roundCorners; request.resize = QSize(_thumbw, _thumbh) * cIntRetinaFactor();
request.radius = roundRadius; request.corners = roundCorners;
p.drawImage(rthumb, player->frame(request)); request.radius = roundRadius;
} else { p.drawImage(rthumb, player->frame(request));
p.drawPixmap(rthumb.topLeft(), reader->current(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners, paused ? 0 : ms));
}
if (const auto playback = videoPlayback()) { if (const auto playback = videoPlayback()) {
const auto value = playback->value(); const auto value = playback->value();
@ -372,8 +378,8 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners); App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
} }
if (radial || (!reader && !player && (_gif.isBad() || (!loaded && !_data->loading()) || !autoplayEnabled()))) { if (radial || (!player && ((_streamed && _streamed->player.failed()) || (!_data->loaded() && !_data->loading()) || !autoplayEnabled()))) {
auto radialOpacity = (radial && loaded && item->id > 0) ? _animation->radial.opacity() : 1.; auto radialOpacity = (radial && _data->loaded() && item->id > 0) ? _animation->radial.opacity() : 1.;
auto inner = QRect(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); auto inner = QRect(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
if (selected) { if (selected) {
@ -413,7 +419,7 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
_animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::historyFileThumbRadialFgSelected : st::historyFileThumbRadialFg); _animation->radial.draw(p, rinner, st::msgFileRadialLine, selected ? st::historyFileThumbRadialFgSelected : st::historyFileThumbRadialFg);
} }
if (!isRound && (!animating || item->id < 0)) { if (!isRound && (!player || item->id < 0)) {
auto statusX = paintx + st::msgDateImgDelta + st::msgDateImgPadding.x(); auto statusX = paintx + st::msgDateImgDelta + st::msgDateImgPadding.x();
auto statusY = painty + st::msgDateImgDelta + st::msgDateImgPadding.y(); auto statusY = painty + st::msgDateImgDelta + st::msgDateImgPadding.y();
auto statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x(); auto statusW = st::normalFont->width(_statusText) + 2 * st::msgDateImgPadding.x();
@ -781,7 +787,7 @@ QString Gif::additionalInfoString() const {
} }
bool Gif::isReadyForOpen() const { bool Gif::isReadyForOpen() const {
return _data->loaded(); return true;
} }
void Gif::parentTextUpdated() { void Gif::parentTextUpdated() {
@ -808,94 +814,194 @@ int Gif::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply
return ::Media::Player::instance()->roundVideoPlayer(_parent->data()); return ::Media::Player::instance()->roundVideoPlayer(_parent->data());
} }
::Media::Clip::Reader *Gif::currentReader() const { ::Media::Streaming::Player *Gif::activeOwnPlayer() const {
return (_gif && _gif->ready()) ? _gif.get() : nullptr; return (_streamed
&& _streamed->player.ready()
&& !_streamed->player.videoSize().isEmpty())
? &_streamed->player
: nullptr;
}
::Media::Streaming::Player *Gif::activeCurrentPlayer() const {
if (const auto player = activeRoundPlayer()) {
return player;
}
return activeOwnPlayer();
} }
::Media::View::PlaybackProgress *Gif::videoPlayback() const { ::Media::View::PlaybackProgress *Gif::videoPlayback() const {
return ::Media::Player::instance()->roundVideoPlayback(_parent->data()); return ::Media::Player::instance()->roundVideoPlayback(_parent->data());
} }
// #TODO video
void Gif::clipCallback(::Media::Clip::Notification notification) { //void Gif::clipCallback(::Media::Clip::Notification notification) {
using namespace ::Media::Clip; // using namespace ::Media::Clip;
//
const auto reader = _gif.get(); // const auto reader = _gif.get();
if (!reader) { // if (!reader) {
return; // return;
} // }
switch (notification) { // switch (notification) {
case NotificationReinit: { // case NotificationReinit: {
auto stopped = false; // auto stopped = false;
if (reader->autoPausedGif()) { // if (reader->autoPausedGif()) {
auto amVisible = false; // auto amVisible = false;
history()->owner().queryItemVisibility().notify( // history()->owner().queryItemVisibility().notify(
{ _parent->data(), &amVisible }, // { _parent->data(), &amVisible },
true); // true);
if (!amVisible) { // Stop animation if it is not visible. // if (!amVisible) { // Stop animation if it is not visible.
stopAnimation(); // stopAnimation();
stopped = true; // stopped = true;
} // }
} // }
if (!stopped) { // if (!stopped) {
history()->owner().requestViewResize(_parent); // history()->owner().requestViewResize(_parent);
} // }
} break; // } break;
//
case NotificationRepaint: { // case NotificationRepaint: {
if (!reader->currentDisplayed()) { // if (!reader->currentDisplayed()) {
history()->owner().requestViewRepaint(_parent); // history()->owner().requestViewRepaint(_parent);
} // }
} break; // } break;
} // }
} //}
void Gif::playAnimation(bool autoplay) { void Gif::playAnimation(bool autoplay) {
if (_data->isVideoMessage() && !autoplay) { if (_data->isVideoMessage() && !autoplay) {
return; return;
} else if (_gif && autoplay) { } else if (_streamed && autoplay) {
return; return;
} else if (_gif && autoplayEnabled()) { } else if ((_streamed && autoplayEnabled())
|| (!autoplay && _data->isVideoFile())) {
Core::App().showDocument(_data, _parent->data()); Core::App().showDocument(_data, _parent->data());
return; return;
} }
using Mode = ::Media::Clip::Reader::Mode; using Mode = ::Media::Clip::Reader::Mode;
if (_gif) { if (_streamed) {
stopAnimation(); stopAnimation();
} else if (_data->loaded(DocumentData::FilePathResolve::Checked)) { } else if (_data->canBePlayed()) {
if (!autoplayEnabled()) { if (!autoplayEnabled()) {
history()->owner().stopAutoplayAnimations(); history()->owner().checkPlayingVideoFiles();
}
setClipReader(::Media::Clip::MakeReader(
_data,
_parent->data()->fullId(),
[=](auto notification) { clipCallback(notification); },
Mode::Gif));
if (_gif && autoplay) {
_gif->setAutoplay();
} }
createStreamedPlayer();
auto options = ::Media::Streaming::PlaybackOptions();
options.audioId = AudioMsgId(_data, _realParent->fullId());
//if (!_streamed->withSound) {
options.mode = ::Media::Streaming::Mode::Video;
options.loop = true;
//}
_streamed->player.play(options);
} }
} }
void Gif::createStreamedPlayer() {
setStreamed(std::make_unique<Streamed>(
&_data->owner(),
_data->owner().documentStreamedReader(
_data,
_realParent->fullId())));
_streamed->player.updates(
) | rpl::start_with_next_error([=](::Media::Streaming::Update &&update) {
handleStreamingUpdate(std::move(update));
}, [=](::Media::Streaming::Error &&error) {
handleStreamingError(std::move(error));
}, _streamed->player.lifetime());
_streamed->player.fullInCache(
) | rpl::start_with_next([=](bool fullInCache) {
_data->setLoadedInMediaCache(fullInCache);
}, _streamed->player.lifetime());
}
void Gif::setStreamed(std::unique_ptr<Streamed> value) {
const auto removed = (_streamed && !value);
const auto set = (!_streamed && value);
if (removed) {
history()->owner().unregisterPlayingVideoFile(_parent);
}
_streamed = std::move(value);
if (set) {
history()->owner().registerPlayingVideoFile(_parent);
}
}
void Gif::handleStreamingUpdate(::Media::Streaming::Update &&update) {
using namespace ::Media::Streaming;
update.data.match([&](Information &update) {
streamingReady(std::move(update));
}, [&](const PreloadedVideo &update) {
_streamed->info.video.state.receivedTill = update.till;
//updatePlaybackState();
}, [&](const UpdateVideo &update) {
_streamed->info.video.state.position = update.position;
history()->owner().requestViewRepaint(_parent);
Core::App().updateNonIdle();
//updatePlaybackState();
}, [&](const PreloadedAudio &update) {
//_streamed->info.audio.state.receivedTill = update.till;
//updatePlaybackState();
}, [&](const UpdateAudio &update) {
//_streamed->info.audio.state.position = update.position;
//updatePlaybackState();
}, [&](const WaitingForData &update) {
//playbackWaitingChange(update.waiting);
}, [&](MutedByOther) {
}, [&](Finished) {
const auto finishTrack = [](TrackState &state) {
state.position = state.receivedTill = state.duration;
};
finishTrack(_streamed->info.audio.state);
finishTrack(_streamed->info.video.state);
//updatePlaybackState();
});
}
void Gif::handleStreamingError(::Media::Streaming::Error &&error) {
using namespace ::Media::Streaming;
if (error == Error::NotStreamable) {
_data->setNotSupportsStreaming();
} else if (error == Error::OpenFailed) {
_data->setInappPlaybackFailed();
}
//if (!_data->canBePlayed()) {
// redisplayContent();
//} else {
// playbackWaitingChange(false);
// updatePlaybackState();
//}
}
void Gif::streamingReady(::Media::Streaming::Information &&info) {
_streamed->info = std::move(info);
history()->owner().requestViewResize(_parent);
//validateStreamedGoodThumbnail();
//if (videoShown()) {
// const auto contentSize = ConvertScale(videoSize());
// if (contentSize != QSize(_width, _height)) {
// update(contentRect());
// _w = contentSize.width();
// _h = contentSize.height();
// contentSizeChanged();
// }
//}
//history()->owner().requestViewRepaint(_parent);
//playbackWaitingChange(false);
}
void Gif::stopAnimation() { void Gif::stopAnimation() {
if (_gif) { if (_streamed) {
clearClipReader(); setStreamed(nullptr);
history()->owner().requestViewResize(_parent); history()->owner().requestViewResize(_parent);
_data->unload(); _data->unload();
} }
} }
void Gif::setClipReader(::Media::Clip::ReaderPointer gif) { void Gif::checkAnimation() {
if (_gif) { if (_streamed && !autoplayEnabled()) {
history()->owner().unregisterAutoplayAnimation(_gif.get()); stopAnimation();
} }
_gif = std::move(gif);
if (_gif) {
history()->owner().registerAutoplayAnimation(_gif.get(), _parent);
}
}
Gif::~Gif() {
clearClipReader();
} }
float64 Gif::dataProgress() const { float64 Gif::dataProgress() const {

View File

@ -23,16 +23,20 @@ class PlaybackProgress;
namespace Media { namespace Media {
namespace Streaming { namespace Streaming {
class Player; class Player;
struct Update;
struct Information;
enum class Error;
} // namespace Streaming } // namespace Streaming
} // namespace Media } // namespace Media
namespace HistoryView { namespace HistoryView {
class Gif : public File { class Gif final : public File {
public: public:
Gif( Gif(
not_null<Element*> parent, not_null<Element*> parent,
not_null<DocumentData*> document); not_null<DocumentData*> document);
~Gif();
void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override; void draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms) const override;
TextState textState(QPoint point, StateRequest request) const override; TextState textState(QPoint point, StateRequest request) const override;
@ -58,6 +62,7 @@ public:
} }
void stopAnimation() override; void stopAnimation() override;
void checkAnimation() override;
TextWithEntities getCaption() const override { TextWithEntities getCaption() const override {
return _caption.toTextWithEntities(); return _caption.toTextWithEntities();
@ -75,28 +80,29 @@ public:
void parentTextUpdated() override; void parentTextUpdated() override;
~Gif(); private:
struct Streamed;
protected:
float64 dataProgress() const override; float64 dataProgress() const override;
bool dataFinished() const override; bool dataFinished() const override;
bool dataLoaded() const override; bool dataLoaded() const override;
void setClipReader(::Media::Clip::ReaderPointer gif);
void clearClipReader() {
setClipReader(::Media::Clip::ReaderPointer());
}
private:
[[nodiscard]] bool autoplayEnabled() const; [[nodiscard]] bool autoplayEnabled() const;
void playAnimation(bool autoplay) override; void playAnimation(bool autoplay) override;
QSize countOptimalSize() override; QSize countOptimalSize() override;
QSize countCurrentSize(int newWidth) override; QSize countCurrentSize(int newWidth) override;
QSize videoSize() const; QSize videoSize() const;
::Media::Streaming::Player *activeRoundPlayer() const; ::Media::Streaming::Player *activeRoundPlayer() const;
::Media::Clip::Reader *currentReader() const; ::Media::Streaming::Player *activeOwnPlayer() const;
::Media::Streaming::Player *activeCurrentPlayer() const;
::Media::View::PlaybackProgress *videoPlayback() const; ::Media::View::PlaybackProgress *videoPlayback() const;
void clipCallback(::Media::Clip::Notification notification);
void createStreamedPlayer();
void setStreamed(std::unique_ptr<Streamed> value);
void handleStreamingUpdate(::Media::Streaming::Update &&update);
void handleStreamingError(::Media::Streaming::Error &&error);
void streamingReady(::Media::Streaming::Information &&info);
bool needInfoDisplay() const; bool needInfoDisplay() const;
int additionalWidth( int additionalWidth(
@ -111,7 +117,7 @@ private:
int _thumbw = 1; int _thumbw = 1;
int _thumbh = 1; int _thumbh = 1;
Ui::Text::String _caption; Ui::Text::String _caption;
::Media::Clip::ReaderPointer _gif; std::unique_ptr<Streamed> _streamed;
void setStatusSize(int newSize) const; void setStatusSize(int newSize) const;
void updateStatusText() const; void updateStatusText() const;

View File

@ -133,6 +133,8 @@ public:
} }
virtual void clearStickerLoopPlayed() { virtual void clearStickerLoopPlayed() {
} }
virtual void checkAnimation() {
}
[[nodiscard]] virtual QSize sizeForGrouping() const { [[nodiscard]] virtual QSize sizeForGrouping() const {
Unexpected("Grouping method call."); Unexpected("Grouping method call.");

View File

@ -62,6 +62,9 @@ public:
void stopAnimation() override { void stopAnimation() override {
if (_attach) _attach->stopAnimation(); if (_attach) _attach->stopAnimation();
} }
void checkAnimation() override {
if (_attach) _attach->checkAnimation();
}
not_null<WebPageData*> webpage() { not_null<WebPageData*> webpage() {
return _data; return _data;

View File

@ -466,7 +466,7 @@ void SetupPerformance(
}) | rpl::start_with_next([=](bool enabled) { }) | rpl::start_with_next([=](bool enabled) {
session->settings().setAutoplayGifs(enabled); session->settings().setAutoplayGifs(enabled);
if (!enabled) { if (!enabled) {
session->data().stopAutoplayAnimations(); session->data().checkPlayingVideoFiles();
} }
session->saveSettingsDelayed(); session->saveSettingsDelayed();
}, container->lifetime()); }, container->lifetime());