Fix inline player for rotated videos.

This commit is contained in:
John Preston 2019-12-18 20:15:42 +03:00
parent 10c810ff03
commit a2b6e05cdf
4 changed files with 112 additions and 18 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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));
}

View File

@ -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;