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));
|
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
|
} // namespace
|
||||||
|
|
||||||
struct OverlayWidget::SharedMedia {
|
struct OverlayWidget::SharedMedia {
|
||||||
@ -460,9 +434,7 @@ void OverlayWidget::moveToScreen(bool force) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QSize OverlayWidget::flipSizeByRotation(QSize size) const {
|
QSize OverlayWidget::flipSizeByRotation(QSize size) const {
|
||||||
return (((_rotation / 90) % 2) == 1)
|
return FlipSizeByRotation(size, _rotation);
|
||||||
? QSize(size.height(), size.width())
|
|
||||||
: size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OverlayWidget::videoShown() const {
|
bool OverlayWidget::videoShown() const {
|
||||||
@ -2289,9 +2261,7 @@ QImage OverlayWidget::transformVideoFrame(QImage frame) const {
|
|||||||
|
|
||||||
const auto rotation = contentRotation();
|
const auto rotation = contentRotation();
|
||||||
if (rotation != 0) {
|
if (rotation != 0) {
|
||||||
auto transform = QTransform();
|
frame = RotateFrameImage(std::move(frame), rotation);
|
||||||
transform.rotate(rotation);
|
|
||||||
frame = frame.transformed(transform);
|
|
||||||
}
|
}
|
||||||
const auto requiredSize = videoSize();
|
const auto requiredSize = videoSize();
|
||||||
if (frame.size() != requiredSize) {
|
if (frame.size() != requiredSize) {
|
||||||
@ -2304,13 +2274,9 @@ QImage OverlayWidget::transformVideoFrame(QImage frame) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QImage OverlayWidget::transformStaticContent(QPixmap content) const {
|
QImage OverlayWidget::transformStaticContent(QPixmap content) const {
|
||||||
auto image = content.toImage();
|
return _rotation
|
||||||
if (!_rotation) {
|
? RotateFrameImage(content.toImage(), _rotation)
|
||||||
return image;
|
: content.toImage();
|
||||||
}
|
|
||||||
auto transform = QTransform();
|
|
||||||
transform.rotate(_rotation);
|
|
||||||
return image.transformed(transform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::handleStreamingUpdate(Streaming::Update &&update) {
|
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 "media/audio/media_audio.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_media_rotation.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
#include "ui/platform/ui_platform_utility.h"
|
||||||
@ -253,8 +255,94 @@ constexpr auto kMsInSecond = 1000;
|
|||||||
return result;
|
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
|
} // 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(
|
PipPanel::PipPanel(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
Fn<void(QPainter&, FrameRequest)> paint)
|
Fn<void(QPainter&, FrameRequest)> paint)
|
||||||
@ -724,6 +812,7 @@ Pip::Pip(
|
|||||||
_delegate->pipParentWidget(),
|
_delegate->pipParentWidget(),
|
||||||
[=](QPainter &p, const FrameRequest &request) { paint(p, request); })
|
[=](QPainter &p, const FrameRequest &request) { paint(p, request); })
|
||||||
, _playbackProgress(std::make_unique<PlaybackProgress>())
|
, _playbackProgress(std::make_unique<PlaybackProgress>())
|
||||||
|
, _rotation(document->owner().mediaRotation().get(document))
|
||||||
, _roundRect(ImageRoundRadius::Large, st::radialBg)
|
, _roundRect(ImageRoundRadius::Large, st::radialBg)
|
||||||
, _closeAndContinue(std::move(closeAndContinue))
|
, _closeAndContinue(std::move(closeAndContinue))
|
||||||
, _destroy(std::move(destroy)) {
|
, _destroy(std::move(destroy)) {
|
||||||
@ -735,15 +824,16 @@ Pip::Pip(
|
|||||||
Pip::~Pip() = default;
|
Pip::~Pip() = default;
|
||||||
|
|
||||||
void Pip::setupPanel() {
|
void Pip::setupPanel() {
|
||||||
const auto size = style::ConvertScale(_instance.info().video.size);
|
const auto size = [&] {
|
||||||
if (size.isEmpty()) {
|
if (!_instance.info().video.size.isEmpty()) {
|
||||||
|
return _instance.info().video.size;
|
||||||
|
}
|
||||||
const auto good = _document->goodThumbnail();
|
const auto good = _document->goodThumbnail();
|
||||||
const auto useGood = (good && good->loaded());
|
const auto useGood = (good && good->loaded());
|
||||||
const auto original = useGood ? good->size() : _document->dimensions;
|
const auto original = useGood ? good->size() : _document->dimensions;
|
||||||
_panel.setAspectRatio(original.isEmpty() ? QSize(1, 1) : original);
|
return original.isEmpty() ? QSize(1, 1) : original;
|
||||||
} else {
|
}();
|
||||||
_panel.setAspectRatio(size);
|
_panel.setAspectRatio(FlipSizeByRotation(size, _rotation));
|
||||||
}
|
|
||||||
_panel.setPosition(Deserialize(_delegate->pipLoadGeometry()));
|
_panel.setPosition(Deserialize(_delegate->pipLoadGeometry()));
|
||||||
_panel.show();
|
_panel.show();
|
||||||
|
|
||||||
@ -1022,11 +1112,25 @@ void Pip::setupStreaming() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Pip::paint(QPainter &p, FrameRequest request) {
|
void Pip::paint(QPainter &p, FrameRequest request) {
|
||||||
const auto image = videoFrameForDirectPaint(request);
|
const auto image = videoFrameForDirectPaint(
|
||||||
|
UnrotateRequest(request, _rotation));
|
||||||
const auto inner = _panel.inner();
|
const auto inner = _panel.inner();
|
||||||
p.drawImage(
|
const auto rect = QRect{
|
||||||
QRect{ inner.topLeft(), request.outer / style::DevicePixelRatio() },
|
inner.topLeft(),
|
||||||
image);
|
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()) {
|
if (_instance.player().ready()) {
|
||||||
_instance.markFrameShown();
|
_instance.markFrameShown();
|
||||||
}
|
}
|
||||||
@ -1149,7 +1253,8 @@ void Pip::handleStreamingUpdate(Streaming::Update &&update) {
|
|||||||
using namespace Streaming;
|
using namespace Streaming;
|
||||||
|
|
||||||
update.data.match([&](Information &update) {
|
update.data.match([&](Information &update) {
|
||||||
_panel.setAspectRatio(update.video.size);
|
_panel.setAspectRatio(
|
||||||
|
FlipSizeByRotation(update.video.size, _rotation));
|
||||||
}, [&](const PreloadedVideo &update) {
|
}, [&](const PreloadedVideo &update) {
|
||||||
updatePlaybackState();
|
updatePlaybackState();
|
||||||
}, [&](const UpdateVideo &update) {
|
}, [&](const UpdateVideo &update) {
|
||||||
|
@ -29,6 +29,11 @@ namespace View {
|
|||||||
|
|
||||||
class PlaybackProgress;
|
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
|
#if defined Q_OS_MAC && !defined OS_MAC_OLD
|
||||||
#define USE_OPENGL_OVERLAY_WIDGET
|
#define USE_OPENGL_OVERLAY_WIDGET
|
||||||
#endif // Q_OS_MAC && !OS_MAC_OLD
|
#endif // Q_OS_MAC && !OS_MAC_OLD
|
||||||
@ -204,6 +209,7 @@ private:
|
|||||||
bool _pausedBySeek = false;
|
bool _pausedBySeek = false;
|
||||||
QString _timeAlready, _timeLeft;
|
QString _timeAlready, _timeLeft;
|
||||||
int _timeLeftWidth = 0;
|
int _timeLeftWidth = 0;
|
||||||
|
int _rotation = 0;
|
||||||
crl::time _seekPositionMs = -1;
|
crl::time _seekPositionMs = -1;
|
||||||
crl::time _lastDurationMs = 0;
|
crl::time _lastDurationMs = 0;
|
||||||
OverState _over = OverState::None;
|
OverState _over = OverState::None;
|
||||||
|
Loading…
Reference in New Issue
Block a user