Play webm stickers only once if looping is disabled.

This commit is contained in:
John Preston 2022-02-10 19:10:42 +03:00
parent b4a49de819
commit 95e806cb89
12 changed files with 95 additions and 38 deletions

View File

@ -415,9 +415,21 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
activeOwnPlaying->frozenFrame = QImage();
activeOwnPlaying->frozenStatusText = QString();
}
p.drawImage(rthumb, streamed->frame(request));
if (!paused) {
streamed->markFrameShown();
const auto frame = streamed->frameWithInfo(request);
const auto playOnce = sticker
&& !Core::App().settings().loopAnimatedStickers();
const auto switchToNext = !playOnce
|| (frame.index != 0)
|| !_stickerOncePlayed;
p.drawImage(rthumb, frame.image);
if (!paused
&& switchToNext
&& streamed->markFrameShown()
&& playOnce
&& !_stickerOncePlayed) {
_stickerOncePlayed = true;
_parent->delegate()->elementStartStickerLoop(_parent);
}
}

View File

@ -101,6 +101,10 @@ public:
QPoint resolveCustomInfoRightBottom() const override;
QString additionalInfoString() const override;
void stickerClearLoopPlayed() override {
_stickerOncePlayed = false;
}
bool skipBubbleTail() const override {
return isRoundedInBubbleBottom() && _caption.isEmpty();
}
@ -192,6 +196,7 @@ private:
ClickHandlerPtr _stickerLink;
QString _downloadSize;
mutable bool _stickerOncePlayed = false;
};

View File

