Add limits on video frame size.

Any video that starts streaming is limited to 4K.
Any in-chat streaming is limited to full hd.
Any GIF panel animation is limited to 720p.
This commit is contained in:
John Preston 2020-03-23 16:59:46 +04:00
parent 2c0b852dad
commit 01c79f917e
4 changed files with 44 additions and 7 deletions

View file

@ -40,6 +40,7 @@ namespace {
constexpr auto kMaxGifForwardedBarLines = 4;
constexpr auto kUseNonBlurredThreshold = 240;
constexpr auto kMaxInlineArea = 1920 * 1080;
int gifMaxStatusWidth(DocumentData *document) {
auto result = st::normalFont->width(formatDownloadText(document->size, document->size));
@ -47,6 +48,11 @@ int gifMaxStatusWidth(DocumentData *document) {
return result;
}
[[nodiscard]] bool CanPlayInline(not_null<DocumentData*> document) {
const auto dimensions = document->dimensions;
return dimensions.width() * dimensions.height() <= kMaxInlineArea;
}
} // namespace
struct Gif::Streamed {
@ -261,7 +267,7 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
const auto selected = (selection == FullSelection);
const auto autoPaused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
const auto cornerDownload = downloadInCorner();
const auto canBePlayed = _data->canBePlayed();
const auto canBePlayed = _data->canBePlayed() && CanPlayInline(_data);
const auto autoplay = autoplayEnabled() && canBePlayed;
const auto activeRoundPlaying = activeRoundStreamed();
const auto startPlay = autoplay
@ -865,7 +871,7 @@ void Gif::drawGrouped(
const auto autoPaused = App::wnd()->sessionController()->isGifPausedAtLeastFor(Window::GifPauseReason::Any);
const auto fullFeatured = fullFeaturedGrouped(sides);
const auto cornerDownload = fullFeatured && downloadInCorner();
const auto canBePlayed = _data->canBePlayed();
const auto canBePlayed = _data->canBePlayed() && CanPlayInline(_data);;
const auto autoplay = fullFeatured && autoplayEnabled() && canBePlayed;
const auto startPlay = autoplay && !_streamed;
if (startPlay) {
@ -1404,7 +1410,13 @@ void Gif::repaintStreamedContent() {
}
void Gif::streamingReady(::Media::Streaming::Information &&info) {
history()->owner().requestViewResize(_parent);
if (info.video.size.width() * info.video.size.height()
> kMaxInlineArea) {
_data->dimensions = info.video.size;
stopAnimation();
} else {
history()->owner().requestViewResize(_parent);
}
}
void Gif::stopAnimation() {

View file

@ -35,6 +35,13 @@ namespace internal {
using TextState = HistoryView::TextState;
constexpr auto kMaxInlineArea = 1280 * 720;
[[nodiscard]] bool CanPlayInline(not_null<DocumentData*> document) {
const auto dimensions = document->dimensions;
return dimensions.width() * dimensions.height() <= kMaxInlineArea;
}
FileBase::FileBase(not_null<Context*> context, not_null<Result*> result)
: ItemBase(context, result) {
}
@ -141,7 +148,10 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
document->automaticLoad(fileOrigin(), nullptr);
bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !_gif && !_gif.isBad()) {
if (loaded
&& !_gif
&& !_gif.isBad()
&& CanPlayInline(document)) {
auto that = const_cast<Gif*>(this);
that->_gif = Media::Clip::MakeReader(document, FullMsgId(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
@ -371,9 +381,16 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
_gif.setBad();
getShownDocument()->unload();
} else if (_gif->ready() && !_gif->started()) {
auto height = st::inlineMediaHeight;
auto frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, RectPart::None);
if (_gif->width() * _gif->height() > kMaxInlineArea) {
getShownDocument()->dimensions = QSize(
_gif->width(),
_gif->height());
unloadAnimation();
} else {
auto height = st::inlineMediaHeight;
auto frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, RectPart::None);
}
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
unloadAnimation();
}

View file

@ -17,6 +17,7 @@ namespace internal {
namespace {
constexpr auto kSkipInvalidDataPackets = 10;
constexpr auto kMaxInlineArea = 1280 * 720;
// See https://github.com/telegramdesktop/tdesktop/issues/7225
constexpr auto kAlignImageBy = 64;
@ -59,6 +60,9 @@ ReaderImplementation::ReadResult FFMpegReaderImplementation::readNextFrame() {
do {
int res = avcodec_receive_frame(_codecContext, _frame.get());
if (res >= 0) {
if (_frame->width * _frame->height > kMaxInlineArea) {
return ReadResult::Error;
}
processReadFrame();
return ReadResult::Success;
}

View file

@ -14,6 +14,7 @@ namespace Media {
namespace Streaming {
namespace {
constexpr auto kMaxFrameArea = 3840 * 2160; // usual 4K
constexpr auto kDisplaySkipped = crl::time(-1);
constexpr auto kFinishedPosition = std::numeric_limits<crl::time>::max();
static_assert(kDisplaySkipped != kTimeUnknown);
@ -511,6 +512,9 @@ bool VideoTrackObject::tryReadFirstFrame(FFmpeg::Packet &&packet) {
}
bool VideoTrackObject::processFirstFrame() {
if (_stream.frame->width * _stream.frame->height >= kMaxFrameArea) {
return false;
}
auto frame = ConvertFrame(
_stream,
_stream.frame.get(),