From be495c17bc081407091afc1521b49c30b382a9ee Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 13 Mar 2019 16:02:59 +0400 Subject: [PATCH] Fix seek to video end. --- .../streaming/media_streaming_audio_track.cpp | 40 +++++++++++------ .../streaming/media_streaming_video_track.cpp | 45 +++++++++++-------- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp index f34ff6138..3e8c95761 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_audio_track.cpp @@ -69,28 +69,40 @@ bool AudioTrack::tryReadFirstFrame(Packet &&packet) { if (ProcessPacket(_stream, std::move(packet)).failed()) { return false; } - if (const auto error = ReadNextFrame(_stream)) { - if (error.code() == AVERROR_EOF) { - // Return the last valid frame if we seek too far. - return processFirstFrame(); - } else if (error.code() != AVERROR(EAGAIN) || _noMoreData) { + while (true) { + if (const auto error = ReadNextFrame(_stream)) { + if (error.code() == AVERROR_EOF) { + if (!_initialSkippingFrame) { + return false; + } + // Return the last valid frame if we seek too far. + _stream.frame = std::move(_initialSkippingFrame); + return processFirstFrame(); + } else if (error.code() != AVERROR(EAGAIN) || _noMoreData) { + return false; + } else { + // Waiting for more packets. + return true; + } + } else if (!fillStateFromFrame()) { return false; - } else { - // Waiting for more packets. - return true; + } else if (_startedPosition >= _options.position) { + return processFirstFrame(); } - } else if (!fillStateFromFrame()) { - return false; - } else if (_startedPosition < _options.position) { + // Seek was with AVSEEK_FLAG_BACKWARD so first we get old frames. // Try skipping frames until one is after the requested position. - return true; - } else { - return processFirstFrame(); + std::swap(_initialSkippingFrame, _stream.frame); + if (!_stream.frame) { + _stream.frame = MakeFramePointer(); + } } } bool AudioTrack::processFirstFrame() { + if (!FrameHasData(_stream.frame.get())) { + return false; + } mixerInit(); callReady(); return true; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp index 39fc2e1f5..f0911f892 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_video_track.cpp @@ -98,6 +98,9 @@ private: bool _queued = false; base::ConcurrentTimer _readFramesTimer; + // For initial frame skipping for an exact seek. + FramePointer _initialSkippingFrame; + }; VideoTrackObject::VideoTrackObject( @@ -349,25 +352,33 @@ bool VideoTrackObject::tryReadFirstFrame(Packet &&packet) { if (ProcessPacket(_stream, std::move(packet)).failed()) { return false; } - auto frame = QImage(); - if (const auto error = ReadNextFrame(_stream)) { - if (error.code() == AVERROR_EOF) { - // Return the last valid frame if we seek too far. - return processFirstFrame(); - } else if (error.code() != AVERROR(EAGAIN) || _noMoreData) { + while (true) { + if (const auto error = ReadNextFrame(_stream)) { + if (error.code() == AVERROR_EOF) { + if (!_initialSkippingFrame) { + return false; + } + // Return the last valid frame if we seek too far. + _stream.frame = std::move(_initialSkippingFrame); + return processFirstFrame(); + } else if (error.code() != AVERROR(EAGAIN) || _noMoreData) { + return false; + } else { + // Waiting for more packets. + return true; + } + } else if (!fillStateFromFrame()) { return false; - } else { - // Waiting for more packets. - return true; + } else if (_syncTimePoint.trackTime >= _options.position) { + return processFirstFrame(); } - } else if (!fillStateFromFrame()) { - return false; - } else if (_syncTimePoint.trackTime < _options.position) { + // Seek was with AVSEEK_FLAG_BACKWARD so first we get old frames. // Try skipping frames until one is after the requested position. - return true; - } else { - return processFirstFrame(); + std::swap(_initialSkippingFrame, _stream.frame); + if (!_stream.frame) { + _stream.frame = MakeFramePointer(); + } } } @@ -382,9 +393,7 @@ bool VideoTrackObject::processFirstFrame() { } _shared->init(std::move(frame), _syncTimePoint.trackTime); callReady(); - if (!_stream.queue.empty()) { - queueReadFrames(); - } + queueReadFrames(); return true; }