@ -177,7 +177,7 @@ struct FrameYUV420 {
};
struct FrameWithInfo {
QImage original;
QImage image;
FrameYUV420 *yuv420 = nullptr;
FrameFormat format = FrameFormat::None;
int index = -1;

View File

@ -172,6 +172,10 @@ QImage Instance::frame(const FrameRequest &request) const {
return player().frame(request, this);
}
FrameWithInfo Instance::frameWithInfo(const FrameRequest &request) const {
return player().frameWithInfo(request, this);
}
FrameWithInfo Instance::frameWithInfo() const {
return player().frameWithInfo(this);
}

View File

@ -69,6 +69,8 @@ public:
void callWaitingCallback();
[[nodiscard]] QImage frame(const FrameRequest &request) const;
[[nodiscard]] FrameWithInfo frameWithInfo(
const FrameRequest &request) const;
[[nodiscard]] FrameWithInfo frameWithInfo() const;
bool markFrameShown() const;

View File

@ -884,6 +884,14 @@ QImage Player::frame(
return _video->frame(request, instance);
}
FrameWithInfo Player::frameWithInfo(
const FrameRequest &request,
const Instance *instance) const {
Expects(_video != nullptr);
return _video->frameWithInfo(request, instance);
}
FrameWithInfo Player::frameWithInfo(const Instance *instance) const {
Expects(_video != nullptr);

View File

@ -64,7 +64,9 @@ public:
[[nodiscard]] QImage frame(
const FrameRequest &request,
const Instance *instance = nullptr) const;
[[nodiscard]] FrameWithInfo frameWithInfo(
const FrameRequest &request,
const Instance *instance = nullptr) const;
[[nodiscard]] FrameWithInfo frameWithInfo(
const Instance *instance = nullptr) const; // !requireARGB32

View File

@ -154,6 +154,7 @@ private:
Fn<void(Error)> _error;
crl::time _pausedTime = kTimeUnknown;
crl::time _resumedTime = kTimeUnknown;
int _frameIndex = 0;
int _durationByLastPacket = 0;
mutable TimePoint _syncTimePoint;
crl::time _loopingShift = 0;
@ -330,6 +331,7 @@ bool VideoTrackObject::loopAround() {
return false;
}
avcodec_flush_buffers(_stream.codec.get());
_frameIndex = 0;
_loopingShift += duration;
_readTillEnd = false;
return true;
@ -372,6 +374,7 @@ auto VideoTrackObject::readFrame(not_null<Frame*> frame) -> FrameResult {
return FrameResult::Error;
}
std::swap(frame->decoded, _stream.frame);
frame->index = _frameIndex++;
frame->position = position;
frame->displayed = kTimeUnknown;
return FrameResult::Done;
@ -651,6 +654,7 @@ void VideoTrackObject::callReady() {
Expects(_ready != nullptr);
const auto frame = _shared->frameForPaint();
++_frameIndex;
auto data = VideoInformation();
data.size = FFmpeg::CorrectByAspect(
@ -961,9 +965,6 @@ bool VideoTrack::Shared::markFrameShown() {
if (frame->displayed == kTimeUnknown) {
return false;
}
if (counter == 2 * kFramesCount - 1) {
++_counterCycle;
}
_counter.store(
next,
std::memory_order_release);
@ -995,7 +996,7 @@ VideoTrack::FrameWithIndex VideoTrack::Shared::frameForPaintWithIndex() {
Assert(frame->displayed != kTimeUnknown);
return {
.frame = frame,
.index = (_counterCycle * 2 * kFramesCount) + index,
.index = frame->index,
};
}
@ -1101,7 +1102,44 @@ bool VideoTrack::markFrameShown() {
QImage VideoTrack::frame(
const FrameRequest &request,
const Instance *instance) {
const auto frame = _shared->frameForPaint();
return frameImage(_shared->frameForPaint(), request, instance);
}
FrameWithInfo VideoTrack::frameWithInfo(
const FrameRequest &request,
const Instance *instance) {
const auto data = _shared->frameForPaintWithIndex();
return {
.image = frameImage(data.frame, request, instance),
.format = FrameFormat::ARGB32,
.index = data.index,
};
}
FrameWithInfo VideoTrack::frameWithInfo(const Instance *instance) {
const auto data = _shared->frameForPaintWithIndex();
const auto i = data.frame->prepared.find(instance);
const auto none = (i == data.frame->prepared.end());
if (none || i->second.request.requireARGB32) {
_wrapped.with([=](Implementation &unwrapped) {
unwrapped.updateFrameRequest(
instance,
{ .requireARGB32 = false });
});
}
return {
.image = data.frame->original,
.yuv420 = &data.frame->yuv420,
.format = data.frame->format,
.index = data.index,
.alpha = data.frame->alpha,
};
}
QImage VideoTrack::frameImage(
not_null<Frame*> frame,
const FrameRequest &request,
const Instance *instance) {
const auto i = frame->prepared.find(instance);
const auto none = (i == frame->prepared.end());
const auto preparedFor = frame->prepared.empty()
@ -1151,26 +1189,6 @@ QImage VideoTrack::frame(
return i->second.image;
}
FrameWithInfo VideoTrack::frameWithInfo(const Instance *instance) {
const auto data = _shared->frameForPaintWithIndex();
const auto i = data.frame->prepared.find(instance);
const auto none = (i == data.frame->prepared.end());
if (none || i->second.request.requireARGB32) {
_wrapped.with([=](Implementation &unwrapped) {
unwrapped.updateFrameRequest(
instance,
{ .requireARGB32 = false });
});
}
return {
.original = data.frame->original,
.yuv420 = &data.frame->yuv420,
.format = data.frame->format,
.index = data.index,
.alpha = data.frame->alpha,
};
}
QImage VideoTrack::currentFrameImage() {
const auto frame = _shared->frameForPaint();
if (frame->original.isNull() && frame->format == FrameFormat::YUV420) {

View File

@ -58,6 +58,9 @@ public:
[[nodiscard]] QImage frame(
const FrameRequest &request,
const Instance *instance);
[[nodiscard]] FrameWithInfo frameWithInfo(
const FrameRequest &request,
const Instance *instance);
[[nodiscard]] FrameWithInfo frameWithInfo(const Instance *instance);
[[nodiscard]] QImage currentFrameImage();
void unregisterInstance(not_null<const Instance*> instance);
@ -88,6 +91,7 @@ private:
base::flat_map<const Instance*, Prepared> prepared;
int index = 0;
bool alpha = false;
};
struct FrameWithIndex {
@ -141,9 +145,6 @@ private:
static constexpr auto kCounterUninitialized = -1;
std::atomic<int> _counter = kCounterUninitialized;
// Main thread.
int _counterCycle = 0;
static constexpr auto kFramesCount = 4;
std::array<Frame, kFramesCount> _frames;
@ -160,6 +161,11 @@ private:
not_null<const Frame*> frame,
crl::time trackTime);
[[nodiscard]] QImage frameImage(
not_null<Frame*> frame,
const FrameRequest &request,
const Instance *instance);
const int _streamIndex = 0;
const AVRational _streamTimeBase;
const crl::time _streamDuration = 0;

View File

@ -188,9 +188,9 @@ void OverlayWidget::RendererGL::paintTransformedVideoFrame(
if (data.format == Streaming::FrameFormat::None) {
return;
} else if (data.format == Streaming::FrameFormat::ARGB32) {
Assert(!data.original.isNull());
Assert(!data.image.isNull());
paintTransformedStaticContent(
data.original,
data.image,
geometry,
data.alpha,
data.alpha);

View File

@ -610,7 +610,7 @@ Streaming::FrameWithInfo OverlayWidget::videoFrameWithInfo() const {
return _streamed->instance.player().ready()
? _streamed->instance.frameWithInfo()
: Streaming::FrameWithInfo{
.original = _streamed->instance.info().video.cover,
.image = _streamed->instance.info().video.cover,
.format = Streaming::FrameFormat::ARGB32,
.index = -2,
.alpha = _streamed->instance.info().video.alpha,

View File

@ -285,8 +285,8 @@ void Pip::RendererGL::paintTransformedVideoFrame(
}
geometry.rotation = (geometry.rotation + geometry.videoRotation) % 360;
if (data.format == Streaming::FrameFormat::ARGB32) {
Assert(!data.original.isNull());
paintTransformedStaticContent(data.original, geometry);
Assert(!data.image.isNull());
paintTransformedStaticContent(data.image, geometry);
return;
}
Assert(data.format == Streaming::FrameFormat::YUV420);