@@ -544,11 +544,12 @@ void DocumentData::setVideoQualities(
544544 return ;
545545 }
546546 const auto good = [&](not_null<DocumentData*> document) {
547+ // Transcodes in alt_documents are always streamable,
548+ // even if the supports_streaming flag is missing
547549 return document->isVideoFile ()
548550 && !document->dimensions .isEmpty ()
549551 && !document->inappPlaybackFailed ()
550- && document->useStreamingLoader ()
551- && document->canBeStreamed ();
552+ && document->useStreamingLoader ();
552553 };
553554 ranges::sort (
554555 qualities,
@@ -578,18 +579,65 @@ void DocumentData::setVideoQualities(
578579 }
579580 qualities.erase (qualities.begin () + count, qualities.end ());
580581 if (!qualities.empty ()) {
581- if (const auto mine = resolveVideoQuality ()) {
582- if (mine > qualities.front ()->resolveVideoQuality ()) {
583- qualities.insert (begin (qualities), this );
582+ auto transcodeMax = 0 ;
583+ for (const auto &quality : qualities) {
584+ const auto qres = quality->resolveVideoQuality ();
585+ if (qres > transcodeMax) {
586+ transcodeMax = qres;
584587 }
585588 }
589+ const auto apiSize = isVideoFile () ? dimensions : QSize ();
590+ const auto api = apiSize.isEmpty ()
591+ ? 0
592+ : std::min (apiSize.width (), apiSize.height ());
593+
594+ // Heuristic: Trust API resolution unless it blatantly
595+ // contradicts server-side transcodes (>1.5x delta)
596+ auto mine = (transcodeMax > 0
597+ && (api < transcodeMax || api > transcodeMax * 1.5 ))
598+ ? transcodeMax
599+ : api;
600+ if (mine) {
601+ qualities.insert (begin (qualities), this );
602+ }
586603 }
587604 data->qualities = std::move (qualities);
588605}
589606
590607int DocumentData::resolveVideoQuality () const {
591- const auto size = isVideoFile () ? dimensions : QSize ();
592- return size.isEmpty () ? 0 : std::min (size.width (), size.height ());
608+ if (const auto data = video ()) {
609+ if (!data->realVideoSize .isEmpty ()) {
610+ // Always trust FFmpeg-parsed physical resolution
611+ const auto size = data->realVideoSize ;
612+ return std::min (size.width (), size.height ());
613+ }
614+ const auto apiSize = isVideoFile () ? dimensions : QSize ();
615+ const auto api = apiSize.isEmpty ()
616+ ? 0
617+ : std::min (apiSize.width (), apiSize.height ());
618+ if (!data->qualities .empty ()) {
619+ auto transcodeMax = 0 ;
620+ for (const auto &quality : data->qualities ) {
621+ if (quality != this ) {
622+ const auto qres = quality->resolveVideoQuality ();
623+ if (qres > transcodeMax) {
624+ transcodeMax = qres;
625+ }
626+ }
627+ }
628+ if (transcodeMax > 0 ) {
629+ // Trust transcodes if attributes appear fake
630+ if (api < transcodeMax || api > transcodeMax * 1.5 ) {
631+ return transcodeMax;
632+ }
633+ return api;
634+ }
635+ }
636+ }
637+ const auto apiSize = isVideoFile () ? dimensions : QSize ();
638+ return apiSize.isEmpty ()
639+ ? 0
640+ : std::min (apiSize.width (), apiSize.height ());
593641}
594642
595643auto DocumentData::resolveQualities (HistoryItem *context) const
@@ -611,19 +659,30 @@ not_null<DocumentData*> DocumentData::chooseQuality(
611659 return this ;
612660 }
613661 const auto height = int (request.height );
614- auto closest = this ;
615- auto closestAbs = std::abs (height - resolveVideoQuality ());
616- auto closestSize = size;
662+ if (height >= Media::kVideoQualityOriginalOffset ) {
663+ return this ;
664+ }
665+
666+ auto closest = (DocumentData*)nullptr ;
667+ auto closestAbs = -1 ;
668+ auto closestSize = -1 ;
669+
617670 for (const auto &quality : list) {
618- const auto abs = std::abs (height - quality->resolveVideoQuality ());
619- if (abs < closestAbs
620- || (abs == closestAbs && quality->size < closestSize)) {
671+ const auto qres = quality->resolveVideoQuality ();
672+ const auto abs = std::abs (height - qres);
673+ // Prefer Original if it fits target resolution best,
674+ // falling back to transcode only on exact matches
675+ if (!closest
676+ || abs < closestAbs
677+ || (abs == closestAbs && (quality->size < closestSize
678+ || (closest == this && quality != this )))) {
621679 closest = quality;
622680 closestAbs = abs;
623681 closestSize = quality->size ;
624682 }
625683 }
626- return closest;
684+
685+ return closest ? closest : this ;
627686}
628687
629688void DocumentData::validateLottieSticker () {
0 commit comments