diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index b07a71c83..66e4eb908 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -858,8 +858,8 @@ void StickerSetBox::Inner::paintSticker( const auto &media = element.documentMedia; media->checkStickerSmall(); - const auto isAnimated = document->sticker()->animated; - if (isAnimated + const auto isLottie = document->sticker()->isLottie(); + if (isLottie && !element.animated && media->loaded()) { const_cast(this)->setupLottie(index); @@ -867,7 +867,7 @@ void StickerSetBox::Inner::paintSticker( auto w = 1; auto h = 1; - if (isAnimated && !document->dimensions.isEmpty()) { + if (isLottie && !document->dimensions.isEmpty()) { const auto request = Lottie::FrameRequest{ boundingBoxSize() * cIntRetinaFactor() }; const auto size = request.size(document->dimensions, true) / cIntRetinaFactor(); w = std::max(size.width(), 1); diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 46c2bd373..10b96ce27 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -827,7 +827,7 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) { const auto &media = sticker.documentMedia; if (!document->sticker()) continue; - if (document->sticker()->animated + if (document->sticker()->isLottie() && !sticker.animated && media->loaded()) { setupLottie(sticker); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp index d197246e8..31d671c4d 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_dice_pack.cpp @@ -141,7 +141,7 @@ void DicePack::generateLocal(int index, const QString &name) { _map.emplace(index, document); Ensures(document->sticker()); - Ensures(document->sticker()->animated); + Ensures(document->sticker()->isLottie()); } DicePacks::DicePacks(not_null session) : _session(session) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index f0516d5d6..3ff413bc7 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -1916,8 +1916,8 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section, return; } - const auto isAnimated = document->sticker()->animated; - if (isAnimated + const auto isLottie = document->sticker()->isLottie(); + if (isLottie && !sticker.animated && media->loaded()) { setupLottie(set, section, index); @@ -1936,7 +1936,7 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section, auto w = 1; auto h = 1; - if (isAnimated && !document->dimensions.isEmpty()) { + if (isLottie && !document->dimensions.isEmpty()) { const auto request = Lottie::FrameRequest{ boundingBoxSize() * cIntRetinaFactor() }; const auto size = request.size(document->dimensions, true) / cIntRetinaFactor(); w = std::max(size.width(), 1); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp b/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp index e9bc23149..ed7a11731 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_lottie.cpp @@ -139,7 +139,7 @@ bool HasLottieThumbnail( } const auto document = media->owner(); if (const auto info = document->sticker()) { - if (!info->animated) { + if (!info->isLottie()) { return false; } media->automaticLoad(document->stickerSetOrigin(), nullptr); diff --git a/Telegram/SourceFiles/core/mime_type.cpp b/Telegram/SourceFiles/core/mime_type.cpp index 8b8339ccd..737e285f1 100644 --- a/Telegram/SourceFiles/core/mime_type.cpp +++ b/Telegram/SourceFiles/core/mime_type.cpp @@ -109,6 +109,14 @@ MimeType MimeTypeForData(const QByteArray &data) { return MimeType(QMimeDatabase().mimeTypeForData(data)); } +bool IsMimeStickerLottie(const QString &mime) { + return (mime == u"application/x-tgsticker"_q); +} + +bool IsMimeStickerWebm(const QString &mime) { + return (mime == u"video/webm"_q); +} + bool IsMimeStickerAnimated(const QString &mime) { return (mime == u"application/x-tgsticker"_q); } diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 0308cc3bc..4a4c0f7d6 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -52,7 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { -const auto kAnimatedStickerDimensions = QSize( +const auto kLottieStickerDimensions = QSize( kStickerSideSize, kStickerSideSize); @@ -262,6 +262,22 @@ Data::FileOrigin StickerData::setOrigin() const { : Data::FileOrigin(); } +bool StickerData::isStatic() const { + return (type == StickerType::Webp); +} + +bool StickerData::isLottie() const { + return (type == StickerType::Tgs); +} + +bool StickerData::isAnimated() const { + return !isStatic(); +} + +bool StickerData::isWebm() const { + return (type == StickerType::Webm); +} + VoiceData::~VoiceData() { if (!waveform.isEmpty() && waveform[0] == -1 @@ -380,12 +396,19 @@ void DocumentData::setattributes( } if (type == StickerDocument && ((size > Storage::kMaxStickerBytesSize) - || (!sticker()->animated + || (!sticker()->isLottie() && !GoodStickerDimensions( dimensions.width(), dimensions.height())))) { type = FileDocument; _additional = nullptr; + } else if (type == FileDocument + && hasMimeType(qstr("video/webm")) + && (size < Storage::kMaxStickerBytesSize) + && GoodStickerDimensions(dimensions.width(), dimensions.height())) { + type = StickerDocument; + _additional = std::make_unique(); + sticker()->type = StickerType::Webm; } if (isAudioFile() || isAnimation() || isVoiceMessage()) { setMaybeSupportsStreaming(true); @@ -397,8 +420,8 @@ void DocumentData::validateLottieSticker() { && hasMimeType(qstr("application/x-tgsticker"))) { type = StickerDocument; _additional = std::make_unique(); - sticker()->animated = true; - dimensions = kAnimatedStickerDimensions; + sticker()->type = StickerType::Tgs; + dimensions = kLottieStickerDimensions; } } diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 2275094b2..c82ac71ef 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -57,12 +57,22 @@ struct DocumentAdditionalData { }; -struct StickerData : public DocumentAdditionalData { - Data::FileOrigin setOrigin() const; +enum class StickerType : uchar { + Webp, + Tgs, + Webm, +}; + +struct StickerData : public DocumentAdditionalData { + [[nodiscard]] Data::FileOrigin setOrigin() const; + [[nodiscard]] bool isStatic() const; + [[nodiscard]] bool isLottie() const; + [[nodiscard]] bool isAnimated() const; + [[nodiscard]] bool isWebm() const; - bool animated = false; QString alt; StickerSetIdentifier set; + StickerType type = StickerType::Webp; }; struct SongData : public DocumentAdditionalData { diff --git a/Telegram/SourceFiles/data/data_document_media.cpp b/Telegram/SourceFiles/data/data_document_media.cpp index 47481cdbb..52068ebdd 100644 --- a/Telegram/SourceFiles/data/data_document_media.cpp +++ b/Telegram/SourceFiles/data/data_document_media.cpp @@ -49,7 +49,7 @@ enum class FileType { || owner->isAnimation() || owner->isWallPaper() || owner->isTheme() - || (owner->sticker() && owner->sticker()->animated); + || (owner->sticker() && owner->sticker()->isAnimated()); } [[nodiscard]] QImage PrepareGoodThumbnail( @@ -260,7 +260,7 @@ void DocumentMedia::checkStickerLarge() { return; } automaticLoad(_owner->stickerSetOrigin(), nullptr); - if (data->animated || !loaded()) { + if (data->isAnimated() || !loaded()) { return; } if (_bytes.isEmpty()) { @@ -366,9 +366,9 @@ bool DocumentMedia::thumbnailEnoughForSticker() const { void DocumentMedia::checkStickerSmall() { const auto data = _owner->sticker(); - if ((data && data->animated) || thumbnailEnoughForSticker()) { + if ((data && data->isAnimated()) || thumbnailEnoughForSticker()) { _owner->loadThumbnail(_owner->stickerSetOrigin()); - if (data && data->animated) { + if (data && data->isAnimated()) { automaticLoad(_owner->stickerSetOrigin(), nullptr); } } else { @@ -383,7 +383,7 @@ Image *DocumentMedia::getStickerLarge() { Image *DocumentMedia::getStickerSmall() { const auto data = _owner->sticker(); - if ((data && data->animated) || thumbnailEnoughForSticker()) { + if ((data && data->isAnimated()) || thumbnailEnoughForSticker()) { return thumbnail(); } return _sticker.get(); diff --git a/Telegram/SourceFiles/data/stickers/data_stickers.cpp b/Telegram/SourceFiles/data/stickers/data_stickers.cpp index 6a8988855..591b1c9ff 100644 --- a/Telegram/SourceFiles/data/stickers/data_stickers.cpp +++ b/Telegram/SourceFiles/data/stickers/data_stickers.cpp @@ -994,7 +994,7 @@ std::vector> Stickers::getListByEmoji( const auto CreateSortKey = [&]( not_null document, int base) { - if (document->sticker() && document->sticker()->animated) { + if (document->sticker() && document->sticker()->isAnimated()) { base += kSlice; } return TimeId(base + int((document->id ^ seed) % kSlice)); @@ -1005,7 +1005,7 @@ std::vector> Stickers::getListByEmoji( auto myCounter = 0; const auto CreateMySortKey = [&](not_null document) { auto base = kSlice * 6; - if (!document->sticker() || !document->sticker()->animated) { + if (!document->sticker() || !document->sticker()->isAnimated()) { base -= kSlice; } return (base - (++myCounter)); @@ -1019,7 +1019,7 @@ std::vector> Stickers::getListByEmoji( const auto InstallDateAdjusted = [&]( TimeId date, not_null document) { - return (document->sticker() && document->sticker()->animated) + return (document->sticker() && document->sticker()->isAnimated()) ? date : date / 2; }; diff --git a/Telegram/SourceFiles/editor/scene/scene_item_sticker.cpp b/Telegram/SourceFiles/editor/scene/scene_item_sticker.cpp index 741d41060..16497ccb9 100644 --- a/Telegram/SourceFiles/editor/scene/scene_item_sticker.cpp +++ b/Telegram/SourceFiles/editor/scene/scene_item_sticker.cpp @@ -38,7 +38,7 @@ ItemSticker::ItemSticker( ? 1.0 : (_pixmap.height() / float64(_pixmap.width()))); }); - if (stickerData->animated) { + if (stickerData->isLottie()) { _lottie.player = ChatHelpers::LottiePlayerFromDocument( _mediaView.get(), ChatHelpers::StickerLottieSize::MessageHistory, diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index bfdc2795d..fd44944e6 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -391,6 +391,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { auto request = ::Media::Streaming::FrameRequest(); request.outer = QSize(usew, painth) * cIntRetinaFactor(); request.resize = QSize(_thumbw, _thumbh) * cIntRetinaFactor(); + request.keepAlpha = true; AssertIsDebug(); request.corners = roundCorners; request.radius = roundRadius; if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) { @@ -992,6 +993,7 @@ void Gif::drawGrouped( { geometry.width(), geometry.height() }); request.outer = geometry.size() * cIntRetinaFactor(); request.resize = pixSize * cIntRetinaFactor(); + request.keepAlpha = true; AssertIsDebug(); request.corners = corners; request.radius = roundRadius; if (activeOwnPlaying->instance.playerLocked()) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp index 16e00c365..d35bba657 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp @@ -123,7 +123,7 @@ bool Sticker::readyToDrawLottie() { ensureDataMediaCreated(); _dataMedia->checkStickerLarge(); const auto loaded = _dataMedia->loaded(); - if (sticker->animated && !_lottie && loaded) { + if (sticker->isLottie() && !_lottie && loaded) { setupLottie(); } return (_lottie && _lottie->ready()); @@ -147,7 +147,7 @@ void Sticker::draw( if (readyToDrawLottie()) { paintLottie(p, context, r); } else if (!_data->sticker() - || (_data->sticker()->animated && _replacements) + || (_data->sticker()->isLottie() && _replacements) || !paintPixmap(p, context, r)) { paintPath(p, context, r); } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index b16c9c2c1..3b6ce3231 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -554,7 +554,7 @@ void Sticker::prepareThumbnail() const { ensureDataMediaCreated(document); if (!_lottie && document->sticker() - && document->sticker()->animated + && document->sticker()->isLottie() && _dataMedia->loaded()) { setupLottie(); } diff --git a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp index e1161a9b7..553b1d6da 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp @@ -188,8 +188,16 @@ crl::time FFMpegReaderImplementation::framePresentationTime() const { } crl::time FFMpegReaderImplementation::durationMs() const { - if (_fmtContext->streams[_streamId]->duration == AV_NOPTS_VALUE) return 0; - return (_fmtContext->streams[_streamId]->duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den; + const auto rebase = [](int64_t duration, const AVRational &base) { + return (duration * 1000LL * base.num) / base.den; + }; + const auto stream = _fmtContext->streams[_streamId]; + if (stream->duration != AV_NOPTS_VALUE) { + return rebase(stream->duration, stream->time_base); + } else if (_fmtContext->duration != AV_NOPTS_VALUE) { + return rebase(_fmtContext->duration, AVRational{ 1, AV_TIME_BASE }); + } + return 0; } bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const QSize &size) { @@ -211,8 +219,12 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q if (to.isNull() || to.size() != toSize || !to.isDetached() || !isAlignedImage(to)) { to = createAlignedImage(toSize); } - hasAlpha = (_frame->format == AV_PIX_FMT_BGRA || (_frame->format == -1 && _codecContext->pix_fmt == AV_PIX_FMT_BGRA)); - if (_frame->width == toSize.width() && _frame->height == toSize.height() && hasAlpha) { + const auto format = (_frame->format == AV_PIX_FMT_NONE) + ? _codecContext->pix_fmt + : _frame->format; + const auto bgra = (format == AV_PIX_FMT_BGRA); + hasAlpha = bgra || (format == AV_PIX_FMT_YUVA420P); + if (_frame->width == toSize.width() && _frame->height == toSize.height() && bgra) { int32 sbpl = _frame->linesize[0], dbpl = to.bytesPerLine(), bpl = qMin(sbpl, dbpl); uchar *s = _frame->data[0], *d = to.bits(); for (int32 i = 0, l = _frame->height; i < l; ++i) { @@ -228,7 +240,7 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q int toLinesize[AV_NUM_DATA_POINTERS] = { int(to.bytesPerLine()), 0 }; sws_scale(_swsContext, _frame->data, _frame->linesize, 0, _frame->height, toData, toLinesize); } - if (hasAlpha) { + if (bgra) { FFmpeg::PremultiplyInplace(to); } if (_rotation != Rotation::None) { @@ -391,6 +403,19 @@ bool FFMpegReaderImplementation::isGifv() const { return true; } +bool FFMpegReaderImplementation::isWebmSticker() const { + if (_hasAudioStream) { + return false; + } + if (dataSize() > kMaxInMemory) { + return false; + } + if (_codecContext->codec_id != AV_CODEC_ID_VP9) { + return false; + } + return true; +} + QString FFMpegReaderImplementation::logData() const { return u"for file '%1', data size '%2'"_q.arg(_location ? _location->name() : QString()).arg(_data->size()); } diff --git a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.h b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.h index 03d96ff0e..4d5493f40 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.h +++ b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.h @@ -43,6 +43,7 @@ public: QString logData() const; bool isGifv() const; + bool isWebmSticker() const; ~FFMpegReaderImplementation(); diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp index a36758720..2c2552c2a 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp @@ -845,6 +845,7 @@ Ui::PreparedFileInformation::Video PrepareForSending(const QString &fname, const auto durationMs = reader->durationMs(); if (durationMs > 0) { result.isGifv = reader->isGifv(); + result.isWebmSticker = reader->isWebmSticker(); // Use first video frame as a thumbnail. // All other apps and server do that way. //if (!result.isGifv) { @@ -857,7 +858,7 @@ Ui::PreparedFileInformation::Video PrepareForSending(const QString &fname, const auto readResult = reader->readFramesTill(-1, crl::now()); auto readFrame = (readResult == internal::ReaderImplementation::ReadResult::Success); if (readFrame && reader->renderFrame(result.thumbnail, hasAlpha, QSize())) { - if (hasAlpha) { + if (hasAlpha && !result.isWebmSticker) { auto cacheForResize = QImage(); auto request = FrameRequest(); request.framew = request.outerw = result.thumbnail.width(); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_common.h b/Telegram/SourceFiles/media/streaming/media_streaming_common.h index 49d85410b..8d42fa599 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_common.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_common.h @@ -121,6 +121,7 @@ struct FrameRequest { ImageRoundRadius radius = ImageRoundRadius(); RectParts corners = RectPart::AllCorners; bool requireARGB32 = true; + bool keepAlpha = false; bool strict = true; static FrameRequest NonStrict() { @@ -138,6 +139,7 @@ struct FrameRequest { && (outer == other.outer) && (radius == other.radius) && (corners == other.corners) + && (keepAlpha == other.keepAlpha) && (requireARGB32 == other.requireARGB32); } [[nodiscard]] bool operator!=(const FrameRequest &other) const { @@ -146,6 +148,7 @@ struct FrameRequest { [[nodiscard]] bool goodFor(const FrameRequest &other) const { return (requireARGB32 == other.requireARGB32) + && (keepAlpha == other.keepAlpha) && ((*this == other) || (strict && !other.strict)); } }; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp index 951f66a8a..172347efc 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp @@ -89,9 +89,10 @@ FFmpeg::AvErrorWrap ReadNextFrame(Stream &stream) { bool GoodForRequest( const QImage &image, + bool hasAlpha, int rotation, const FrameRequest &request) { - if (image.isNull()) { + if (image.isNull() || (hasAlpha && !request.keepAlpha)) { return false; } else if (request.resize.isEmpty()) { return true; @@ -170,6 +171,10 @@ QImage ConvertFrame( frame->height, data, linesize); + + if (frame->format == AV_PIX_FMT_YUVA420P) { + FFmpeg::PremultiplyInplace(storage); + } } FFmpeg::ClearFrameMemory(frame); @@ -274,8 +279,11 @@ void PaintFrameContent( (full.height() - size.height()) / 2, size.width(), size.height()); - PaintFrameOuter(p, to, full); - PaintFrameInner(p, to, original, alpha, rotation); + if (!alpha || !request.keepAlpha) { + PaintFrameOuter(p, to, full); + } + const auto deAlpha = alpha && !request.keepAlpha; + PaintFrameInner(p, to, original, deAlpha, rotation); } void ApplyFrameRounding(QImage &storage, const FrameRequest &request) { @@ -304,6 +312,10 @@ QImage PrepareByRequest( storage = FFmpeg::CreateFrameStorage(outer); } + if (alpha && request.keepAlpha) { + storage.fill(Qt::transparent); + } + QPainter p(&storage); PaintFrameContent(p, original, alpha, rotation, request); p.end(); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.h b/Telegram/SourceFiles/media/streaming/media_streaming_utility.h index 6a0769c26..b581fee3e 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.h @@ -51,6 +51,7 @@ struct Stream { [[nodiscard]] bool GoodForRequest( const QImage &image, + bool hasAlpha, int rotation, const FrameRequest &request); [[nodiscard]] QImage ConvertFrame( diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index ba0e4b586..f510b31e0 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -444,7 +444,8 @@ void VideoTrackObject::rasterizeFrame(not_null frame) { } frame->format = FrameFormat::YUV420; } else { - frame->alpha = (frame->decoded->format == AV_PIX_FMT_BGRA); + frame->alpha = (frame->decoded->format == AV_PIX_FMT_BGRA) + || (frame->decoded->format == AV_PIX_FMT_YUVA420P); frame->yuv420.size = { frame->decoded->width, frame->decoded->height @@ -1110,8 +1111,11 @@ QImage VideoTrack::frame( && frame->format == FrameFormat::YUV420) { frame->original = ConvertToARGB32(frame->yuv420); } - if (!frame->alpha - && GoodForRequest(frame->original, _streamRotation, useRequest)) { + if (GoodForRequest( + frame->original, + frame->alpha, + _streamRotation, + useRequest)) { return frame->original; } else if (changed || none || i->second.image.isNull()) { const auto j = none @@ -1187,8 +1191,11 @@ void VideoTrack::PrepareFrameByRequests( const auto end = frame->prepared.end(); for (auto i = begin; i != end; ++i) { auto &prepared = i->second; - if (frame->alpha - || !GoodForRequest(frame->original, rotation, prepared.request)) { + if (!GoodForRequest( + frame->original, + frame->alpha, + rotation, + prepared.request)) { auto j = begin; for (; j != i; ++j) { if (j->second.request == prepared.request) { diff --git a/Telegram/SourceFiles/storage/localimageloader.cpp b/Telegram/SourceFiles/storage/localimageloader.cpp index e3dfe5d3c..dd63aeba8 100644 --- a/Telegram/SourceFiles/storage/localimageloader.cpp +++ b/Telegram/SourceFiles/storage/localimageloader.cpp @@ -619,6 +619,7 @@ bool FileLoadTask::CheckForVideo( static const auto extensions = { qstr(".mp4"), qstr(".mov"), + qstr(".webm"), }; if (!CheckMimeOrExtensions(filepath, result->filemime, mimes, extensions)) { return false; diff --git a/Telegram/SourceFiles/storage/storage_media_prepare.cpp b/Telegram/SourceFiles/storage/storage_media_prepare.cpp index 7893d7ad7..084d5af13 100644 --- a/Telegram/SourceFiles/storage/storage_media_prepare.cpp +++ b/Telegram/SourceFiles/storage/storage_media_prepare.cpp @@ -298,7 +298,7 @@ void PrepareDetails(PreparedFile &file, int previewWidth) { UpdateImageDetails(file, previewWidth); file.type = PreparedFile::Type::Photo; } else if (Core::IsMimeSticker(file.information->filemime) - || image->animated) { + || image->animated) { file.type = PreparedFile::Type::None; } } else if (const auto video = std::get_if