diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 6a07e63e2..853804b8e 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/platform_specific.h" #include "base/platform/base_platform_info.h" #include "base/power_save_blocker.h" +#include "media/streaming/media_streaming_utility.h" #include "window/main_window.h" #include "webrtc/webrtc_video_track.h" #include "webrtc/webrtc_media_devices.h" @@ -335,16 +336,10 @@ void Panel::refreshIncomingGeometry() { return; } const auto to = widget()->size(); - const auto small = _incomingFrameSize.scaled(to, Qt::KeepAspectRatio); - const auto big = _incomingFrameSize.scaled( + const auto use = ::Media::Streaming::DecideFrameResize( to, - Qt::KeepAspectRatioByExpanding); - - // If we cut out no more than 0.25 of the original, let's use expanding. - const auto use = ((big.width() * 3 <= to.width() * 4) - && (big.height() * 3 <= to.height() * 4)) - ? big - : small; + _incomingFrameSize + ).result; const auto pos = QPoint( (to.width() - use.width()) / 2, (to.height() - use.height()) / 2); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index a7b9b7b9e..9aa0a96b1 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/group/calls_group_viewport_tile.h" #include "webrtc/webrtc_video_track.h" #include "media/view/media_view_pip.h" +#include "media/streaming/media_streaming_utility.h" #include "calls/group/calls_group_members_row.h" #include "lang/lang_keys.h" #include "ui/gl/gl_shader.h" @@ -31,7 +32,6 @@ constexpr auto kNoiseTextureSize = 256; constexpr auto kBlurTextureSizeFactor = 4.; constexpr auto kBlurOpacity = 0.65; constexpr auto kDitherNoiseAmount = 0.002; -constexpr auto kMinCameraVisiblePart = 0.75; constexpr auto kQuads = 9; constexpr auto kQuadVertices = kQuads * 4; @@ -224,13 +224,8 @@ vec4 background() { } [[nodiscard]] bool UseExpandForCamera(QSize original, QSize viewport) { - const auto big = original.scaled( - viewport, - Qt::KeepAspectRatioByExpanding); - - // If we cut out no more than 0.25 of the original, let's use expanding. - return (big.width() * kMinCameraVisiblePart <= viewport.width()) - && (big.height() * kMinCameraVisiblePart <= viewport.height()); + using namespace ::Media::Streaming; + return DecideFrameResize(viewport, original).expanding; } [[nodiscard]] QSize NonEmpty(QSize size) { diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp index 2335e181e..091ab66d8 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp @@ -482,6 +482,10 @@ bool RotationSwapWidthHeight(int rotation) { return (rotation == 90 || rotation == 270); } +QSize TransposeSizeByRotation(QSize size, int rotation) { + return RotationSwapWidthHeight(rotation) ? size.transposed() : size; +} + bool GoodStorageForFrame(const QImage &storage, QSize size) { return !storage.isNull() && (storage.format() == kImageFormat) diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h index 5e334b0e0..dd2f359aa 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h @@ -180,6 +180,7 @@ void LogError(QLatin1String method, FFmpeg::AvErrorWrap error); [[nodiscard]] int ReadRotationFromMetadata(not_null stream); [[nodiscard]] AVRational ValidateAspectRatio(AVRational aspect); [[nodiscard]] bool RotationSwapWidthHeight(int rotation); +[[nodiscard]] QSize TransposeSizeByRotation(QSize size, int rotation); [[nodiscard]] QSize CorrectByAspect(QSize size, AVRational aspect); [[nodiscard]] bool GoodStorageForFrame(const QImage &storage, QSize size); diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index 3d6e9a875..d4d1d6466 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -142,6 +142,28 @@ void PaintWaveform( } } +[[nodiscard]] int MaxStatusWidth(not_null document) { + using namespace Ui; + auto result = 0; + const auto add = [&](const QString &text) { + accumulate_max(result, st::normalFont->width(text)); + }; + add(FormatDownloadText(document->size, document->size)); + const auto duration = document->getDuration(); + if (const auto song = document->song()) { + add(FormatPlayedText(duration, duration)); + add(FormatDurationAndSizeText(duration, document->size)); + } else if (const auto voice = document->voice()) { + add(FormatPlayedText(duration, duration)); + add(FormatDurationAndSizeText(duration, document->size)); + } else if (document->isVideoFile()) { + add(FormatDurationAndSizeText(duration, document->size)); + } else { + add(FormatSizeText(document->size)); + } + return result; +} + } // namespace Document::Document( @@ -317,10 +339,10 @@ QSize Document::countOptimalSize() { const auto tleft = st.padding.left() + st.thumbSize + st.padding.right(); const auto tright = st.padding.left(); if (thumbed) { - accumulate_max(maxWidth, tleft + documentMaxStatusWidth(_data) + tright); + accumulate_max(maxWidth, tleft + MaxStatusWidth(_data) + tright); } else { auto unread = _data->isVoiceMessage() ? (st::mediaUnreadSkip + st::mediaUnreadSize) : 0; - accumulate_max(maxWidth, tleft + documentMaxStatusWidth(_data) + unread + _parent->skipBlockWidth() + st::msgPadding.right()); + accumulate_max(maxWidth, tleft + MaxStatusWidth(_data) + unread + _parent->skipBlockWidth() + st::msgPadding.right()); } if (auto named = Get()) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_game.cpp b/Telegram/SourceFiles/history/view/media/history_view_game.cpp index 859ca1961..a809c427b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_game.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_game.cpp @@ -48,7 +48,7 @@ Game::Game( } QSize Game::countOptimalSize() { - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); const auto item = _parent->data(); if (!_openl && item->isRegular()) { @@ -149,7 +149,7 @@ QSize Game::countCurrentSize(int newWidth) { // enable any count of lines in game description / message auto linesMax = 4096; - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); auto newHeight = 0; if (_title.isEmpty()) { _titleLines = 0; @@ -225,7 +225,7 @@ void Game::draw(Painter &p, const PaintContext &context) const { QRect bar(style::rtlrect(st::msgPadding.left(), tshift, st::webPageBar, height() - tshift - bshift, width())); p.fillRect(bar, barfg); - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); if (_titleLines) { p.setPen(semibold); p.setTextPalette(stm->semiboldPalette); @@ -301,7 +301,7 @@ TextState Game::textState(QPoint point, StateRequest request) const { auto inThumb = false; auto symbolAdd = 0; - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); if (_titleLines) { if (point.y() >= tshift && point.y() < tshift + _titleLines * lineHeight) { Ui::Text::StateRequestElided titleRequest = request.forText(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 9e6dfb609..524aac032 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/player/media_player_instance.h" #include "media/streaming/media_streaming_instance.h" #include "media/streaming/media_streaming_player.h" +#include "media/streaming/media_streaming_utility.h" #include "media/view/media_view_playback_progress.h" #include "ui/boxes/confirm_box.h" #include "history/history_item_components.h" @@ -147,21 +148,23 @@ QSize Gif::countOptimalSize() { auto thumbMaxWidth = st::msgMaxWidth; const auto scaled = countThumbSize(thumbMaxWidth); - _thumbw = scaled.width(); - _thumbh = scaled.height(); + const auto minWidthByInfo = _parent->infoWidth() + + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()); auto maxWidth = std::clamp( - std::max(_thumbw, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())), + std::max(scaled.width(), minWidthByInfo), st::minPhotoSize, thumbMaxWidth); - auto minHeight = qMax(_thumbh, st::minPhotoSize); + auto minHeight = qMax(scaled.height(), st::minPhotoSize); if (!activeCurrentStreamed()) { accumulate_max(maxWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); } if (_parent->hasBubble()) { accumulate_max(maxWidth, _parent->minWidthForMedia()); if (!_caption.isEmpty()) { - auto captionw = maxWidth - st::msgPadding.left() - st::msgPadding.right(); - minHeight += st::mediaCaptionSkip + _caption.countHeight(captionw); + maxWidth = qMax(maxWidth, st::msgPadding.left() + + _caption.maxWidth() + + st::msgPadding.right()); + minHeight += st::mediaCaptionSkip + _caption.minHeight(); if (isBubbleBottom()) { minHeight += st::msgPadding.bottom(); } @@ -185,21 +188,28 @@ QSize Gif::countCurrentSize(int newWidth) { auto thumbMaxWidth = newWidth; const auto scaled = countThumbSize(thumbMaxWidth); - _thumbw = scaled.width(); - _thumbh = scaled.height(); - + const auto minWidthByInfo = _parent->infoWidth() + + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x()); newWidth = std::clamp( - std::max(_thumbw, _parent->infoWidth() + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())), + std::max(scaled.width(), minWidthByInfo), st::minPhotoSize, thumbMaxWidth); - auto newHeight = qMax(_thumbh, st::minPhotoSize); + auto newHeight = qMax(scaled.height(), st::minPhotoSize); if (!activeCurrentStreamed()) { accumulate_max(newWidth, gifMaxStatusWidth(_data) + 2 * (st::msgDateImgDelta + st::msgDateImgPadding.x())); } if (_parent->hasBubble()) { accumulate_max(newWidth, _parent->minWidthForMedia()); if (!_caption.isEmpty()) { - auto captionw = newWidth - st::msgPadding.left() - st::msgPadding.right(); + const auto maxWithCaption = qMin( + st::msgMaxWidth, + (st::msgPadding.left() + + _caption.maxWidth() + + st::msgPadding.right())); + newWidth = qMax(newWidth, maxWithCaption); + const auto captionw = newWidth + - st::msgPadding.left() + - st::msgPadding.right(); newHeight += st::mediaCaptionSkip + _caption.countHeight(captionw); if (isBubbleBottom()) { newHeight += st::msgPadding.bottom(); @@ -380,11 +390,12 @@ void Gif::draw(Painter &p, const PaintContext &context) const { displayMute = true; } } - auto request = ::Media::Streaming::FrameRequest(); - request.outer = QSize(usew, painth) * cIntRetinaFactor(); - request.resize = QSize(_thumbw, _thumbh) * cIntRetinaFactor(); - request.corners = roundCorners; - request.radius = roundRadius; + auto request = ::Media::Streaming::FrameRequest{ + .outer = QSize(usew, painth) * cIntRetinaFactor(), + .radius = roundRadius, + .corners = roundCorners, + .blurredBackground = true, + }; if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) { if (activeOwnPlaying->frozenFrame.isNull()) { activeOwnPlaying->frozenRequest = request; @@ -433,49 +444,8 @@ void Gif::draw(Painter &p, const PaintContext &context) const { } } else if (!skipDrawingContent) { ensureDataMediaCreated(); - const auto size = QSize(_thumbw, _thumbh); - const auto args = Images::PrepareArgs{ - .options = Images::RoundOptions(roundRadius, roundCorners), - .outer = QSize(usew, painth), - }; - if (const auto good = _dataMedia->goodThumbnail()) { - p.drawPixmap(rthumb.topLeft(), good->pixSingle(size, args)); - } else { - const auto normal = _dataMedia->thumbnail(); - if (normal) { - const auto blurred = (normal->width() < kUseNonBlurredThreshold) - && (normal->height() < kUseNonBlurredThreshold); - p.drawPixmap( - rthumb.topLeft(), - normal->pixSingle(size, blurred ? args.blurred() : args)); - } else { - _data->loadThumbnail(_realParent->fullId()); - validateVideoThumbnail(); - if (_videoThumbnailFrame) { - p.drawPixmap(rthumb.topLeft(), _videoThumbnailFrame->pixSingle(size, args)); - } else if (const auto blurred = _dataMedia->thumbnailInline()) { - p.drawPixmap(rthumb.topLeft(), blurred->pixSingle(size, args.blurred())); - } else if (!unwrapped) { - if (roundRadius == ImageRoundRadius::Ellipse) { - PainterHighQualityEnabler hq(p); - p.setPen(Qt::NoPen); - p.setBrush(st->imageBg()); - p.drawEllipse(rthumb); - } else { - const auto roundTop = (roundCorners & RectPart::TopLeft); - const auto roundBottom = (roundCorners & RectPart::BottomLeft); - const auto margin = inWebPage - ? st::roundRadiusSmall - : st::historyMessageRadius; - const auto parts = roundCorners - | RectPart::NoTopBottom - | (roundTop ? RectPart::Top : RectPart::None) - | (roundBottom ? RectPart::Bottom : RectPart::None); - Ui::FillRoundRect(p, rthumb.marginsAdded({ 0, roundTop ? 0 : margin, 0, roundBottom ? 0 : margin }), st->imageBg(), roundRadius, parts); - } - } - } - } + validateThumbCache({ usew, painth }, roundRadius, roundCorners); + p.drawImage(rthumb, _thumbCache); } if (context.selected()) { @@ -688,6 +658,74 @@ void Gif::validateVideoThumbnail() const { : info.thumbnail); } +void Gif::validateThumbCache( + QSize outer, + ImageRoundRadius radius, + RectParts corners) const { + const auto intRadius = static_cast(radius); + const auto intCorners = static_cast(corners); + const auto good = _dataMedia->goodThumbnail(); + const auto normal = good ? good : _dataMedia->thumbnail(); + if (!normal) { + _data->loadThumbnail(_realParent->fullId()); + validateVideoThumbnail(); + } + const auto videothumb = normal ? nullptr : _videoThumbnailFrame.get(); + const auto blurred = normal + ? (!good + && (normal->width() < kUseNonBlurredThreshold) + && (normal->height() < kUseNonBlurredThreshold)) + : !videothumb; + const auto ratio = style::DevicePixelRatio(); + const auto shouldBeBlurred = blurred ? 1 : 0; + if (_thumbCache.size() == (outer * ratio) + && _thumbCacheRoundRadius == intRadius + && _thumbCacheRoundCorners == intCorners + && _thumbCacheBlurred == shouldBeBlurred) { + return; + } + _thumbCache = prepareThumbCache(outer, radius, corners); + _thumbCacheRoundRadius = intRadius; + _thumbCacheRoundCorners = intCorners; + _thumbCacheBlurred = shouldBeBlurred; +} + +QImage Gif::prepareThumbCache( + QSize outer, + ImageRoundRadius radius, + RectParts corners) const { + return Images::Round(prepareThumbCache(outer), radius, corners); +} + +QImage Gif::prepareThumbCache(QSize outer) const { + const auto good = _dataMedia->goodThumbnail(); + const auto normal = good ? good : _dataMedia->thumbnail(); + const auto videothumb = normal ? nullptr : _videoThumbnailFrame.get(); + const auto ratio = style::DevicePixelRatio(); + auto blurred = (!good + && normal + && (normal->width() < kUseNonBlurredThreshold) + && (normal->height() < kUseNonBlurredThreshold)) + ? normal + : nullptr; + const auto blurFromLarge = good || (normal && !blurred); + const auto large = blurFromLarge ? normal : videothumb; + if (videothumb) { + } else if (const auto embedded = _dataMedia->thumbnailInline()) { + blurred = embedded; + } + const auto resize = large + ? ::Media::Streaming::DecideVideoFrameResize( + outer, + good ? large->size() : _data->dimensions) + : ::Media::Streaming::ExpandDecision(); + return PrepareWithBlurredBackground( + outer, + resize, + large, + blurFromLarge ? large : blurred); +} + void Gif::drawCornerStatus( Painter &p, const PaintContext &context, @@ -996,17 +1034,18 @@ void Gif::drawGrouped( if (streamed) { const auto paused = autoPaused; - auto request = ::Media::Streaming::FrameRequest(); const auto original = sizeForAspectRatio(); const auto originalWidth = style::ConvertScale(original.width()); const auto originalHeight = style::ConvertScale(original.height()); const auto pixSize = Ui::GetImageScaleSizeForGeometry( { originalWidth, originalHeight }, { geometry.width(), geometry.height() }); - request.outer = geometry.size() * cIntRetinaFactor(); - request.resize = pixSize * cIntRetinaFactor(); - request.corners = corners; - request.radius = roundRadius; + auto request = ::Media::Streaming::FrameRequest{ + .resize = pixSize * cIntRetinaFactor(), + .outer = geometry.size() * cIntRetinaFactor(), + .radius = roundRadius, + .corners = corners, + }; if (activeOwnPlaying->instance.playerLocked()) { if (activeOwnPlaying->frozenFrame.isNull()) { activeOwnPlaying->frozenRequest = request; @@ -1408,6 +1447,7 @@ bool Gif::hasHeavyPart() const { void Gif::unloadHeavyPart() { stopAnimation(); _dataMedia = nullptr; + _thumbCache = QImage(); _videoThumbnailFrame = nullptr; _caption.unloadCustomEmoji(); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index 0d771d02c..19513e93a 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -158,6 +158,16 @@ private: [[nodiscard]] int additionalWidth() const; [[nodiscard]] bool isUnwrapped() const; + void validateThumbCache( + QSize outer, + ImageRoundRadius radius, + RectParts corners) const; + [[nodiscard]] QImage prepareThumbCache( + QSize outer, + ImageRoundRadius radius, + RectParts corners) const; + [[nodiscard]] QImage prepareThumbCache(QSize outer) const; + void validateGroupedCache( const QRect &geometry, RectParts corners, @@ -178,13 +188,15 @@ private: QPoint position) const; const not_null _data; - int _thumbw = 1; - int _thumbh = 1; Ui::Text::String _caption; std::unique_ptr _streamed; mutable std::shared_ptr _dataMedia; mutable std::unique_ptr _videoThumbnailFrame; QString _downloadSize; + mutable QImage _thumbCache; + mutable int _thumbCacheRoundRadius : 4 = 0; + mutable int _thumbCacheRoundCorners : 12 = 0; + mutable int _thumbCacheBlurred : 1 = 0; }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_invoice.cpp b/Telegram/SourceFiles/history/view/media/history_view_invoice.cpp index cf9dd097b..ff0432876 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_invoice.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_invoice.cpp @@ -83,7 +83,7 @@ void Invoice::fillFromData(not_null invoice) { } QSize Invoice::countOptimalSize() { - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); if (_attach) { if (_status.hasSkipBlock()) { @@ -139,7 +139,7 @@ QSize Invoice::countCurrentSize(int newWidth) { accumulate_min(newWidth, maxWidth()); auto innerWidth = newWidth - st::msgPadding.left() - st::msgPadding.right(); - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); auto newHeight = 0; if (_title.isEmpty()) { @@ -211,7 +211,7 @@ void Invoice::draw(Painter &p, const PaintContext &context) const { auto tshift = padding.top(); paintw -= padding.left() + padding.right(); - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); if (_titleHeight) { p.setPen(semibold); p.setTextPalette(stm->semiboldPalette); @@ -283,7 +283,7 @@ TextState Invoice::textState(QPoint point, StateRequest request) const { } paintw -= padding.left() + padding.right(); - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); auto symbolAdd = 0; if (_titleHeight) { if (point.y() >= tshift && point.y() < tshift + _titleHeight) { diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp index f21a7be1c..e6b6f2448 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp @@ -18,27 +18,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_document.h" #include "history/view/media/history_view_sticker.h" #include "history/view/media/history_view_theme_document.h" +#include "media/streaming/media_streaming_utility.h" #include "styles/style_chat.h" namespace HistoryView { -int documentMaxStatusWidth(DocumentData *document) { - auto result = st::normalFont->width(Ui::FormatDownloadText(document->size, document->size)); - const auto duration = document->getDuration(); - if (const auto song = document->song()) { - accumulate_max(result, st::normalFont->width(Ui::FormatPlayedText(duration, duration))); - accumulate_max(result, st::normalFont->width(Ui::FormatDurationAndSizeText(duration, document->size))); - } else if (const auto voice = document->voice()) { - accumulate_max(result, st::normalFont->width(Ui::FormatPlayedText(duration, duration))); - accumulate_max(result, st::normalFont->width(Ui::FormatDurationAndSizeText(duration, document->size))); - } else if (document->isVideoFile()) { - accumulate_max(result, st::normalFont->width(Ui::FormatDurationAndSizeText(duration, document->size))); - } else { - accumulate_max(result, st::normalFont->width(Ui::FormatSizeText(document->size))); - } - return result; -} - void PaintInterpolatedIcon( Painter &p, const style::icon &a, @@ -105,8 +89,49 @@ std::unique_ptr CreateAttach( return nullptr; } -int unitedLineHeight() { - return qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height); +int UnitedLineHeight() { + return std::max(st::semiboldFont->height, st::normalFont->height); +} + +QImage PrepareWithBlurredBackground( + QSize outer, + ::Media::Streaming::ExpandDecision resize, + Image *large, + Image *blurred) { + const auto ratio = style::DevicePixelRatio(); + if (resize.expanding) { + return Images::Prepare(large->original(), resize.result * ratio, { + .outer = outer, + }); + } + auto background = QImage( + outer * ratio, + QImage::Format_ARGB32_Premultiplied); + background.setDevicePixelRatio(ratio); + if (!blurred) { + background.fill(Qt::black); + if (!large) { + return background; + } + } + auto p = QPainter(&background); + if (blurred) { + using namespace ::Media::Streaming; + FillBlurredBackground(p, outer, blurred->original()); + } + if (large) { + auto image = large->original().scaled( + resize.result * ratio, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); + image.setDevicePixelRatio(ratio); + p.drawImage( + (outer.width() - resize.result.width()) / 2, + (outer.height() - resize.result.height()) / 2, + image); + } + p.end(); + return background; } } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_common.h b/Telegram/SourceFiles/history/view/media/history_view_media_common.h index a16ccb017..5c9a83173 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_common.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_common.h @@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +class DocumentData; +class PhotoData; +class Image; + namespace HistoryView { class Element; } // namespace HistoryView @@ -15,15 +19,14 @@ namespace Data { class Media; } // namespace Data -class DocumentData; -class PhotoData; +namespace Media::Streaming { +struct ExpandDecision; +} // namespace Media::Streaming namespace HistoryView { class Media; -int documentMaxStatusWidth(DocumentData *document); - void PaintInterpolatedIcon( Painter &p, const style::icon &a, @@ -41,7 +44,7 @@ void PaintInterpolatedIcon( PhotoData *photo, const std::vector> &collage, const QString &webpageUrl); -int unitedLineHeight(); +[[nodiscard]] int UnitedLineHeight(); [[nodiscard]] inline QSize NonEmptySize(QSize size) { return QSize(std::max(size.width(), 1), std::max(size.height(), 1)); @@ -54,4 +57,10 @@ int unitedLineHeight(); : size)); } +[[nodiscard]] QImage PrepareWithBlurredBackground( + QSize outer, + ::Media::Streaming::ExpandDecision resize, + Image *large, + Image *blurred); + } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 93495ac5d..11aa7160f 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/streaming/media_streaming_instance.h" #include "media/streaming/media_streaming_player.h" #include "media/streaming/media_streaming_document.h" +#include "media/streaming/media_streaming_utility.h" #include "main/main_session.h" #include "main/main_session_settings.h" #include "ui/image/image.h" @@ -185,7 +186,7 @@ QSize Photo::countOptimalSize() { return { maxWidth, minHeight }; } -QSize Photo::countCurrentSize(int newWidth) { +QSize Photo::pixmapSizeFromData(int newWidth) const { auto tw = style::ConvertScale(_data->width()); auto th = style::ConvertScale(_data->height()); if (tw > st::maxMediaSize) { @@ -197,33 +198,38 @@ QSize Photo::countCurrentSize(int newWidth) { th = st::maxMediaSize; } - _pixw = qMin(newWidth, maxWidth()); - _pixh = th; - if (tw > _pixw) { - _pixh = (_pixw * _pixh / tw); + auto pixw = qMin(newWidth, maxWidth()); + auto pixh = th; + if (tw > pixw) { + pixh = (pixw * pixh / tw); } else { - _pixw = tw; + pixw = tw; } - if (_pixh > newWidth) { - _pixw = (_pixw * newWidth) / _pixh; - _pixh = newWidth; + if (pixh > newWidth) { + pixw = (pixw * newWidth) / pixh; + pixh = newWidth; } - if (_pixw < 1) _pixw = 1; - if (_pixh < 1) _pixh = 1; + return { pixw, pixh }; +} +QSize Photo::countCurrentSize(int newWidth) { + if (_serviceWidth) { + return { _serviceWidth, _serviceWidth }; + } const auto minWidth = std::clamp( _parent->minWidthForMedia(), (_parent->hasBubble() ? st::historyPhotoBubbleMinWidth : st::minPhotoSize), std::min(newWidth, st::maxMediaSize)); - newWidth = qMax(_pixw, minWidth); - auto newHeight = qMax(_pixh, st::minPhotoSize); + auto pix = pixmapSizeFromData(newWidth); + newWidth = qMax(pix.width(), minWidth); + auto newHeight = qMax(pix.height(), st::minPhotoSize); if (_parent->hasBubble() && !_caption.isEmpty()) { const auto maxWithCaption = qMin( st::msgMaxWidth, (st::msgPadding.left() + _caption.maxWidth() + st::msgPadding.right())); - newWidth = qMin(maxWidth(), maxWithCaption); + newWidth = qMax(newWidth, maxWithCaption); const auto captionw = newWidth - st::msgPadding.left() - st::msgPadding.right(); @@ -390,68 +396,10 @@ QImage Photo::prepareImageCache(QSize outer) const { } else { blurred = large; } - if (large) { - const auto from = large->size(); - // If we cut out no more than 0.25 of the original, let's expand. - const auto big = from.scaled(outer, Qt::KeepAspectRatioByExpanding); - if ((big.width() * 3 <= outer.width() * 4) - && (big.height() * 3 <= outer.height() * 4)) { - return Images::Prepare(large->original(), big * ratio, { - .outer = outer, - }); - } - } - auto background = QImage( - outer * ratio, - QImage::Format_ARGB32_Premultiplied); - background.setDevicePixelRatio(ratio); - if (!blurred) { - background.fill(Qt::black); - return background; - } - const auto bsize = blurred->size(); - const auto copyw = std::min( - bsize.width(), - outer.width() * bsize.height() / outer.height()); - const auto copyh = std::min( - bsize.height(), - outer.height() * bsize.width() / outer.width()); - auto copy = (bsize == QSize(copyw, copyh)) - ? blurred->original() - : blurred->original().copy( - (bsize.width() - copyw) / 2, - (bsize.height() - copyh) / 2, - copyw, - copyh); - auto scaled = Images::Blur((outer.width() < 10 - || outer.height() < 10 - || (copy.width() * 5 < background.width() - && copy.height() * 5 < background.height())) - ? std::move(copy) - : copy.scaled( - std::min(copy.width(), background.width() / 5), - std::min(copy.height(), background.height() / 5), - Qt::KeepAspectRatio, - Qt::FastTransformation)); - auto p = QPainter(&background); - { - auto hq = PainterHighQualityEnabler(p); - p.drawImage(QRect(QPoint(), outer), scaled); - } - if (large) { - auto image = large->original().scaled( - background.size(), - Qt::KeepAspectRatio, - Qt::SmoothTransformation); - image.setDevicePixelRatio(ratio); - const auto size = image.size() / ratio; - p.drawImage( - (outer.width() - size.width()) / 2, - (outer.height() - size.height()) / 2, - image); - } - p.end(); - return background; + const auto resize = large + ? ::Media::Streaming::DecideFrameResize(outer, large->size()) + : ::Media::Streaming::ExpandDecision(); + return PrepareWithBlurredBackground(outer, resize, large, blurred); } void Photo::paintUserpicFrame( @@ -466,7 +414,7 @@ void Photo::paintUserpicFrame( checkStreamedIsStarted(); } - const auto size = QSize(_pixw, _pixh); + const auto size = QSize(width(), height()); const auto rect = QRect(photoPosition, size); const auto st = context.st; const auto sti = context.imageStyle(); diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index 75d3dbd06..c0cc03461 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -116,6 +116,7 @@ private: QSize countOptimalSize() override; QSize countCurrentSize(int newWidth) override; + [[nodiscard]] QSize pixmapSizeFromData(int newWidth) const; bool needInfoDisplay() const; void validateGroupedCache( @@ -152,8 +153,6 @@ private: mutable std::unique_ptr _streamed; mutable QImage _imageCache; int _serviceWidth = 0; - int _pixw = 1; - int _pixh = 1; mutable int _imageCacheRoundRadius : 4 = 0; mutable int _imageCacheRoundCorners : 12 = 0; mutable int _imageCacheBlurred : 1 = 0; diff --git a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp index af991bfb9..1090ffecb 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_web_page.cpp @@ -106,7 +106,7 @@ QSize WebPage::countOptimalSize() { _title = Ui::Text::String(st::msgMinWidth - st::webPageLeft); _description = Ui::Text::String(st::msgMinWidth - st::webPageLeft); } - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); if (!_openl && !_data->url.isEmpty()) { const auto previewOfHiddenUrl = [&] { @@ -328,7 +328,7 @@ QSize WebPage::countCurrentSize(int newWidth) { auto innerWidth = newWidth - st::msgPadding.left() - st::webPageLeft - st::msgPadding.right(); auto newHeight = 0; - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); auto linesMax = isLogEntryOriginal() ? kMaxOriginalEntryLines : 5; auto siteNameHeight = _siteNameLines ? lineHeight : 0; if (asArticle()) { @@ -498,7 +498,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const { QRect bar(style::rtlrect(st::msgPadding.left(), tshift, st::webPageBar, height() - tshift - bshift, width())); p.fillRect(bar, barfg); - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); if (asArticle()) { ensurePhotoMediaCreated(); @@ -650,7 +650,7 @@ TextState WebPage::textState(QPoint point, StateRequest request) const { } paintw -= padding.left() + padding.right(); - auto lineHeight = unitedLineHeight(); + auto lineHeight = UnitedLineHeight(); auto inThumb = false; if (asArticle()) { auto pw = qMax(_pixw, lineHeight); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_common.h b/Telegram/SourceFiles/media/streaming/media_streaming_common.h index 3fdb120a4..6baba93c4 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_common.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_common.h @@ -123,6 +123,7 @@ struct FrameRequest { ImageRoundRadius radius = ImageRoundRadius(); RectParts corners = RectPart::AllCorners; QColor colored = QColor(0, 0, 0, 0); + bool blurredBackground = false; bool requireARGB32 = true; bool keepAlpha = false; bool strict = true; @@ -134,7 +135,7 @@ struct FrameRequest { } [[nodiscard]] bool empty() const { - return resize.isEmpty(); + return blurredBackground ? outer.isEmpty() : resize.isEmpty(); } [[nodiscard]] bool operator==(const FrameRequest &other) const { @@ -144,14 +145,16 @@ struct FrameRequest { && (corners == other.corners) && (colored == other.colored) && (keepAlpha == other.keepAlpha) - && (requireARGB32 == other.requireARGB32); + && (requireARGB32 == other.requireARGB32) + && (blurredBackground == other.blurredBackground); } [[nodiscard]] bool operator!=(const FrameRequest &other) const { return !(*this == other); } [[nodiscard]] bool goodFor(const FrameRequest &other) const { - return (requireARGB32 == other.requireARGB32) + return (blurredBackground == other.blurredBackground) + && (requireARGB32 == other.requireARGB32) && (keepAlpha == other.keepAlpha) && (colored == other.colored) && ((strict && !other.strict) || (*this == other)); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp index 508f87210..6a815e888 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp @@ -177,7 +177,8 @@ Stream File::Context::initStream( return result; } result.rotation = FFmpeg::ReadRotationFromMetadata(info); - result.aspect = FFmpeg::ValidateAspectRatio(info->sample_aspect_ratio); + result.aspect = FFmpeg::ValidateAspectRatio( + info->sample_aspect_ratio); } else if (type == AVMEDIA_TYPE_AUDIO) { result.frequency = info->codecpar->sample_rate; if (!result.frequency) { diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp index 7f1e2f4b1..238a52fa1 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp @@ -96,7 +96,7 @@ bool GoodForRequest( || (hasAlpha && !request.keepAlpha) || request.colored.alpha() != 0) { return false; - } else if (request.resize.isEmpty()) { + } else if (!request.blurredBackground && request.resize.isEmpty()) { return true; } else if (rotation != 0) { return false; @@ -104,8 +104,10 @@ bool GoodForRequest( && ((request.corners & RectPart::AllCorners) != 0)) { return false; } - return (request.resize == request.outer) - && (request.resize == image.size()); + const auto size = request.blurredBackground + ? request.outer + : request.resize; + return (size == request.outer) && (size == image.size()); } bool TransferFrame( @@ -279,28 +281,69 @@ void PaintFrameInner( p.drawImage(rect, original); } +QImage PrepareBlurredBackground(QSize outer, QImage frame) { + const auto bsize = frame.size(); + const auto copyw = std::min( + bsize.width(), + outer.width() * bsize.height() / outer.height()); + const auto copyh = std::min( + bsize.height(), + outer.height() * bsize.width() / outer.width()); + auto copy = (bsize == QSize(copyw, copyh)) + ? std::move(frame) + : frame.copy( + (bsize.width() - copyw) / 2, + (bsize.height() - copyh) / 2, + copyw, + copyh); + auto scaled = (copy.width() <= 100 && copy.height() <= 100) + ? std::move(copy) + : copy.scaled(40, 40, Qt::KeepAspectRatio, Qt::FastTransformation); + return Images::Blur(std::move(scaled), true); +} + +void FillBlurredBackground(QPainter &p, QSize outer, QImage bg) { + auto hq = PainterHighQualityEnabler(p); + const auto rect = QRect(QPoint(), outer); + const auto ratio = p.device()->devicePixelRatio(); + p.drawImage( + rect, + PrepareBlurredBackground(outer * ratio, std::move(bg))); + p.fillRect(rect, QColor(0, 0, 0, 48)); +} + void PaintFrameContent( QPainter &p, const QImage &original, - bool alpha, + bool hasAlpha, + const AVRational &aspect, int rotation, const FrameRequest &request) { - const auto full = request.outer.isEmpty() - ? original.size() - : request.outer; - const auto size = request.resize.isEmpty() - ? original.size() - : request.resize; - const auto to = QRect( + const auto outer = request.outer; + const auto full = request.outer.isEmpty() ? original.size() : outer; + const auto deAlpha = hasAlpha && !request.keepAlpha; + const auto resize = request.blurredBackground + ? DecideVideoFrameResize( + outer, + FFmpeg::TransposeSizeByRotation( + FFmpeg::CorrectByAspect(original.size(), aspect), rotation)) + : ExpandDecision{ request.resize.isEmpty() + ? original.size() + : request.resize }; + const auto size = resize.result; + const auto target = QRect( (full.width() - size.width()) / 2, (full.height() - size.height()) / 2, size.width(), size.height()); - if (!alpha || !request.keepAlpha) { - PaintFrameOuter(p, to, full); + if (request.blurredBackground) { + if (!resize.expanding) { + FillBlurredBackground(p, full, original); + } + } else if (!hasAlpha || !request.keepAlpha) { + PaintFrameOuter(p, target, full); } - const auto deAlpha = alpha && !request.keepAlpha; - PaintFrameInner(p, to, original, deAlpha, rotation); + PaintFrameInner(p, target, original, deAlpha, rotation); } void ApplyFrameRounding(QImage &storage, const FrameRequest &request) { @@ -314,13 +357,41 @@ void ApplyFrameRounding(QImage &storage, const FrameRequest &request) { request.corners); } +ExpandDecision DecideFrameResize( + QSize outer, + QSize original, + int minVisibleNominator, + int minVisibleDenominator) { + if (outer.isEmpty()) { + // Often "expanding" means that we don't need to fill the background. + return { .result = original, .expanding = true }; + } + const auto big = original.scaled(outer, Qt::KeepAspectRatioByExpanding); + if ((big.width() * minVisibleNominator + <= outer.width() * minVisibleDenominator) + && (big.height() * minVisibleNominator + <= outer.height() * minVisibleDenominator)) { + return { .result = big, .expanding = true }; + } + return { .result = original.scaled(outer, Qt::KeepAspectRatio) }; +} + +ExpandDecision DecideVideoFrameResize(QSize outer, QSize original) { + return DecideFrameResize(outer, original, 1, 2); +} + +QSize CalculateResizeFromOuter(QSize outer, QSize original) { + return DecideVideoFrameResize(outer, original).result; +} + QImage PrepareByRequest( const QImage &original, - bool alpha, + bool hasAlpha, + const AVRational &aspect, int rotation, const FrameRequest &request, QImage storage) { - Expects(!request.outer.isEmpty() || alpha); + Expects(!request.outer.isEmpty() || hasAlpha); const auto outer = request.outer.isEmpty() ? original.size() @@ -329,12 +400,12 @@ QImage PrepareByRequest( storage = FFmpeg::CreateFrameStorage(outer); } - if (alpha && request.keepAlpha) { + if (hasAlpha && request.keepAlpha) { storage.fill(Qt::transparent); } QPainter p(&storage); - PaintFrameContent(p, original, alpha, rotation, request); + PaintFrameContent(p, original, hasAlpha, aspect, rotation, request); p.end(); ApplyFrameRounding(storage, request); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.h b/Telegram/SourceFiles/media/streaming/media_streaming_utility.h index 72dd6441a..7c997b136 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.h @@ -65,9 +65,26 @@ struct Stream { QSize resize, QImage storage); [[nodiscard]] FrameYUV ExtractYUV(Stream &stream, AVFrame *frame); + +struct ExpandDecision { + QSize result; + bool expanding = false; +}; +[[nodiscard]] ExpandDecision DecideFrameResize( + QSize outer, + QSize original, + int minVisibleNominator = 3, // If we cut out no more than 0.25 of + int minVisibleDenominator = 4); // the original, let's expand. +[[nodiscard]] ExpandDecision DecideVideoFrameResize( + QSize outer, + QSize original); +[[nodiscard]] QSize CalculateResizeFromOuter(QSize outer, QSize original); +[[nodiscard]] QImage PrepareBlurredBackground(QSize outer, QImage frame); +void FillBlurredBackground(QPainter &p, QSize outer, QImage bg); [[nodiscard]] QImage PrepareByRequest( const QImage &original, - bool alpha, + bool hasAlpha, + const AVRational &aspect, int rotation, const FrameRequest &request, QImage storage); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index 191593814..b9518125f 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -133,7 +133,7 @@ private: [[nodiscard]] ReadEnoughState readEnoughFrames(crl::time trackTime); [[nodiscard]] FrameResult readFrame(not_null frame); void fillRequests(not_null frame) const; - [[nodiscard]] QSize chooseOriginalResize() const; + [[nodiscard]] QSize chooseOriginalResize(QSize encoded) const; void presentFrameIfNeeded(); void callReady(); [[nodiscard]] bool loopAround(); @@ -402,16 +402,22 @@ void VideoTrackObject::fillRequests(not_null frame) const { } } -QSize VideoTrackObject::chooseOriginalResize() const { +QSize VideoTrackObject::chooseOriginalResize(QSize encoded) const { auto chosen = QSize(); + if (FFmpeg::RotationSwapWidthHeight(_stream.rotation)) { + encoded.transpose(); + } for (const auto &[_, request] : _requests) { - if (request.resize.isEmpty()) { + const auto resize = request.blurredBackground + ? CalculateResizeFromOuter(request.outer, encoded) + : request.resize; + if (resize.isEmpty()) { return QSize(); } - const auto byWidth = (request.resize.width() >= chosen.width()); - const auto byHeight = (request.resize.height() >= chosen.height()); + const auto byWidth = (resize.width() >= chosen.width()); + const auto byHeight = (resize.height() >= chosen.height()); if (byWidth && byHeight) { - chosen = request.resize; + chosen = resize; } else if (byWidth || byHeight) { return QSize(); } @@ -483,7 +489,8 @@ void VideoTrackObject::rasterizeFrame(not_null frame) { frame->original = ConvertFrame( _stream, frameWithData, - chooseOriginalResize(), + chooseOriginalResize( + { frameWithData->width, frameWithData->height }), std::move(frame->original)); if (frame->original.isNull()) { frame->prepared.clear(); @@ -493,7 +500,10 @@ void VideoTrackObject::rasterizeFrame(not_null frame) { frame->format = FrameFormat::ARGB32; } - VideoTrack::PrepareFrameByRequests(frame, _stream.rotation); + VideoTrack::PrepareFrameByRequests( + frame, + _stream.aspect, + _stream.rotation); Ensures(VideoTrack::IsRasterized(frame)); } @@ -706,22 +716,21 @@ void VideoTrackObject::callReady() { const auto frame = _shared->frameForPaint(); ++_frameIndex; - auto data = VideoInformation(); - data.size = FFmpeg::CorrectByAspect( - frame->original.size(), - _stream.aspect); - if (FFmpeg::RotationSwapWidthHeight(_stream.rotation)) { - data.size.transpose(); - } - data.cover = frame->original; - data.rotation = _stream.rotation; - data.alpha = frame->alpha; - data.state.duration = _stream.duration; - data.state.position = _syncTimePoint.trackTime; - data.state.receivedTill = _readTillEnd - ? _stream.duration - : _syncTimePoint.trackTime; - base::take(_ready)({ data }); + base::take(_ready)({ VideoInformation{ + .state = { + .position = _syncTimePoint.trackTime, + .receivedTill = (_readTillEnd + ? _stream.duration + : _syncTimePoint.trackTime), + .duration = _stream.duration, + }, + .size = FFmpeg::TransposeSizeByRotation( + FFmpeg::CorrectByAspect(frame->original.size(), _stream.aspect), + _stream.rotation), + .cover = frame->original, + .rotation = _stream.rotation, + .alpha = frame->alpha, + } }); } TimePoint VideoTrackObject::trackTime() const { @@ -1060,7 +1069,7 @@ VideoTrack::VideoTrack( , _streamTimeBase(stream.timeBase) , _streamDuration(stream.duration) , _streamRotation(stream.rotation) -//, _streamAspect(stream.aspect) +, _streamAspect(stream.aspect) , _shared(std::make_unique()) , _wrapped( options, @@ -1232,6 +1241,7 @@ QImage VideoTrack::frameImage( j->second.image = PrepareByRequest( frame->original, frame->alpha, + _streamAspect, _streamRotation, useRequest, std::move(j->second.image)); @@ -1258,6 +1268,7 @@ void VideoTrack::unregisterInstance(not_null instance) { void VideoTrack::PrepareFrameByRequests( not_null frame, + const AVRational &aspect, int rotation) { Expects(frame->format != FrameFormat::ARGB32 || !frame->original.isNull()); @@ -1286,6 +1297,7 @@ void VideoTrack::PrepareFrameByRequests( prepared.image = PrepareByRequest( frame->original, frame->alpha, + aspect, rotation, prepared.request, std::move(prepared.image)); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h index 95957b5d9..87a6d85cb 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h @@ -155,7 +155,10 @@ private: }; - static void PrepareFrameByRequests(not_null frame, int rotation); + static void PrepareFrameByRequests( + not_null frame, + const AVRational &aspect, + int rotation); [[nodiscard]] static bool IsDecoded(not_null frame); [[nodiscard]] static bool IsRasterized(not_null frame); [[nodiscard]] static bool IsStale( @@ -171,7 +174,7 @@ private: const AVRational _streamTimeBase; const crl::time _streamDuration = 0; const int _streamRotation = 0; - //AVRational _streamAspect = kNormalAspect; + const AVRational _streamAspect = FFmpeg::kNormalAspect; std::unique_ptr _shared; using Implementation = VideoTrackObject; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 95dd2c846..2e63c6103 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 95dd2c8465d4b5bfcbcdb47ce7a1d1e743d04477 +Subproject commit 2e63c6103e3b23bfcd65dcb8afb19c020511b168