From 2255eb2c68ebc0873a16b84920395448741f8a72 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 31 May 2019 14:45:35 +0300 Subject: [PATCH] Show loaded till in playback slider. --- .../SourceFiles/media/audio/media_audio.h | 1 + .../media/streaming/media_streaming_common.h | 1 + .../media/streaming/media_streaming_file.cpp | 3 +- .../streaming/media_streaming_file_delegate.h | 1 + .../streaming/media_streaming_player.cpp | 9 +++- .../media/streaming/media_streaming_player.h | 2 +- .../streaming/media_streaming_reader.cpp | 8 +++ .../media/streaming/media_streaming_reader.h | 2 + .../view/media_view_playback_controls.cpp | 14 ++++- .../media/view/media_view_playback_controls.h | 2 + .../view/media_view_playback_progress.cpp | 54 +++++++++++-------- .../media/view/media_view_playback_progress.h | 14 ++--- 12 files changed, 78 insertions(+), 33 deletions(-) diff --git a/Telegram/SourceFiles/media/audio/media_audio.h b/Telegram/SourceFiles/media/audio/media_audio.h index e87bf581e..45fadf33e 100644 --- a/Telegram/SourceFiles/media/audio/media_audio.h +++ b/Telegram/SourceFiles/media/audio/media_audio.h @@ -119,6 +119,7 @@ struct TrackState { int64 receivedTill = 0; int64 length = 0; int frequency = kDefaultFrequency; + int fileHeaderSize = 0; bool waitingForData = false; }; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_common.h b/Telegram/SourceFiles/media/streaming/media_streaming_common.h index de70c8262..b3a7d976f 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_common.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_common.h @@ -63,6 +63,7 @@ struct AudioInformation { struct Information { VideoInformation video; AudioInformation audio; + int headerSize = 0; }; template diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp index 5b53285a5..01310b695 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_file.cpp @@ -251,7 +251,8 @@ void File::Context::start(crl::time position) { return; } - if (!_delegate->fileReady(std::move(video), std::move(audio))) { + const auto header = _reader->headerSize(); + if (!_delegate->fileReady(header, std::move(video), std::move(audio))) { return fail(Error::OpenFailed); } _format = std::move(format); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h b/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h index 475846127..b24271b21 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_file_delegate.h @@ -17,6 +17,7 @@ enum class Error; class FileDelegate { public: [[nodiscard]] virtual bool fileReady( + int headerSize, Stream &&video, Stream &&audio) = 0; virtual void fileError(Error error) = 0; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp index fc40f27e8..357da5d17 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp @@ -72,6 +72,9 @@ void SaveValidStartInformation(Information &to, Information &&from) { if (from.video.state.duration != kTimeUnknown) { SaveValidVideoInformation(to.video, std::move(from.video)); } + if (from.headerSize && !to.headerSize) { + to.headerSize = from.headerSize; + } } } // namespace @@ -209,12 +212,13 @@ void Player::videoPlayedTill(crl::time position) { trackPlayedTill(*_video, _information.video.state, position); } -bool Player::fileReady(Stream &&video, Stream &&audio) { +bool Player::fileReady(int headerSize, Stream &&video, Stream &&audio) { _waitingForData = false; const auto weak = base::make_weak(&_sessionGuard); const auto ready = [=](const Information &data) { crl::on_main(weak, [=, data = data]() mutable { + data.headerSize = headerSize; streamReady(std::move(data)); }); }; @@ -702,7 +706,9 @@ void Player::stop(bool stillActive) { _durationByPackets = 0; _durationByLastAudioPacket = 0; _durationByLastVideoPacket = 0; + const auto header = _information.headerSize; _information = Information(); + _information.headerSize = header; } std::optional Player::failed() const { @@ -801,6 +807,7 @@ Media::Player::TrackState Player::prepareLegacyState() const { ? getCurrentReceivedTill(result.length) : 0; result.frequency = kMsFrequency; + result.fileHeaderSize = _information.headerSize; if (result.length == kTimeUnknown) { const auto document = _options.audioId.audio(); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.h b/Telegram/SourceFiles/media/streaming/media_streaming_player.h index 4c5b74ec3..417472827 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.h @@ -79,7 +79,7 @@ private: not_null delegate(); // FileDelegate methods are called only from the File thread. - bool fileReady(Stream &&video, Stream &&audio) override; + bool fileReady(int headerSize, Stream &&video, Stream &&audio) override; void fileError(Error error) override; void fileWaitingForData() override; bool fileProcessPacket(Packet &&packet) override; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp index 2a083ea33..ee881be47 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_reader.cpp @@ -381,6 +381,10 @@ void Reader::Slices::headerDone(bool fromCache) { } } +int Reader::Slices::headerSize() const { + return _header.parts.size() * kPartSize; +} + bool Reader::Slices::headerWontBeFilled() const { return headerModeUnknown() && (_header.parts.size() >= kMaxPartsInHeader); @@ -1075,6 +1079,10 @@ void Reader::headerDone() { _slices.headerDone(false); } +int Reader::headerSize() const { + return _slices.headerSize(); +} + bool Reader::fill( int offset, bytes::span buffer, diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_reader.h b/Telegram/SourceFiles/media/streaming/media_streaming_reader.h index e631eaf2f..a8eb7a852 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_reader.h +++ b/Telegram/SourceFiles/media/streaming/media_streaming_reader.h @@ -49,6 +49,7 @@ public: not_null notify); [[nodiscard]] std::optional streamingError() const; void headerDone(); + [[nodiscard]] int headerSize() const; // Thread safe. void startSleep(not_null wake); @@ -133,6 +134,7 @@ private: Slices(int size, bool useCache); void headerDone(bool fromCache); + [[nodiscard]] int headerSize() const; [[nodiscard]] bool headerWontBeFilled() const; [[nodiscard]] bool headerModeUnknown() const; [[nodiscard]] bool isFullInHeader() const; diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp index 6284d0232..83445413f 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp @@ -154,10 +154,22 @@ void PlaybackControls::fadeUpdated(float64 opacity) { void PlaybackControls::updatePlayback(const Player::TrackState &state) { updatePlayPauseResumeState(state); - _playbackProgress->updateState(state); + _playbackProgress->updateState(state, countDownloadedTillPercent(state)); updateTimeTexts(state); } +float64 PlaybackControls::countDownloadedTillPercent( + const Player::TrackState &state) const { + if (_loadingReady > 0 && _loadingReady == _loadingTotal) { + return 1.; + } + const auto header = state.fileHeaderSize; + if (!header || _loadingReady <= header || _loadingTotal <= header) { + return 0.; + } + return (_loadingReady - header) / float64(_loadingTotal - header); +} + void PlaybackControls::setLoadingProgress(int ready, int total) { if (_loadingReady == ready && _loadingTotal == total) { return; diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.h b/Telegram/SourceFiles/media/view/media_view_playback_controls.h index 7f382eacc..0a2e11104 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.h +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.h @@ -64,6 +64,8 @@ private: void fadeFinished(); void fadeUpdated(float64 opacity); void refreshFadeCache(); + [[nodiscard]] float64 countDownloadedTillPercent( + const Player::TrackState &state) const; void updatePlayPauseResumeState(const Player::TrackState &state); void updateTimeTexts(const Player::TrackState &state); diff --git a/Telegram/SourceFiles/media/view/media_view_playback_progress.cpp b/Telegram/SourceFiles/media/view/media_view_playback_progress.cpp index 2979904c5..e09507427 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_progress.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_progress.cpp @@ -22,12 +22,14 @@ PlaybackProgress::PlaybackProgress() : _valueAnimation([=](crl::time now) { return valueAnimationCallback(now); }) -, _receivedTillAnimation([=](crl::time now) { - return receivedTillAnimationCallback(now); +, _availableTillAnimation([=](crl::time now) { + return availableTillAnimationCallback(now); }) { } -void PlaybackProgress::updateState(const Player::TrackState &state) { +void PlaybackProgress::updateState( + const Player::TrackState &state, + float64 loadedTillPercent) { _playing = !Player::IsStopped(state.state); const auto length = state.length; const auto position = Player::IsStoppedAtEnd(state.state) @@ -38,6 +40,12 @@ void PlaybackProgress::updateState(const Player::TrackState &state) { const auto receivedTill = (length && state.receivedTill > position) ? state.receivedTill : -1; + const auto loadedTill = (loadedTillPercent != 0.) + ? int64(std::floor(loadedTillPercent * length)) + : -1; + const auto availableTill = (length && loadedTill > position) + ? std::max(receivedTill, loadedTill) + : receivedTill; const auto wasInLoadingState = _inLoadingState; if (wasInLoadingState) { @@ -52,8 +60,8 @@ void PlaybackProgress::updateState(const Player::TrackState &state) { : length ? snap(float64(position) / length, 0., 1.) : 0.; - const auto receivedTillProgress = (receivedTill > position) - ? snap(float64(receivedTill) / length, 0., 1.) + const auto availableTillProgress = (availableTill > position) + ? snap(float64(availableTill) / length, 0., 1.) : -1.; const auto animatedPosition = position + (state.frequency * kPlaybackAnimationDurationMs / 1000); const auto animatedProgress = length ? qMax(float64(animatedPosition) / length, 0.) : 0.; @@ -66,9 +74,9 @@ void PlaybackProgress::updateState(const Player::TrackState &state) { _position = position; _length = length; } - if (receivedTill != _receivedTill) { - setReceivedTill(receivedTillProgress); - _receivedTill = receivedTill; + if (availableTill != _availableTill) { + setAvailableTill(availableTillProgress); + _availableTill = availableTill; } } @@ -99,18 +107,18 @@ void PlaybackProgress::setValue(float64 value, bool animated) { emitUpdatedValue(); } -void PlaybackProgress::setReceivedTill(float64 value) { - const auto current = a_receivedTill.current(); +void PlaybackProgress::setAvailableTill(float64 value) { + const auto current = a_availableTill.current(); if (value > current && current > 0.) { - receivedTillAnimationCallback(crl::now()); - a_receivedTill.start(value); - _receivedTillAnimation.start(); + availableTillAnimationCallback(crl::now()); + a_availableTill.start(value); + _availableTillAnimation.start(); } else if (value > a_value.current()) { - a_receivedTill = anim::value(a_value.current(), value); - _receivedTillAnimation.start(); + a_availableTill = anim::value(a_value.current(), value); + _availableTillAnimation.start(); } else { - a_receivedTill = anim::value(-1., -1.); - _receivedTillAnimation.stop(); + a_availableTill = anim::value(-1., -1.); + _availableTillAnimation.stop(); } emitUpdatedValue(); } @@ -129,15 +137,15 @@ bool PlaybackProgress::valueAnimationCallback(float64 now) { return (dt < 1.); } -bool PlaybackProgress::receivedTillAnimationCallback(float64 now) { - const auto time = now - _receivedTillAnimation.started(); +bool PlaybackProgress::availableTillAnimationCallback(float64 now) { + const auto time = now - _availableTillAnimation.started(); const auto dt = anim::Disabled() ? 1. : (time / kPlaybackAnimationDurationMs); if (dt >= 1.) { - a_receivedTill.finish(); + a_availableTill.finish(); } else { - a_receivedTill.update(dt, anim::linear); + a_availableTill.update(dt, anim::linear); } emitUpdatedValue(); return (dt < 1.); @@ -146,8 +154,8 @@ bool PlaybackProgress::receivedTillAnimationCallback(float64 now) { void PlaybackProgress::emitUpdatedValue() { if (_valueChanged) { const auto value = a_value.current(); - const auto receivedTill = a_receivedTill.current(); - _valueChanged(value, std::max(value, receivedTill)); + const auto availableTill = a_availableTill.current(); + _valueChanged(value, std::max(value, availableTill)); } } diff --git a/Telegram/SourceFiles/media/view/media_view_playback_progress.h b/Telegram/SourceFiles/media/view/media_view_playback_progress.h index 6a05f50ce..663c318cc 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_progress.h +++ b/Telegram/SourceFiles/media/view/media_view_playback_progress.h @@ -29,20 +29,22 @@ public: void setValue(float64 value, bool animated); float64 value() const; - void updateState(const Player::TrackState &state); + void updateState( + const Player::TrackState &state, + float64 loadedTillPercent = 0.); void updateLoadingState(float64 progress); private: bool valueAnimationCallback(float64 now); - bool receivedTillAnimationCallback(float64 now); - void setReceivedTill(float64 value); + bool availableTillAnimationCallback(float64 now); + void setAvailableTill(float64 value); void emitUpdatedValue(); // This can animate for a very long time (like in music playing), // so it should be a Basic, not a Simple animation, because // Simple-s pauses mtproto responses/updates handling while playing. - anim::value a_value, a_receivedTill; - Ui::Animations::Basic _valueAnimation, _receivedTillAnimation; + anim::value a_value, a_availableTill; + Ui::Animations::Basic _valueAnimation, _availableTillAnimation; Fn _valueChanged; bool _inLoadingState = false; @@ -50,7 +52,7 @@ private: int64 _position = 0; int64 _length = 0; - int64 _receivedTill = -1; + int64 _availableTill = -1; bool _playing = false;