From 377ff2f4217c24d25650f99cb27f78a7bd4f8955 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 13 Aug 2020 15:32:25 +0400 Subject: [PATCH] Use expanding incoming frame scale if aspect is good. --- Telegram/SourceFiles/calls/calls_panel.cpp | 90 ++++++++++++++++------ Telegram/SourceFiles/calls/calls_panel.h | 7 +- 2 files changed, 70 insertions(+), 27 deletions(-) diff --git a/Telegram/SourceFiles/calls/calls_panel.cpp b/Telegram/SourceFiles/calls/calls_panel.cpp index 0e7595dca..fd2ac77f2 100644 --- a/Telegram/SourceFiles/calls/calls_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_panel.cpp @@ -448,11 +448,11 @@ void Panel::initControls() { _cancel->finishAnimating(); } -void Panel::setIncomingShown(bool shown) { - if (_incomingShown == shown) { +void Panel::setIncomingSize(QSize size) { + if (_incomingFrameSize == size) { return; } - _incomingShown = shown; + _incomingFrameSize = size; showControls(); } @@ -501,12 +501,30 @@ void Panel::reinitWithCall(Call *call) { stateChanged(state); }, _callLifetime); - rpl::merge( - _call->videoIncoming()->renderNextFrame(), - _call->videoOutgoing()->renderNextFrame() + _call->videoIncoming()->renderNextFrame( ) | rpl::start_with_next([=] { - setIncomingShown(!_call->videoIncoming()->frame({}).isNull()); - widget()->update(); + setIncomingSize(_call->videoIncoming()->frameSize()); + if (_incomingFrameSize.isEmpty()) { + return; + } + const auto incoming = incomingFrameGeometry(); + const auto outgoing = outgoingFrameGeometry(); + if (incoming.intersects(outgoing)) { + widget()->update(incoming.united(outgoing)); + } else { + widget()->update(incoming); + } + }, _callLifetime); + + _call->videoOutgoing()->renderNextFrame( + ) | rpl::start_with_next([=] { + const auto incoming = incomingFrameGeometry(); + const auto outgoing = outgoingFrameGeometry(); + if (incoming.intersects(outgoing)) { + widget()->update(incoming.united(outgoing)); + } else { + widget()->update(outgoing); + } }, _callLifetime); rpl::combine( @@ -551,9 +569,11 @@ void Panel::showControls() { widget()->showChildren(); _decline->setVisible(_decline->toggled()); _cancel->setVisible(_cancel->toggled()); - _name->setVisible(!_incomingShown); - _status->setVisible(!_incomingShown); - _userpic->setVisible(!_incomingShown); + + const auto shown = !_incomingFrameSize.isEmpty(); + _name->setVisible(!shown); + _status->setVisible(!shown); + _userpic->setVisible(!shown); } void Panel::hideBeforeDestroy() { @@ -590,6 +610,31 @@ void Panel::toggleFullScreen(bool fullscreen) { } } +QRect Panel::incomingFrameGeometry() const { + if (!_call || _incomingFrameSize.isEmpty()) { + return QRect(); + } + const auto to = widget()->size(); + const auto small = _incomingFrameSize.scaled(to, Qt::KeepAspectRatio); + const auto big = _incomingFrameSize.scaled( + to, + Qt::KeepAspectRatioByExpanding); + + // If we cut out no more than 0.33 of the original, let's use expanding. + const auto use = ((big.width() * 3 <= to.width() * 4) + && (big.height() * 3 <= to.height() * 4)) + ? big + : small; + const auto pos = QPoint( + (to.width() - use.width()) / 2, + (to.height() - use.height()) / 2); + return QRect(pos, use); +} + +QRect Panel::outgoingFrameGeometry() const { + return _outgoingVideoBubble->geometry(); +} + void Panel::updateFingerprintGeometry() { auto realSize = Ui::Emoji::GetSizeNormal(); auto size = realSize / cIntRetinaFactor(); @@ -712,20 +757,15 @@ void Panel::paint(QRect clip) { p.fillRect(clip, st::callBgOpaque); - const auto incomingFrame = _call - ? _call->videoIncoming()->frame(Webrtc::FrameRequest()) - : QImage(); - if (!incomingFrame.isNull()) { - const auto to = widget()->rect(); - p.save(); - p.setClipRect(to); - const auto big = incomingFrame.size().scaled(to.size(), Qt::KeepAspectRatio); - const auto pos = QPoint( - to.left() + (to.width() - big.width()) / 2, - to.top() + (to.height() - big.height()) / 2); - auto hq = PainterHighQualityEnabler(p); - p.drawImage(QRect(pos, big), incomingFrame); - p.restore(); + const auto incoming = incomingFrameGeometry(); + if (!incoming.isEmpty()) { + Assert(_call != nullptr); + const auto frame = _call->videoIncoming()->frame( + Webrtc::FrameRequest()); + if (!frame.isNull()) { + auto hq = PainterHighQualityEnabler(p); + p.drawImage(incoming, frame); + } } _call->videoIncoming()->markFrameShown(); diff --git a/Telegram/SourceFiles/calls/calls_panel.h b/Telegram/SourceFiles/calls/calls_panel.h index e9c5f3999..5ba75ac69 100644 --- a/Telegram/SourceFiles/calls/calls_panel.h +++ b/Telegram/SourceFiles/calls/calls_panel.h @@ -90,11 +90,14 @@ private: void updateStatusText(State state); void startDurationUpdateTimer(crl::time currentDuration); void fillFingerprint(); - void setIncomingShown(bool shown); + void setIncomingSize(QSize size); void refreshOutgoingPreviewInBody(State state); void toggleFullScreen(bool fullscreen); + [[nodiscard]] QRect incomingFrameGeometry() const; + [[nodiscard]] QRect outgoingFrameGeometry() const; + Call *_call = nullptr; not_null _user; @@ -104,7 +107,7 @@ private: std::unique_ptr _controls; #endif // Q_OS_WIN - bool _incomingShown = false; + QSize _incomingFrameSize; rpl::lifetime _callLifetime;