diff --git a/Telegram/SourceFiles/api/api_credits.cpp b/Telegram/SourceFiles/api/api_credits.cpp index 0453cfc4f..6c0a7324a 100644 --- a/Telegram/SourceFiles/api/api_credits.cpp +++ b/Telegram/SourceFiles/api/api_credits.cpp @@ -39,8 +39,8 @@ constexpr auto kTransactionsLimit = 100; if (const auto list = tl.data().vextended_media()) { extended.reserve(list->v.size()); for (const auto &media : list->v) { - media.match([&](const MTPDmessageMediaPhoto &photo) { - if (const auto inner = photo.vphoto()) { + media.match([&](const MTPDmessageMediaPhoto &data) { + if (const auto inner = data.vphoto()) { const auto photo = owner->processPhoto(*inner); if (!photo->isNull()) { extended.push_back(CreditsHistoryMedia{ @@ -49,9 +49,11 @@ constexpr auto kTransactionsLimit = 100; }); } } - }, [&](const MTPDmessageMediaDocument &document) { - if (const auto inner = document.vdocument()) { - const auto document = owner->processDocument(*inner); + }, [&](const MTPDmessageMediaDocument &data) { + if (const auto inner = data.vdocument()) { + const auto document = owner->processDocument( + *inner, + data.valt_documents()); if (document->isAnimation() || document->isVideoFile() || document->isGifv()) { diff --git a/Telegram/SourceFiles/data/components/sponsored_messages.cpp b/Telegram/SourceFiles/data/components/sponsored_messages.cpp index 7de46e59f..d2746ad9a 100644 --- a/Telegram/SourceFiles/data/components/sponsored_messages.cpp +++ b/Telegram/SourceFiles/data/components/sponsored_messages.cpp @@ -346,7 +346,9 @@ void SponsoredMessages::append( }, [&](const MTPDmessageMediaDocument &media) { if (const auto tlDocument = media.vdocument()) { tlDocument->match([&](const MTPDdocument &data) { - const auto d = history->owner().processDocument(data); + const auto d = history->owner().processDocument( + data, + media.valt_documents()); if (d->isVideoFile() || d->isSilentVideo() || d->isAnimation() diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp index 5456ef280..d4306b2fb 100644 --- a/Telegram/SourceFiles/data/data_document.cpp +++ b/Telegram/SourceFiles/data/data_document.cpp @@ -332,6 +332,8 @@ void DocumentData::setattributes( validateLottieSticker(); + auto wasVideoData = isVideoFile() ? std::move(_additional) : nullptr; + _videoPreloadPrefix = 0; for (const auto &attribute : attributes) { attribute.match([&](const MTPDdocumentAttributeImageSize &data) { @@ -388,11 +390,21 @@ void DocumentData::setattributes( : VideoDocument; if (data.is_round_message()) { _additional = std::make_unique(); - } else if (const auto size = data.vpreload_prefix_size()) { - if (size->v > 0 && size->v < kMaxAllowedPreloadPrefix) { - _videoPreloadPrefix = size->v; + } else { + if (const auto size = data.vpreload_prefix_size()) { + if (size->v > 0 + && size->v < kMaxAllowedPreloadPrefix) { + _videoPreloadPrefix = size->v; + } } + _additional = wasVideoData + ? std::move(wasVideoData) + : std::make_unique(); + video()->codec = qs( + data.vvideo_codec().value_or_empty()); } + } else if (type == VideoDocument && wasVideoData) { + _additional = std::move(wasVideoData); } else if (const auto info = sticker()) { info->type = StickerType::Webm; } @@ -511,6 +523,67 @@ void DocumentData::setattributes( } } +void DocumentData::setVideoQualities(const QVector &list) { + auto qualities = std::vector>(); + qualities.reserve(list.size()); + for (const auto &document : list) { + qualities.push_back(owner().processDocument(document)); + } + setVideoQualities(std::move(qualities)); +} + +void DocumentData::setVideoQualities( + std::vector> qualities) { + const auto data = video(); + if (!data) { + return; + } + auto count = int(qualities.size()); + if (qualities.empty()) { + return; + } + const auto good = [&](not_null document) { + return document->isVideoFile() + && !document->dimensions.isEmpty() + && !document->inappPlaybackFailed() + && document->useStreamingLoader() + && document->canBeStreamed(nullptr); + }; + ranges::sort( + qualities, + ranges::greater(), + &DocumentData::resolveVideoQuality); + for (auto i = 0; i != count - 1;) { + const auto my = qualities[i]; + const auto next = qualities[i + 1]; + const auto myQuality = my->resolveVideoQuality(); + const auto nextQuality = next->resolveVideoQuality(); + const auto myGood = good(my); + const auto nextGood = good(next); + if (!myGood || !nextGood || myQuality == nextQuality) { + const auto removeMe = !myGood + || (nextGood && (my->size > next->size)); + const auto from = i + (removeMe ? 1 : 2); + for (auto j = from; j != count; ++j) { + qualities[j - 1] = qualities[j]; + } + --count; + } else { + ++i; + } + } + if (!qualities[count - 1]->resolveVideoQuality()) { + --count; + } + qualities.erase(qualities.begin() + count, qualities.end()); + data->qualities = std::move(qualities); +} + +int DocumentData::resolveVideoQuality() const { + const auto size = isVideoFile() ? dimensions : QSize(); + return size.isEmpty() ? 0 : std::min(size.width(), size.height()); +} + void DocumentData::validateLottieSticker() { if (type == FileDocument && hasMimeType(u"application/x-tgsticker"_q)) { @@ -1384,6 +1457,16 @@ const RoundData *DocumentData::round() const { return const_cast(this)->round(); } +VideoData *DocumentData::video() { + return isVideoFile() + ? static_cast(_additional.get()) + : nullptr; +} + +const VideoData *DocumentData::video() const { + return const_cast(this)->video(); +} + bool DocumentData::hasRemoteLocation() const { return (_dc != 0 && _access != 0); } diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h index 47237b3c4..ceba0e875 100644 --- a/Telegram/SourceFiles/data/data_document.h +++ b/Telegram/SourceFiles/data/data_document.h @@ -92,6 +92,11 @@ struct VoiceData : public DocumentAdditionalData { char wavemax = 0; }; +struct VideoData : public DocumentAdditionalData { + QString codec; + std::vector> qualities; +}; + using RoundData = VoiceData; namespace Serialize { @@ -108,8 +113,11 @@ public: void setattributes( const QVector &attributes); + void setVideoQualities(const QVector &list); void automaticLoadSettingsChanged(); + void setVideoQualities(std::vector> qualities); + [[nodiscard]] int resolveVideoQuality() const; [[nodiscard]] bool loading() const; [[nodiscard]] QString loadingFilePath() const; @@ -161,6 +169,8 @@ public: [[nodiscard]] const VoiceData *voice() const; [[nodiscard]] RoundData *round(); [[nodiscard]] const RoundData *round() const; + [[nodiscard]] VideoData *video(); + [[nodiscard]] const VideoData *video() const; void forceIsStreamedAnimation(); [[nodiscard]] bool isVoiceMessage() const; diff --git a/Telegram/SourceFiles/data/data_file_origin.cpp b/Telegram/SourceFiles/data/data_file_origin.cpp index 76838edc3..48f2be854 100644 --- a/Telegram/SourceFiles/data/data_file_origin.cpp +++ b/Telegram/SourceFiles/data/data_file_origin.cpp @@ -87,6 +87,7 @@ struct FileReferenceAccumulator { push(data.vphoto()); }, [&](const MTPDmessageMediaDocument &data) { push(data.vdocument()); + push(data.valt_documents()); }, [&](const MTPDmessageMediaWebPage &data) { push(data.vwebpage()); }, [&](const MTPDmessageMediaGame &data) { diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 9ce94052f..14be85c06 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -3139,17 +3139,24 @@ not_null Session::document(DocumentId id) { return i->second.get(); } -not_null Session::processDocument(const MTPDocument &data) { +not_null Session::processDocument( + const MTPDocument &data, + const MTPVector *qualities) { return data.match([&](const MTPDdocument &data) { - return processDocument(data); + return processDocument(data, qualities); }, [&](const MTPDdocumentEmpty &data) { return document(data.vid().v); }); } -not_null Session::processDocument(const MTPDdocument &data) { +not_null Session::processDocument( + const MTPDdocument &data, + const MTPVector *qualities) { const auto result = document(data.vid().v); documentApplyFields(result, data); + if (qualities) { + result->setVideoQualities(qualities->v); + } return result; } diff --git a/Telegram/SourceFiles/data/data_session.h b/Telegram/SourceFiles/data/data_session.h index a87e7e604..654cfdba3 100644 --- a/Telegram/SourceFiles/data/data_session.h +++ b/Telegram/SourceFiles/data/data_session.h @@ -558,8 +558,12 @@ public: const ImageLocation &thumbnailLocation); [[nodiscard]] not_null document(DocumentId id); - not_null processDocument(const MTPDocument &data); - not_null processDocument(const MTPDdocument &data); + not_null processDocument( + const MTPDocument &data, + const MTPVector *qualities = nullptr); + not_null processDocument( + const MTPDdocument &data, + const MTPVector *qualities = nullptr); not_null processDocument( const MTPdocument &data, const ImageWithLocation &thumbnail); diff --git a/Telegram/SourceFiles/data/data_stories.cpp b/Telegram/SourceFiles/data/data_stories.cpp index 0d9671f53..bb08bca5d 100644 --- a/Telegram/SourceFiles/data/data_stories.cpp +++ b/Telegram/SourceFiles/data/data_stories.cpp @@ -62,7 +62,9 @@ using UpdateFlag = StoryUpdate::Flag; }, [&](const MTPDmessageMediaDocument &data) -> std::optional { if (const auto document = data.vdocument()) { - const auto result = owner->processDocument(*document); + const auto result = owner->processDocument( + *document, + data.valt_documents()); if (!result->isNull() && (result->isGifv() || result->isVideoFile())) { result->setStoryMedia(true); diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index ddb539d82..afdeb386c 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -299,7 +299,9 @@ std::unique_ptr HistoryItem::CreateMedia( return document->match([&](const MTPDdocument &document) -> Result { return std::make_unique( item, - item->history()->owner().processDocument(document), + item->history()->owner().processDocument( + document, + media.valt_documents()), media.is_nopremium(), media.is_spoiler(), media.vttl_seconds().value_or_empty());