mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 00:08:02 +00:00
Fix inline player for rotated videos.
This commit is contained in:
parent
10c810ff03
commit
a2b6e05cdf
@ -85,9 +85,14 @@ FFmpeg::AvErrorWrap ReadNextFrame(Stream &stream) {
|
||||
return error;
|
||||
}
|
||||
|
||||
bool GoodForRequest(const QImage &image, const FrameRequest &request) {
|
||||
bool GoodForRequest(
|
||||
const QImage &image,
|
||||
int rotation,
|
||||
const FrameRequest &request) {
|
||||
if (request.resize.isEmpty()) {
|
||||
return true;
|
||||
} else if (rotation != 0) {
|
||||
return false;
|
||||
} else if ((request.radius != ImageRoundRadius::None)
|
||||
&& ((request.corners & RectPart::AllCorners) != 0)) {
|
||||
return false;
|
||||
@ -174,8 +179,95 @@ QImage ConvertFrame(
|
||||
return storage;
|
||||
}
|
||||
|
||||
void PaintFrameOuter(QPainter &p, const QRect &inner, QSize outer) {
|
||||
const auto left = inner.x();
|
||||
const auto right = outer.width() - inner.width() - left;
|
||||
const auto top = inner.y();
|
||||
const auto bottom = outer.height() - inner.height() - top;
|
||||
if (left > 0) {
|
||||
p.fillRect(0, 0, left, outer.height(), st::imageBg);
|
||||
}
|
||||
if (right > 0) {
|
||||
p.fillRect(
|
||||
outer.width() - right,
|
||||
0,
|
||||
right,
|
||||
outer.height(),
|
||||
st::imageBg);
|
||||
}
|
||||
if (top > 0) {
|
||||
p.fillRect(left, 0, inner.width(), top, st::imageBg);
|
||||
}
|
||||
if (bottom > 0) {
|
||||
p.fillRect(
|
||||
left,
|
||||
outer.height() - bottom,
|
||||
inner.width(),
|
||||
bottom,
|
||||
st::imageBg);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintFrameInner(
|
||||
QPainter &p,
|
||||
QRect to,
|
||||
const QImage &original,
|
||||
int rotation) {
|
||||
const auto rotated = [](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 PaintFrameInner.");
|
||||
};
|
||||
|
||||
PainterHighQualityEnabler hq(p);
|
||||
if (rotation) {
|
||||
p.rotate(rotation);
|
||||
}
|
||||
p.drawImage(rotated(to, rotation), original);
|
||||
}
|
||||
|
||||
void PaintFrameContent(
|
||||
QPainter &p,
|
||||
const QImage &original,
|
||||
int rotation,
|
||||
const FrameRequest &request) {
|
||||
const auto full = request.outer;
|
||||
const auto to = QRect(
|
||||
(full.width() - request.resize.width()) / 2,
|
||||
(full.height() - request.resize.height()) / 2,
|
||||
request.resize.width(),
|
||||
request.resize.height());
|
||||
PaintFrameOuter(p, to, full);
|
||||
PaintFrameInner(p, to, original, rotation);
|
||||
}
|
||||
|
||||
void ApplyFrameRounding(QImage &storage, const FrameRequest &request) {
|
||||
if (!(request.corners & RectPart::AllCorners)
|
||||
|| (request.radius == ImageRoundRadius::None)) {
|
||||
return;
|
||||
}
|
||||
Images::prepareRound(storage, request.radius, request.corners);
|
||||
}
|
||||
|
||||
QImage PrepareByRequest(
|
||||
const QImage &original,
|
||||
int rotation,
|
||||
const FrameRequest &request,
|
||||
QImage storage) {
|
||||
Expects(!request.outer.isEmpty());
|
||||
@ -183,16 +275,12 @@ QImage PrepareByRequest(
|
||||
if (!FFmpeg::GoodStorageForFrame(storage, request.outer)) {
|
||||
storage = FFmpeg::CreateFrameStorage(request.outer);
|
||||
}
|
||||
{
|
||||
Painter p(&storage);
|
||||
PainterHighQualityEnabler hq(p);
|
||||
p.drawImage(QRect(QPoint(), request.outer), original);
|
||||
}
|
||||
if ((request.corners & RectPart::AllCorners)
|
||||
&& (request.radius != ImageRoundRadius::None)) {
|
||||
Images::prepareRound(storage, request.radius, request.corners);
|
||||
}
|
||||
// #TODO streaming later full prepare support.
|
||||
|
||||
QPainter p(&storage);
|
||||
PaintFrameContent(p, original, rotation, request);
|
||||
p.end();
|
||||
|
||||
ApplyFrameRounding(storage, request);
|
||||
return storage;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ struct Stream {
|
||||
|
||||
[[nodiscard]] bool GoodForRequest(
|
||||
const QImage &image,
|
||||
int rotation,
|
||||
const FrameRequest &request);
|
||||
[[nodiscard]] QImage ConvertFrame(
|
||||
Stream &stream,
|
||||
@ -59,6 +60,7 @@ struct Stream {
|
||||
QImage storage);
|
||||
[[nodiscard]] QImage PrepareByRequest(
|
||||
const QImage &original,
|
||||
int rotation,
|
||||
const FrameRequest &request,
|
||||
QImage storage);
|
||||
|
||||
|
@ -351,7 +351,7 @@ void VideoTrackObject::presentFrameIfNeeded() {
|
||||
return;
|
||||
}
|
||||
|
||||
VideoTrack::PrepareFrameByRequests(frame);
|
||||
VideoTrack::PrepareFrameByRequests(frame, _stream.rotation);
|
||||
|
||||
Ensures(VideoTrack::IsRasterized(frame));
|
||||
};
|
||||
@ -855,7 +855,7 @@ VideoTrack::VideoTrack(
|
||||
: _streamIndex(stream.index)
|
||||
, _streamTimeBase(stream.timeBase)
|
||||
, _streamDuration(stream.duration)
|
||||
//, _streamRotation(stream.rotation)
|
||||
, _streamRotation(stream.rotation)
|
||||
//, _streamAspect(stream.aspect)
|
||||
, _shared(std::make_unique<Shared>())
|
||||
, _wrapped(
|
||||
@ -955,7 +955,7 @@ QImage VideoTrack::frame(
|
||||
unwrapped.updateFrameRequest(instance, request);
|
||||
});
|
||||
}
|
||||
if (GoodForRequest(frame->original, useRequest)) {
|
||||
if (GoodForRequest(frame->original, _streamRotation, useRequest)) {
|
||||
return frame->original;
|
||||
} else if (changed || none || i->second.image.isNull()) {
|
||||
const auto j = none
|
||||
@ -975,6 +975,7 @@ QImage VideoTrack::frame(
|
||||
}
|
||||
j->second.image = PrepareByRequest(
|
||||
frame->original,
|
||||
_streamRotation,
|
||||
useRequest,
|
||||
std::move(j->second.image));
|
||||
return j->second.image;
|
||||
@ -988,14 +989,16 @@ void VideoTrack::unregisterInstance(not_null<const Instance*> instance) {
|
||||
});
|
||||
}
|
||||
|
||||
void VideoTrack::PrepareFrameByRequests(not_null<Frame*> frame) {
|
||||
void VideoTrack::PrepareFrameByRequests(
|
||||
not_null<Frame*> frame,
|
||||
int rotation) {
|
||||
Expects(!frame->original.isNull());
|
||||
|
||||
const auto begin = frame->prepared.begin();
|
||||
const auto end = frame->prepared.end();
|
||||
for (auto i = begin; i != end; ++i) {
|
||||
auto &prepared = i->second;
|
||||
if (!GoodForRequest(frame->original, prepared.request)) {
|
||||
if (!GoodForRequest(frame->original, rotation, prepared.request)) {
|
||||
auto j = begin;
|
||||
for (; j != i; ++j) {
|
||||
if (j->second.request == prepared.request) {
|
||||
@ -1006,6 +1009,7 @@ void VideoTrack::PrepareFrameByRequests(not_null<Frame*> frame) {
|
||||
if (j == i) {
|
||||
prepared.image = PrepareByRequest(
|
||||
frame->original,
|
||||
rotation,
|
||||
prepared.request,
|
||||
std::move(prepared.image));
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
static void PrepareFrameByRequests(not_null<Frame*> frame);
|
||||
static void PrepareFrameByRequests(not_null<Frame*> frame, int rotation);
|
||||
[[nodiscard]] static bool IsDecoded(not_null<const Frame*> frame);
|
||||
[[nodiscard]] static bool IsRasterized(not_null<const Frame*> frame);
|
||||
[[nodiscard]] static bool IsStale(
|
||||
@ -149,7 +149,7 @@ private:
|
||||
const int _streamIndex = 0;
|
||||
const AVRational _streamTimeBase;
|
||||
const crl::time _streamDuration = 0;
|
||||
//const int _streamRotation = 0;
|
||||
const int _streamRotation = 0;
|
||||
//AVRational _streamAspect = kNormalAspect;
|
||||
std::unique_ptr<Shared> _shared;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user