diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index cc59896cb2..43d3400c81 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -78,6 +78,31 @@ static_assert(kDisplaySkipped != kTimeUnknown); return result; } +[[nodiscard]] float64 SafeRound(float64 value) { + Expects(!std::isnan(value)); + + if (const auto result = std::round(value); !std::isnan(result)) { + return result; + } + const auto errors = std::fetestexcept(FE_ALL_EXCEPT); + LOG(("Streaming Error: Got NAN in std::round(%1), fe: %2." + ).arg(value + ).arg(errors)); + if (const auto result = std::round(value); !std::isnan(result)) { + return result; + } + std::feclearexcept(FE_ALL_EXCEPT); + if (const auto result = std::round(value); !std::isnan(result)) { + return result; + } + CrashReports::SetAnnotation("FE-Error-Value", QString::number(value)); + CrashReports::SetAnnotation("FE-Errors-Were", QString::number(errors)); + CrashReports::SetAnnotation( + "FE-Errors-Now", + QString::number(std::fetestexcept(FE_ALL_EXCEPT))); + Unexpected("NAN after third std::round."); +} + } // namespace class VideoTrackObject final { @@ -379,6 +404,7 @@ void VideoTrackObject::debugLog(const QString &entry) const { _debugLog.push_back("stp.worldTime:" + QString::number(_syncTimePoint.worldTime) + ";stp.trackTime:" + QString::number(_syncTimePoint.trackTime) + + ";fe:" + QString::number(std::fetestexcept(FE_ALL_EXCEPT)) + ";" + entry); } @@ -826,8 +852,6 @@ void VideoTrackObject::callReady() { } TimePoint VideoTrackObject::trackTime() const { - const auto errors1 = std::fetestexcept(FE_ALL_EXCEPT); - debugAssertKnownTime(7, _syncTimePoint.trackTime); auto result = TimePoint(); @@ -855,28 +879,7 @@ TimePoint VideoTrackObject::trackTime() const { } const auto adjust = (result.worldTime - _syncTimePoint.worldTime); const auto adjustSpeed = adjust * _options.speed; - const auto errors2 = std::fetestexcept(FE_ALL_EXCEPT); - auto roundAdjustSpeed = std::round(adjustSpeed); - if (std::isnan(roundAdjustSpeed)) { - TO_LOG(("NAN1,errors1:%1,errors2:%2,errors:%3").arg(errors1).arg(errors2).arg(std::fetestexcept(FE_ALL_EXCEPT))); - roundAdjustSpeed = std::round(adjustSpeed); - if (!std::isnan(roundAdjustSpeed)) { - TO_LOG(("WELL2,adjust:%1,rounded:%2").arg(adjustSpeed).arg(roundAdjustSpeed)); - debugAssertKnownTime(-1, kTimeUnknown); - } else { - TO_LOG(("NAN2,adjust:%1").arg(adjustSpeed)); - } - std::feclearexcept(FE_ALL_EXCEPT); - const auto errors3 = std::fetestexcept(FE_ALL_EXCEPT); - roundAdjustSpeed = std::round(adjustSpeed); - if (!std::isnan(roundAdjustSpeed)) { - TO_LOG(("WELL3,adjust:%1,rounded:%2").arg(adjustSpeed).arg(roundAdjustSpeed)); - debugAssertKnownTime(-2, kTimeUnknown); - } else { - TO_LOG(("NAN3,adjust:%1,errors3:%2,errors:%3").arg(adjustSpeed).arg(errors3).arg(std::fetestexcept(FE_ALL_EXCEPT))); - } - TO_LOG(("qRound:%1,qRound64:%2").arg(qRound(adjustSpeed)).arg(qRound64(adjustSpeed))); - } + const auto roundAdjustSpeed = SafeRound(adjustSpeed); auto timeRoundAdjustSpeed = crl::time(roundAdjustSpeed); const auto fpuErrorHappened = [](crl::time value) { return uint64(value) == 0x8000'0000'0000'0000ULL @@ -1099,9 +1102,11 @@ auto VideoTrack::Shared::presentFrame( return { kTimeUnknown, kTimeUnknown, addedWorldTimeDelay }; } const auto trackLeft = position - time.trackTime; + const auto adjustedBySpeed = trackLeft / playbackSpeed; + const auto roundedAdjustedBySpeed = SafeRound(adjustedBySpeed); frame->display = time.worldTime + addedWorldTimeDelay - + crl::time(std::round(trackLeft / playbackSpeed)); + + crl::time(roundedAdjustedBySpeed); // Release this frame to the main thread for rendering. _counter.store(