Skip to content

Commit d103e9e

Browse files
committed
feat: support 8K video uploads and playback
1 parent 665a288 commit d103e9e

8 files changed

Lines changed: 46 additions & 16 deletions

File tree

Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ constexpr auto kAlignImageBy = 64;
4646
constexpr auto kImageFormat = QImage::Format_ARGB32_Premultiplied;
4747
constexpr auto kMaxScaleByAspectRatio = 16;
4848
constexpr auto kAvioBlockSize = 4096;
49-
constexpr auto kMaxFrameStorageBytes = 64 * 1024 * 1024;
49+
constexpr auto kMaxFrameStorageBytes = 128 * 1024 * 1024;
5050
constexpr auto kMaxPixelsPaddingRatio = 32;
5151
constexpr auto kMaxPixelsFixedPadding = 64 * 1024;
5252
constexpr auto kTimeUnknown = std::numeric_limits<crl::time>::min();

Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace {
1818

1919
constexpr auto kSkipInvalidDataPackets = 10;
2020
constexpr auto kMaxInlineArea = 1280 * 720;
21-
constexpr auto kMaxSendingArea = 3840 * 2160; // usual 4K
21+
constexpr auto kMaxSendingArea = 7680 * 4320; // usual 8K
2222

2323
[[nodiscard]] auto MaxAreaForMode(ReaderImplementation::Mode mode) {
2424
return (mode == ReaderImplementation::Mode::Inspecting)
@@ -168,6 +168,14 @@ crl::time FFMpegReaderImplementation::framePresentationTime() const {
168168
return qMax(_frameTime + _frameTimeCorrection, crl::time(0));
169169
}
170170

171+
QSize FFMpegReaderImplementation::frameSize() const {
172+
auto result = QSize(_frame->width, _frame->height);
173+
if (rotationSwapWidthHeight()) {
174+
result.transpose();
175+
}
176+
return result;
177+
}
178+
171179
crl::time FFMpegReaderImplementation::durationMs() const {
172180
const auto rebase = [](int64_t duration, const AVRational &base) {
173181
return (duration * 1000LL * base.num) / base.den;

Telegram/SourceFiles/media/clip/media_clip_ffmpeg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class FFMpegReaderImplementation : public ReaderImplementation {
3232

3333
crl::time frameRealTime() const override;
3434
crl::time framePresentationTime() const override;
35+
QSize frameSize() const override;
3536

3637
bool renderFrame(
3738
QImage &to,

Telegram/SourceFiles/media/clip/media_clip_implementation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class ReaderImplementation {
4040
// Get current frame real and presentation time.
4141
virtual crl::time frameRealTime() const = 0;
4242
virtual crl::time framePresentationTime() const = 0;
43+
virtual QSize frameSize() const = 0;
4344

4445
// Render current frame to an image with specific size.
4546
virtual bool renderFrame(

Telegram/SourceFiles/media/clip/media_clip_reader.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ namespace {
3535

3636
constexpr auto kClipThreadsCount = 8;
3737
constexpr auto kAverageGifSize = 320 * 240;
38+
constexpr auto kPreparedVideoThumbnailSide = 320;
3839
constexpr auto kWaitBeforeGifPause = crl::time(200);
3940

4041
QImage PrepareFrame(
@@ -493,13 +494,12 @@ class ReaderPrivate {
493494
if (reader->start(internal::ReaderImplementation::Mode::Silent, firstFramePositionMs)) {
494495
auto firstFrameReadResult = reader->readFramesTill(-1, ms);
495496
if (firstFrameReadResult == internal::ReaderImplementation::ReadResult::Success) {
496-
if (reader->renderFrame(frame()->original, frame()->alpha, frame()->index, QSize())) {
497-
frame()->original.fill(QColor(0, 0, 0));
498-
497+
const auto dimensions = reader->frameSize();
498+
if (!dimensions.isEmpty()) {
499499
frame()->positionMs = _seekPositionMs;
500500

501-
_width = frame()->original.width();
502-
_height = frame()->original.height();
501+
_width = dimensions.width();
502+
_height = dimensions.height();
503503
_durationMs = _implementation->durationMs();
504504
return ProcessResult::Started;
505505
}
@@ -510,13 +510,14 @@ class ReaderPrivate {
510510
} else if (readResult != internal::ReaderImplementation::ReadResult::Success) { // Read the first frame.
511511
return error();
512512
}
513-
if (!_implementation->renderFrame(frame()->original, frame()->alpha, frame()->index, QSize())) {
513+
const auto dimensions = _implementation->frameSize();
514+
if (dimensions.isEmpty()) {
514515
return error();
515516
}
516517
frame()->positionMs = _implementation->frameRealTime();
517518

518-
_width = frame()->original.width();
519-
_height = frame()->original.height();
519+
_width = dimensions.width();
520+
_height = dimensions.height();
520521
_durationMs = _implementation->durationMs();
521522
return ProcessResult::Started;
522523
}
@@ -784,6 +785,8 @@ bool Manager::handleProcessResult(ReaderPrivate *reader, ProcessResult result, c
784785

785786
if (result == ProcessResult::Started) {
786787
_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - kAverageGifSize);
788+
it.key()->_width = reader->_width;
789+
it.key()->_height = reader->_height;
787790
it.key()->_durationMs = reader->_durationMs;
788791
}
789792
// See if we need to pause GIF because it is not displayed right now.
@@ -990,7 +993,13 @@ Ui::PreparedFileInformation PrepareForSending(
990993
auto hasAlpha = false;
991994
auto readResult = reader->readFramesTill(-1, crl::now());
992995
auto readFrame = (readResult == internal::ReaderImplementation::ReadResult::Success);
993-
if (readFrame && reader->renderFrame(result.thumbnail, hasAlpha, index, QSize())) {
996+
const auto dimensions = reader->frameSize();
997+
result.dimensions = dimensions;
998+
const auto thumbnailSize = dimensions.scaled(
999+
kPreparedVideoThumbnailSide,
1000+
kPreparedVideoThumbnailSide,
1001+
Qt::KeepAspectRatio);
1002+
if (readFrame && reader->renderFrame(result.thumbnail, hasAlpha, index, thumbnailSize)) {
9941003
if (hasAlpha && !result.isWebmSticker) {
9951004
result.thumbnail = Images::Opaque(std::move(result.thumbnail));
9961005
}

Telegram/SourceFiles/media/streaming/media_streaming_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ bool SupportsSpeedControl();
2323

2424
namespace Streaming {
2525

26-
inline constexpr auto kMaxFrameArea = 3840 * 2160;
26+
inline constexpr auto kMaxFrameArea = 7680 * 4320;
2727

2828
inline bool SupportsSpeedControl() {
2929
return Media::Audio::SupportsSpeedControl();

Telegram/SourceFiles/storage/localimageloader.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ struct PreparedFileThumbnail {
9494
return result;
9595
}
9696

97+
[[nodiscard]] QSize VideoDimensions(
98+
const Ui::PreparedFileInformation::Video &video) {
99+
return video.dimensions.isEmpty()
100+
? video.thumbnail.size()
101+
: video.dimensions;
102+
}
103+
97104
[[nodiscard]] bool FileThumbnailUploadRequired(
98105
const QString &filemime,
99106
int64 filesize) {
@@ -815,8 +822,9 @@ void FileLoadTask::process(ProcessArgs &&args) {
815822
if (auto video = std::get_if<Ui::PreparedFileInformation::Video>(
816823
&_information->media)) {
817824
isVideo = true;
818-
auto coverWidth = video->thumbnail.width();
819-
auto coverHeight = video->thumbnail.height();
825+
const auto dimensions = VideoDimensions(*video);
826+
auto coverWidth = dimensions.width();
827+
auto coverHeight = dimensions.height();
820828
if (video->isGifv && !_album) {
821829
attributes.push_back(MTP_documentAttributeAnimated());
822830
}
@@ -859,8 +867,9 @@ void FileLoadTask::process(ProcessArgs &&args) {
859867
} else if (auto video = std::get_if<Ui::PreparedFileInformation::Video>(
860868
&_information->media)) {
861869
isVideo = true;
862-
auto coverWidth = video->thumbnail.width();
863-
auto coverHeight = video->thumbnail.height();
870+
const auto dimensions = VideoDimensions(*video);
871+
auto coverWidth = dimensions.width();
872+
auto coverHeight = dimensions.height();
864873
if (!_forceFile) {
865874
if (video->isGifv && !_album) {
866875
attributes.push_back(MTP_documentAttributeAnimated());

Telegram/SourceFiles/ui/chat/attach/attach_prepare.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ For license and copyright information please follow this link:
1212
#include "ui/rect_part.h"
1313

1414
#include <QtCore/QSemaphore>
15+
#include <QtCore/QSize>
1516
#include <deque>
1617

1718
class QPainter;
@@ -44,6 +45,7 @@ struct PreparedFileInformation {
4445
bool isWebmSticker = false;
4546
bool supportsStreaming = false;
4647
crl::time duration = -1;
48+
QSize dimensions;
4749
QImage thumbnail;
4850
};
4951

0 commit comments

Comments
 (0)