Add pinned video in wide mode.

This commit is contained in:
John Preston 2021-04-23 19:05:52 +04:00
parent b15623d435
commit e12fe974b2
3 changed files with 113 additions and 9 deletions

View file

@ -410,7 +410,9 @@ void GroupCall::switchToCamera() {
return;
}
_videoDeviceId = _videoInputId;
if (_videoOutgoing)
if (_videoOutgoing->state() != Webrtc::VideoState::Active) {
_videoOutgoing->setState(Webrtc::VideoState::Active);
}
_videoCapture->switchToDevice(_videoDeviceId.toStdString());
}
@ -419,6 +421,9 @@ void GroupCall::switchToScreenSharing(const QString &uniqueId) {
return;
}
_videoDeviceId = uniqueId;
if (_videoOutgoing->state() != Webrtc::VideoState::Active) {
_videoOutgoing->setState(Webrtc::VideoState::Active);
}
_videoCapture->switchToDevice(_videoDeviceId.toStdString());
}
@ -1432,15 +1437,15 @@ void GroupCall::setupOutgoingVideo() {
}
_videoOutgoing->stateValue(
) | rpl::start_with_next([=](Webrtc::VideoState state) {
if (state != Webrtc::VideoState::Inactive && !hasDevices()) {
//if (state != Webrtc::VideoState::Inactive && !hasDevices()) {
//_errors.fire({ ErrorType::NoCamera }); // #TODO videochats
_videoOutgoing->setState(Webrtc::VideoState::Inactive);
//_videoOutgoing->setState(Webrtc::VideoState::Inactive);
//} else if (state != Webrtc::VideoState::Inactive
// && _instance
// && !_instance->supportsVideo()) {
// _errors.fire({ ErrorType::NotVideoCall });
// _videoOutgoing->setState(Webrtc::VideoState::Inactive);
} else if (state != Webrtc::VideoState::Inactive) {
/*} else */if (state != Webrtc::VideoState::Inactive) {
// Paused not supported right now.
Assert(state == Webrtc::VideoState::Active);
if (!_videoCapture) {

View file

@ -47,6 +47,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer_rpl.h"
#include "app.h"
#include "apiwrap.h" // api().kickParticipant.
#include "media/view/media_view_pip.h"
#include "webrtc/webrtc_video_track.h"
#include "styles/style_calls.h"
#include "styles/style_layers.h"
@ -904,6 +906,91 @@ void Panel::setupMembers() {
addMembers();
}
}, _callLifetime);
setupPinnedVideo();
}
void Panel::setupPinnedVideo() {
_pinnedVideo.create(widget());
_pinnedVideo->setVisible(_mode == PanelMode::Wide);
rpl::combine(
_pinnedVideo->shownValue(),
_call->videoLargeTrackValue()
) | rpl::map([](bool shown, Webrtc::VideoTrack *track) {
return shown ? track : nullptr;
}) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](Webrtc::VideoTrack *track) {
_pinnedTrackLifetime.destroy();
if (!track) {
_pinnedVideo->paintRequest(
) | rpl::start_with_next([=](QRect clip) {
QPainter(_pinnedVideo.data()).fillRect(clip, Qt::black);
}, _pinnedTrackLifetime);
_pinnedVideo->update();
return;
}
track->renderNextFrame(
) | rpl::start_with_next([=] {
const auto size = track->frameSize();
if (size.isEmpty()) {
track->markFrameShown();
} else {
_pinnedVideo->update();
}
}, _pinnedTrackLifetime);
_pinnedVideo->paintRequest(
) | rpl::start_with_next([=] {
const auto [image, rotation]
= track->frameOriginalWithRotation();
if (image.isNull()) {
return;
}
auto p = QPainter(_pinnedVideo);
auto hq = PainterHighQualityEnabler(p);
using namespace Media::View;
const auto size = _pinnedVideo->size();
const auto scaled = FlipSizeByRotation(
image.size(),
rotation
).scaled(size, Qt::KeepAspectRatio);
const auto left = (size.width() - scaled.width()) / 2;
const auto top = (size.height() - scaled.height()) / 2;
const auto target = QRect(QPoint(left, top), scaled);
if (UsePainterRotation(rotation)) {
if (rotation) {
p.save();
p.rotate(rotation);
}
p.drawImage(RotatedRect(target, rotation), image);
if (rotation) {
p.restore();
}
} else if (rotation) {
p.drawImage(target, RotateFrameImage(image, rotation));
} else {
p.drawImage(target, image);
}
if (left > 0) {
p.fillRect(0, 0, left, size.height(), Qt::black);
}
if (const auto right = left + scaled.width()
; right < size.width()) {
const auto fill = size.width() - right;
p.fillRect(right, 0, fill, size.height(), Qt::black);
}
if (top > 0) {
p.fillRect(0, 0, size.width(), top, Qt::black);
}
if (const auto bottom = top + scaled.height()
; bottom < size.height()) {
const auto fill = size.height() - bottom;
p.fillRect(0, bottom, size.width(), fill, Qt::black);
}
track->markFrameShown();
}, _pinnedTrackLifetime);
}, widget()->lifetime());
}
void Panel::setupJoinAsChangedToasts() {
@ -1402,6 +1489,7 @@ bool Panel::updateMode() {
if (_members) {
_members->setMode(mode);
}
_pinnedVideo->setVisible(mode == PanelMode::Wide);
updateControlsGeometry();
return true;
}
@ -1457,18 +1545,25 @@ void Panel::updateMembersGeometry() {
return;
}
const auto desiredHeight = _members->desiredHeight();
const auto muteTop = widget()->height() - st::groupCallMuteBottomSkip;
const auto membersTop = st::groupCallMembersTop;
const auto availableHeight = muteTop
- membersTop
- st::groupCallMembersMargin.bottom();
if (_mode == PanelMode::Wide) {
_members->setGeometry(
st::groupCallNarrowSkip,
0,
st::groupCallNarrowSize.width(),
std::min(desiredHeight, widget()->height()));
const auto pinnedLeft = st::groupCallNarrowSkip * 2
+ st::groupCallNarrowSize.width();
_pinnedVideo->setGeometry(
pinnedLeft,
membersTop,
widget()->width() - pinnedLeft,
availableHeight);
} else {
const auto muteTop = widget()->height() - st::groupCallMuteBottomSkip;
const auto membersTop = st::groupCallMembersTop;
const auto availableHeight = muteTop
- membersTop
- st::groupCallMembersMargin.bottom();
const auto membersWidthAvailable = widget()->width()
- st::groupCallMembersMargin.left()
- st::groupCallMembersMargin.right();

View file

@ -31,6 +31,7 @@ class CallButton;
class CallMuteButton;
class IconButton;
class FlatLabel;
class RpWidget;
template <typename Widget>
class FadeWrap;
template <typename Widget>
@ -81,6 +82,7 @@ private:
void initGeometry();
void setupScheduledLabels(rpl::producer<TimeId> date);
void setupMembers();
void setupPinnedVideo();
void setupJoinAsChangedToasts();
void setupTitleChangedToasts();
void setupAllowedToSpeakToasts();
@ -135,6 +137,8 @@ private:
object_ptr<Ui::DropdownMenu> _menu = { nullptr };
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
object_ptr<Members> _members = { nullptr };
object_ptr<Ui::RpWidget> _pinnedVideo = { nullptr };
rpl::lifetime _pinnedTrackLifetime;
object_ptr<Ui::FlatLabel> _startsIn = { nullptr };
object_ptr<Ui::RpWidget> _countdown = { nullptr };
std::shared_ptr<Ui::GroupCallScheduledLeft> _countdownData;