mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 00:08:02 +00:00
Rotate video in PiP.
This commit is contained in:
parent
4544b091a0
commit
d29c3add79
@ -199,32 +199,6 @@ QPixmap PrepareStaticImage(const QString &path) {
|
||||
return App::pixmapFromImageInPlace(std::move(image));
|
||||
}
|
||||
|
||||
[[nodiscard]] QRect RotatedRect(QRect rect, int rotation) {
|
||||
switch (rotation) {
|
||||
case 0: return rect;
|
||||
case 90: return QRect(
|
||||
rect.y(),
|
||||
-rect.x() - rect.width(),
|
||||
rect.height(),
|
||||
rect.width());
|
||||
case 180: return QRect(
|
||||
-rect.x() - rect.width(),
|
||||
-rect.y() - rect.height(),
|
||||
rect.width(),
|
||||
rect.height());
|
||||
case 270: return QRect(
|
||||
-rect.y() - rect.height(),
|
||||
rect.x(),
|
||||
rect.height(),
|
||||
rect.width());
|
||||
}
|
||||
Unexpected("Rotation in RotatedRect.");
|
||||
}
|
||||
|
||||
[[nodiscard]] bool UsePainterRotation(int rotation) {
|
||||
return Platform::IsMac() || !(rotation % 180);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct OverlayWidget::SharedMedia {
|
||||
@ -460,9 +434,7 @@ void OverlayWidget::moveToScreen(bool force) {
|
||||
}
|
||||
|
||||
QSize OverlayWidget::flipSizeByRotation(QSize size) const {
|
||||
return (((_rotation / 90) % 2) == 1)
|
||||
? QSize(size.height(), size.width())
|
||||
: size;
|
||||
return FlipSizeByRotation(size, _rotation);
|
||||
}
|
||||
|
||||
bool OverlayWidget::videoShown() const {
|
||||
@ -2289,9 +2261,7 @@ QImage OverlayWidget::transformVideoFrame(QImage frame) const {
|
||||
|
||||
const auto rotation = contentRotation();
|
||||
if (rotation != 0) {
|
||||
auto transform = QTransform();
|
||||
transform.rotate(rotation);
|
||||
frame = frame.transformed(transform);
|
||||
frame = RotateFrameImage(std::move(frame), rotation);
|
||||
}
|
||||
const auto requiredSize = videoSize();
|
||||
if (frame.size() != requiredSize) {
|
||||
@ -2304,13 +2274,9 @@ QImage OverlayWidget::transformVideoFrame(QImage frame) const {
|
||||
}
|
||||
|
||||
QImage OverlayWidget::transformStaticContent(QPixmap content) const {
|
||||
auto image = content.toImage();
|
||||
if (!_rotation) {
|
||||
return image;
|
||||
}
|
||||
auto transform = QTransform();
|
||||
transform.rotate(_rotation);
|
||||
return image.transformed(transform);
|
||||
return _rotation
|
||||
? RotateFrameImage(content.toImage(), _rotation)
|
||||
: content.toImage();
|
||||
}
|
||||
|
||||
void OverlayWidget::handleStreamingUpdate(Streaming::Update &&update) {
|
||||
|
@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_media_rotation.h"
|
||||
#include "core/application.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "ui/platform/ui_platform_utility.h"
|
||||
@ -253,8 +255,94 @@ constexpr auto kMsInSecond = 1000;
|
||||
return result;
|
||||
}
|
||||
|
||||
Streaming::FrameRequest UnrotateRequest(
|
||||
const Streaming::FrameRequest &request,
|
||||
int rotation) {
|
||||
if (!rotation) {
|
||||
return request;
|
||||
}
|
||||
const auto unrotatedCorner = [&](RectPart corner) {
|
||||
if (!(request.corners & corner)) {
|
||||
return RectPart(0);
|
||||
}
|
||||
switch (corner) {
|
||||
case RectPart::TopLeft:
|
||||
return (rotation == 90)
|
||||
? RectPart::BottomLeft
|
||||
: (rotation == 180)
|
||||
? RectPart::BottomRight
|
||||
: RectPart::TopRight;
|
||||
case RectPart::TopRight:
|
||||
return (rotation == 90)
|
||||
? RectPart::TopLeft
|
||||
: (rotation == 180)
|
||||
? RectPart::BottomLeft
|
||||
: RectPart::BottomRight;
|
||||
case RectPart::BottomRight:
|
||||
return (rotation == 90)
|
||||
? RectPart::TopRight
|
||||
: (rotation == 180)
|
||||
? RectPart::TopLeft
|
||||
: RectPart::BottomLeft;
|
||||
case RectPart::BottomLeft:
|
||||
return (rotation == 90)
|
||||
? RectPart::BottomRight
|
||||
: (rotation == 180)
|
||||
? RectPart::TopRight
|
||||
: RectPart::TopLeft;
|
||||
}
|
||||
Unexpected("Corner in rotateCorner.");
|
||||
};
|
||||
auto result = request;
|
||||
result.outer = FlipSizeByRotation(request.outer, rotation);
|
||||
result.resize = FlipSizeByRotation(request.resize, rotation);
|
||||
result.corners = unrotatedCorner(RectPart::TopLeft)
|
||||
| unrotatedCorner(RectPart::TopRight)
|
||||
| unrotatedCorner(RectPart::BottomRight)
|
||||
| unrotatedCorner(RectPart::BottomLeft);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QRect RotatedRect(QRect rect, int rotation) {
|
||||
switch (rotation) {
|
||||
case 0: return rect;
|
||||
case 90: return QRect(
|
||||
rect.y(),
|
||||
-rect.x() - rect.width(),
|
||||
rect.height(),
|
||||
rect.width());
|
||||
case 180: return QRect(
|
||||
-rect.x() - rect.width(),
|
||||
-rect.y() - rect.height(),
|
||||
rect.width(),
|
||||
rect.height());
|
||||
case 270: return QRect(
|
||||
-rect.y() - rect.height(),
|
||||
rect.x(),
|
||||
rect.height(),
|
||||
rect.width());
|
||||
}
|
||||
Unexpected("Rotation in RotatedRect.");
|
||||
}
|
||||
|
||||
bool UsePainterRotation(int rotation) {
|
||||
return Platform::IsMac() || !(rotation % 180);
|
||||
}
|
||||
|
||||
QSize FlipSizeByRotation(QSize size, int rotation) {
|
||||
return (((rotation / 90) % 2) == 1)
|
||||
? QSize(size.height(), size.width())
|
||||
: size;
|
||||
}
|
||||
|
||||
QImage RotateFrameImage(QImage image, int rotation) {
|
||||
auto transform = QTransform();
|
||||
transform.rotate(rotation);
|
||||
return image.transformed(transform);
|
||||
}
|
||||
|
||||
PipPanel::PipPanel(
|
||||
QWidget *parent,
|
||||
Fn<void(QPainter&, FrameRequest)> paint)
|
||||
@ -724,6 +812,7 @@ Pip::Pip(
|
||||
_delegate->pipParentWidget(),
|
||||
[=](QPainter &p, const FrameRequest &request) { paint(p, request); })
|
||||
, _playbackProgress(std::make_unique<PlaybackProgress>())
|
||||
, _rotation(document->owner().mediaRotation().get(document))
|
||||
, _roundRect(ImageRoundRadius::Large, st::radialBg)
|
||||
, _closeAndContinue(std::move(closeAndContinue))
|
||||
, _destroy(std::move(destroy)) {
|
||||
@ -735,15 +824,16 @@ Pip::Pip(
|
||||
Pip::~Pip() = default;
|
||||
|
||||
void Pip::setupPanel() {
|
||||
const auto size = style::ConvertScale(_instance.info().video.size);
|
||||
if (size.isEmpty()) {
|
||||
const auto size = [&] {
|
||||
if (!_instance.info().video.size.isEmpty()) {
|
||||
return _instance.info().video.size;
|
||||
}
|
||||
const auto good = _document->goodThumbnail();
|
||||
const auto useGood = (good && good->loaded());
|
||||
const auto original = useGood ? good->size() : _document->dimensions;
|
||||
_panel.setAspectRatio(original.isEmpty() ? QSize(1, 1) : original);
|
||||
} else {
|
||||
_panel.setAspectRatio(size);
|
||||
}
|
||||
return original.isEmpty() ? QSize(1, 1) : original;
|
||||
}();
|
||||
_panel.setAspectRatio(FlipSizeByRotation(size, _rotation));
|
||||
_panel.setPosition(Deserialize(_delegate->pipLoadGeometry()));
|
||||
_panel.show();
|
||||
|
||||
@ -1022,11 +1112,25 @@ void Pip::setupStreaming() {
|
||||
}
|
||||
|
||||
void Pip::paint(QPainter &p, FrameRequest request) {
|
||||
const auto image = videoFrameForDirectPaint(request);
|
||||
const auto image = videoFrameForDirectPaint(
|
||||
UnrotateRequest(request, _rotation));
|
||||
const auto inner = _panel.inner();
|
||||
p.drawImage(
|
||||
QRect{ inner.topLeft(), request.outer / style::DevicePixelRatio() },
|
||||
image);
|
||||
const auto rect = QRect{
|
||||
inner.topLeft(),
|
||||
request.outer / style::DevicePixelRatio()
|
||||
};
|
||||
if (UsePainterRotation(_rotation)) {
|
||||
if (_rotation) {
|
||||
p.save();
|
||||
p.rotate(_rotation);
|
||||
}
|
||||
p.drawImage(RotatedRect(rect, _rotation), image);
|
||||
if (_rotation) {
|
||||
p.restore();
|
||||
}
|
||||
} else {
|
||||
p.drawImage(rect, RotateFrameImage(image, _rotation));
|
||||
}
|
||||
if (_instance.player().ready()) {
|
||||
_instance.markFrameShown();
|
||||
}
|
||||
@ -1149,7 +1253,8 @@ void Pip::handleStreamingUpdate(Streaming::Update &&update) {
|
||||
using namespace Streaming;
|
||||
|
||||
update.data.match([&](Information &update) {
|
||||
_panel.setAspectRatio(update.video.size);
|
||||
_panel.setAspectRatio(
|
||||
FlipSizeByRotation(update.video.size, _rotation));
|
||||
}, [&](const PreloadedVideo &update) {
|
||||
updatePlaybackState();
|
||||
}, [&](const UpdateVideo &update) {
|
||||
|
@ -29,6 +29,11 @@ namespace View {
|
||||
|
||||
class PlaybackProgress;
|
||||
|
||||
[[nodiscard]] QRect RotatedRect(QRect rect, int rotation);
|
||||
[[nodiscard]] bool UsePainterRotation(int rotation);
|
||||
[[nodiscard]] QSize FlipSizeByRotation(QSize size, int rotation);
|
||||
[[nodiscard]] QImage RotateFrameImage(QImage image, int rotation);
|
||||
|
||||
#if defined Q_OS_MAC && !defined OS_MAC_OLD
|
||||
#define USE_OPENGL_OVERLAY_WIDGET
|
||||
#endif // Q_OS_MAC && !OS_MAC_OLD
|
||||
@ -204,6 +209,7 @@ private:
|
||||
bool _pausedBySeek = false;
|
||||
QString _timeAlready, _timeLeft;
|
||||
int _timeLeftWidth = 0;
|
||||
int _rotation = 0;
|
||||
crl::time _seekPositionMs = -1;
|
||||
crl::time _lastDurationMs = 0;
|
||||
OverState _over = OverState::None;
|
||||
|
Loading…
Reference in New Issue
Block a user