Mirror my outgoing video in video chats.

This commit is contained in:
John Preston 2024-01-10 08:28:39 -08:00
parent e2439984ae
commit 0dfe37f998
8 changed files with 40 additions and 17 deletions

View file

@ -127,12 +127,13 @@ void VideoBubble::paint() {
const auto inner = _content.rect().marginsRemoved(padding); const auto inner = _content.rect().marginsRemoved(padding);
Ui::Shadow::paint(p, inner, _content.width(), st::boxRoundShadow); Ui::Shadow::paint(p, inner, _content.width(), st::boxRoundShadow);
const auto factor = cIntRetinaFactor(); const auto factor = cIntRetinaFactor();
const auto left = _mirrored
? (_frame.width() - (inner.width() * factor))
: 0;
p.drawImage( p.drawImage(
inner, inner,
_frame, _frame,
QRect( QRect(QPoint(left, 0), inner.size() * factor));
QPoint(_frame.width() - (inner.width() * factor), 0),
inner.size() * factor));
} }
_track->markFrameShown(); _track->markFrameShown();
} }
@ -152,11 +153,10 @@ void VideoBubble::prepareFrame() {
.resize = size, .resize = size,
.outer = size, .outer = size,
}; };
const auto frame = _track->frame(request).mirrored(!_mirrored, false); const auto frame = _track->frame(request);
if (_frame.width() < size.width() || _frame.height() < size.height()) { if (_frame.width() < size.width() || _frame.height() < size.height()) {
_frame = QImage( _frame = QImage(size, QImage::Format_ARGB32_Premultiplied);
size * cIntRetinaFactor(), _frame.fill(Qt::transparent);
QImage::Format_ARGB32_Premultiplied);
} }
Assert(_frame.width() >= frame.width() Assert(_frame.width() >= frame.width()
&& _frame.height() >= frame.height()); && _frame.height() >= frame.height());
@ -174,7 +174,7 @@ void VideoBubble::prepareFrame() {
ImageRoundRadius::Large, ImageRoundRadius::Large,
RectPart::AllCorners, RectPart::AllCorners,
QRect(QPoint(), size) QRect(QPoint(), size)
).mirrored(true, false); ).mirrored(_mirrored, false);
} }
void VideoBubble::setState(Webrtc::VideoState state) { void VideoBubble::setState(Webrtc::VideoState state) {

View file

@ -1060,11 +1060,13 @@ void Panel::setupVideo(not_null<Viewport*> viewport) {
_call->videoEndpointLargeValue(), _call->videoEndpointLargeValue(),
_call->videoEndpointPinnedValue() _call->videoEndpointPinnedValue()
) | rpl::map(_1 == endpoint && _2); ) | rpl::map(_1 == endpoint && _2);
const auto self = (endpoint.peer == _call->joinAs());
viewport->add( viewport->add(
endpoint, endpoint,
VideoTileTrack{ GroupCall::TrackPointer(track), row }, VideoTileTrack{ GroupCall::TrackPointer(track), row },
GroupCall::TrackSizeValue(track), GroupCall::TrackSizeValue(track),
std::move(pinned)); std::move(pinned),
self);
}; };
for (const auto &[endpoint, track] : _call->activeVideoTracks()) { for (const auto &[endpoint, track] : _call->activeVideoTracks()) {
setupTile(endpoint, track); setupTile(endpoint, track);

View file

@ -237,13 +237,15 @@ void Viewport::add(
const VideoEndpoint &endpoint, const VideoEndpoint &endpoint,
VideoTileTrack track, VideoTileTrack track,
rpl::producer<QSize> trackSize, rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned) { rpl::producer<bool> pinned,
bool self) {
_tiles.push_back(std::make_unique<VideoTile>( _tiles.push_back(std::make_unique<VideoTile>(
endpoint, endpoint,
track, track,
std::move(trackSize), std::move(trackSize),
std::move(pinned), std::move(pinned),
[=] { widget()->update(); })); [=] { widget()->update(); },
self));
_tiles.back()->trackSizeValue( _tiles.back()->trackSizeValue(
) | rpl::filter([](QSize size) { ) | rpl::filter([](QSize size) {

View file

@ -80,7 +80,8 @@ public:
const VideoEndpoint &endpoint, const VideoEndpoint &endpoint,
VideoTileTrack track, VideoTileTrack track,
rpl::producer<QSize> trackSize, rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned); rpl::producer<bool> pinned,
bool self);
void remove(const VideoEndpoint &endpoint); void remove(const VideoEndpoint &endpoint);
void showLarge(const VideoEndpoint &endpoint); void showLarge(const VideoEndpoint &endpoint);

View file

@ -531,6 +531,12 @@ void Viewport::RendererGL::paintTile(
{ { 1.f, 0.f } }, { { 1.f, 0.f } },
{ { 0.f, 0.f } }, { { 0.f, 0.f } },
} }; } };
if (tile->mirror()) {
std::swap(toBlurTexCoords[0], toBlurTexCoords[1]);
std::swap(toBlurTexCoords[2], toBlurTexCoords[3]);
std::swap(texCoords[0], texCoords[1]);
std::swap(texCoords[2], texCoords[3]);
}
if (const auto shift = (frameRotation / 90); shift > 0) { if (const auto shift = (frameRotation / 90); shift > 0) {
std::rotate( std::rotate(
toBlurTexCoords.begin(), toBlurTexCoords.begin(),

View file

@ -105,14 +105,14 @@ void Viewport::RendererSW::paintTile(
tileData.blurredFrame = Images::BlurLargeImage( tileData.blurredFrame = Images::BlurLargeImage(
data.original.scaled( data.original.scaled(
VideoTile::PausedVideoSize(), VideoTile::PausedVideoSize(),
Qt::KeepAspectRatio), Qt::KeepAspectRatio).mirrored(tile->mirror(), false),
kBlurRadius); kBlurRadius);
} }
const auto &image = _userpicFrame const auto &image = _userpicFrame
? tileData.userpicFrame ? tileData.userpicFrame
: _pausedFrame : _pausedFrame
? tileData.blurredFrame ? tileData.blurredFrame
: data.original; : data.original.mirrored(tile->mirror(), false);
const auto frameRotation = _userpicFrame ? 0 : data.rotation; const auto frameRotation = _userpicFrame ? 0 : data.rotation;
Assert(!image.isNull()); Assert(!image.isNull());

View file

@ -28,12 +28,14 @@ Viewport::VideoTile::VideoTile(
VideoTileTrack track, VideoTileTrack track,
rpl::producer<QSize> trackSize, rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned, rpl::producer<bool> pinned,
Fn<void()> update) Fn<void()> update,
bool self)
: _endpoint(endpoint) : _endpoint(endpoint)
, _update(std::move(update)) , _update(std::move(update))
, _track(std::move(track)) , _track(std::move(track))
, _trackSize(std::move(trackSize)) , _trackSize(std::move(trackSize))
, _rtmp(endpoint.rtmp()) { , _rtmp(endpoint.rtmp())
, _self(self) {
Expects(_track.track != nullptr); Expects(_track.track != nullptr);
Expects(_track.row != nullptr); Expects(_track.row != nullptr);
@ -48,6 +50,10 @@ Viewport::VideoTile::VideoTile(
setup(std::move(pinned)); setup(std::move(pinned));
} }
bool Viewport::VideoTile::mirror() const {
return _self && (_endpoint.type == VideoEndpointType::Camera);
}
QRect Viewport::VideoTile::pinOuter() const { QRect Viewport::VideoTile::pinOuter() const {
return _pinOuter; return _pinOuter;
} }

View file

@ -28,7 +28,8 @@ public:
VideoTileTrack track, VideoTileTrack track,
rpl::producer<QSize> trackSize, rpl::producer<QSize> trackSize,
rpl::producer<bool> pinned, rpl::producer<bool> pinned,
Fn<void()> update); Fn<void()> update,
bool self);
[[nodiscard]] not_null<Webrtc::VideoTrack*> track() const { [[nodiscard]] not_null<Webrtc::VideoTrack*> track() const {
return _track.track; return _track.track;
@ -54,6 +55,10 @@ public:
[[nodiscard]] bool visible() const { [[nodiscard]] bool visible() const {
return !_hidden && !_geometry.isEmpty(); return !_hidden && !_geometry.isEmpty();
} }
[[nodiscard]] bool self() const {
return _self;
}
[[nodiscard]] bool mirror() const;
[[nodiscard]] QRect pinOuter() const; [[nodiscard]] QRect pinOuter() const;
[[nodiscard]] QRect pinInner() const; [[nodiscard]] QRect pinInner() const;
[[nodiscard]] QRect backOuter() const; [[nodiscard]] QRect backOuter() const;
@ -123,6 +128,7 @@ private:
bool _pinned = false; bool _pinned = false;
bool _hidden = true; bool _hidden = true;
bool _rtmp = false; bool _rtmp = false;
bool _self = false;
std::optional<VideoQuality> _quality; std::optional<VideoQuality> _quality;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;