diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index b77a511aaf..382dd50c4a 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -161,6 +161,7 @@ struct OverlayWidget::Streamed { Ui::InfiniteRadialAnimation radial; Animation fading; base::Timer timer; + QImage frameForDirectPaint; bool resumeOnCallEnd = false; std::optional lastError; @@ -337,6 +338,43 @@ QImage OverlayWidget::videoFrame() const { : _streamed->info.video.cover; } +QImage OverlayWidget::videoFrameForDirectPaint() const { + Expects(_streamed != nullptr); + + const auto result = videoFrame(); +#if defined Q_OS_MAC && !defined OS_MAC_OLD + const auto bytesPerLine = result.bytesPerLine(); + if (bytesPerLine == result.width() * 4) { + return result; + } + + // On macOS 10.8+ we use QOpenGLWidget as OverlayWidget base class. + // The OpenGL painter can't paint textures where byte data is with strides. + // So in that case we prepare a compact copy of the frame to render. + // + // See Qt commit ed557c037847e343caa010562952b398f806adcd + // + auto &cache = _streamed->frameForDirectPaint; + if (cache.size() != result.size()) { + cache = QImage(result.size(), result.format()); + } + const auto height = result.height(); + const auto line = cache.bytesPerLine(); + Assert(line == result.width() * 4); + Assert(line < bytesPerLine); + + auto from = result.bits(); + auto to = cache.bits(); + for (auto y = 0; y != height; ++y) { + memcpy(to, from, line); + to += line; + from += bytesPerLine; + } + return cache; +#endif // Q_OS_MAC && !OS_MAC_OLD + return result; +} + bool OverlayWidget::documentContentShown() const { return _doc && (!_current.isNull() || videoShown()); } @@ -2631,7 +2669,7 @@ void OverlayWidget::checkGroupThumbsAnimation() { void OverlayWidget::paintTransformedVideoFrame(Painter &p) { const auto rect = contentRect(); - const auto image = videoFrame(); + const auto image = videoFrameForDirectPaint(); //if (_fullScreenVideo) { // const auto fill = rect.intersected(this->rect()); // PaintImageProfile(p, image, rect, fill); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 1cd62baabc..e78f7d4c46 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -290,6 +290,7 @@ private: [[nodiscard]] QSize videoSize() const; [[nodiscard]] bool videoIsGifv() const; [[nodiscard]] QImage videoFrame() const; + [[nodiscard]] QImage videoFrameForDirectPaint() const; [[nodiscard]] QImage transformVideoFrame(QImage frame) const; [[nodiscard]] bool documentContentShown() const; [[nodiscard]] bool documentBubbleShown() const;