From c2eb7b293be1b1e2c6b2aac72dde5ae8cd9ae57c Mon Sep 17 00:00:00 2001 From: Eric Desjardins Date: Sat, 28 Sep 2019 13:01:18 -0400 Subject: [PATCH] Fix seek bugs that was blocking the player. --- mediadecoder.cpp | 14 ++++++++++ player.cpp | 69 ++++++++++++++++++++++++++++++++++++++++-------- subtitle.cpp | 2 -- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/mediadecoder.cpp b/mediadecoder.cpp index 999c34dc..f0db33ea 100644 --- a/mediadecoder.cpp +++ b/mediadecoder.cpp @@ -443,6 +443,7 @@ namespace { } videoFrame->timeUs = timeUs; + logger::Trace("Decode frame %f", chrono::Seconds(timeUs)); // Convert the video frame to output format using sws_scale if(videoStream->swsContext) @@ -549,6 +550,7 @@ namespace { void Seek(mediadecoder::Producer* producer ) { + logger::Info("Seek %f", chrono::Seconds(producer->seekTime)); for( auto it = producer->streams.begin(); it != producer->streams.end(); ++it) { mediadecoder::Stream* stream = *it; @@ -1343,6 +1345,11 @@ namespace mediadecoder void Release(Producer* producer, VideoFrame* frame) { + if(!frame) + { + return; + } + const bool outcome = producer->videoFramePool->push(frame); @@ -1354,6 +1361,11 @@ namespace mediadecoder void Release(Producer* producer, AudioFrame* frame) { + if(!frame) + { + return; + } + const bool outcome = producer->audioFramePool->push(frame); if(!outcome) @@ -1427,6 +1439,8 @@ namespace mediadecoder std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_PLAYBACK_SLEEP_TIME_MS)); haveVideo = producer->videoQueueSize > nbBufferForPlayback; } + + logger::Info("Playback ready %d buffers", producer->videoQueueSize.load()); } } diff --git a/player.cpp b/player.cpp index 712fc0ec..f3b08913 100644 --- a/player.cpp +++ b/player.cpp @@ -11,6 +11,13 @@ namespace { const int64_t queueFullSleepTimeMs = 100; const int64_t pauseSleepTimeMs = 500; const int64_t doneSleepTimeMs = 2000; + + const int64_t sleepThresholdUs = 10000; + const int64_t sleepThresholdLogUs = 1000000; + const int64_t millisecondUs = 1000; + const int64_t logDeltaThresholdUs = 1000; + + const double seekFrameSkipThresholdSec = 30.0; player::SwapBufferCallback swapBufferCallback; } @@ -18,10 +25,6 @@ namespace { namespace { bool WaitForPlayback(const char* name, uint64_t startTimeUs, uint64_t timeUs, int64_t waitThresholdUs) { - const int64_t sleepThresholdUs = 10000; - const int64_t millisecondUs = 1000; - const int64_t logDeltaThresholdUs = 100; - int64_t waitTime = chrono::Wait(startTimeUs, timeUs); if( waitTime <= 0 ) @@ -33,6 +36,11 @@ namespace { { if( waitTime >= sleepThresholdUs ) { + if(waitTime >= sleepThresholdLogUs) + { + logger::Warn("WaitForPlayback. %s Got frame to soon %f seconds. Sleeping.", name, chrono::Seconds(waitTime)); + } + std::this_thread::sleep_for(std::chrono::microseconds(waitTime-millisecondUs)); waitTime = chrono::Wait(startTimeUs, timeUs); @@ -436,6 +444,42 @@ namespace player assert(!player->buffering); scopeguard::SetValue bufferingGuard(player->buffering, true, false); + mediadecoder::Release(player->producer, player->videoFrame); + mediadecoder::WaitForPlayback(player->producer); + + int64_t sleepTime = 0; + + // skip old frames from decoder + do + { + if(!player->videoFrame) + { + mediadecoder::Consume(player->producer, player->videoFrame); + } + + if(!player->videoFrame) + { + break; + } + + int64_t deltaUs = player->videoFrame->timeUs - timeUs; + double deltaSec = chrono::Seconds(deltaUs); + if(deltaSec < seekFrameSkipThresholdSec && deltaSec > 0.0) + { + logger::Warn("Seek sleeping for %f", chrono::Seconds(deltaUs)); + sleepTime = deltaUs; + break; + } + + logger::Warn("Player: Seek skipping frame %f frame %ld time %ld", chrono::Seconds(deltaUs), player->videoFrame->timeUs, timeUs); + + mediadecoder::Release(player->producer, player->videoFrame); + player->videoFrame = nullptr; + + + } while(true); + + Result result = StartAudioPlayback(player); if(!result) { @@ -445,6 +489,12 @@ namespace player // reset playback start time player->playbackStartTimeUs = static_cast(chrono::Now()) - static_cast(timeUs); + + // we got video frame in the future, sleep until we can play them + if(sleepTime != 0) + { + std::this_thread::sleep_for(std::chrono::microseconds(sleepTime)); + } logger::Info("Seek end"); } @@ -513,7 +563,7 @@ namespace player const bool drawFrame = WaitForPlayback("video", player->playbackStartTimeUs, player->videoFrame->timeUs, waitThresholdUs); - if( drawFrame ) + if( drawFrame && player->videoFrame ) { profiler::ScopeProfiler profiler(profiler::PROFILER_VIDEO_DRAW); @@ -539,19 +589,16 @@ namespace player mediadecoder::Release(player->producer, player->videoFrame); player->videoFrame = nullptr; } - else + else if(player->videoFrame) { - logger::Warn( "Player: No draw frame" ); + mediadecoder::Release(player->producer, player->videoFrame); + player->videoFrame = nullptr; } } else if(player->producer->done) { std::this_thread::sleep_for(std::chrono::milliseconds(doneSleepTimeMs)); } - else - { - logger::Warn( "Player: No video frame" ); - } } void Close(Player* player) diff --git a/subtitle.cpp b/subtitle.cpp index 95ebf979..549be667 100644 --- a/subtitle.cpp +++ b/subtitle.cpp @@ -223,7 +223,6 @@ namespace { field = true; } - } else { @@ -462,7 +461,6 @@ namespace return Result(false, "ParseSubRipTime invalid format %s", t.c_str()); } - return result; }