diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 2c7e8fcd65f..2e83da16211 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -2658,28 +2658,41 @@ nsresult MediaDecoderStateMachine::RunStateMachine() TimeStamp now = TimeStamp::Now(); NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time."); - // We will remain in the buffering state if we've not decoded enough - // data to begin playback, or if we've not downloaded a reasonable - // amount of data inside our buffering time. - TimeDuration elapsed = now - mBufferingStart; - bool isLiveStream = resource->GetLength() == -1; - if ((isLiveStream || !mDecoder->CanPlayThrough()) && - elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) && - (mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS) - : HasLowUndecodedData(mBufferingWait * USECS_PER_S)) && - mDecoder->IsExpectingMoreData()) - { - DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s", - mBufferingWait, mBufferingWait - elapsed.ToSeconds(), - (mQuickBuffering ? "(quick exit)" : "")); + // When we enter buffering mode from playback, we push our most recent + // video frame back into the queue. So depending on how we started + // buffering, we may have one dummy frame in the queue. :-( + bool outOfAudio = IsAudioDecoding() && !AudioQueue().IsFinished() && AudioQueue().GetSize() == 0; + bool outOfVideo = IsVideoDecoding() && !VideoQueue().IsFinished() && VideoQueue().GetSize() <= 1; + + // With buffering heuristics we will remain in the buffering state if + // we've not decoded enough data to begin playback, or if we've not + // downloaded a reasonable amount of data inside our buffering time. + if (mReader->UseBufferingHeuristics()) { + TimeDuration elapsed = now - mBufferingStart; + bool isLiveStream = resource->GetLength() == -1; + if ((isLiveStream || !mDecoder->CanPlayThrough()) && + elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) && + (mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS) + : HasLowUndecodedData(mBufferingWait * USECS_PER_S)) && + mDecoder->IsExpectingMoreData()) + { + DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s", + mBufferingWait, mBufferingWait - elapsed.ToSeconds(), + (mQuickBuffering ? "(quick exit)" : "")); + ScheduleStateMachine(USECS_PER_S); + return NS_OK; + } + } else if (outOfAudio || outOfVideo) { + DECODER_LOG("Out of decoded data - polling for 1s"); + DispatchDecodeTasksIfNeeded(); ScheduleStateMachine(USECS_PER_S); return NS_OK; - } else { - DECODER_LOG("Changed state from BUFFERING to DECODING"); - DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds()); - StartDecoding(); } + DECODER_LOG("Changed state from BUFFERING to DECODING"); + DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds()); + StartDecoding(); + // Notify to allow blocked decoder thread to continue mDecoder->GetReentrantMonitor().NotifyAll(); UpdateReadyState(); @@ -2938,7 +2951,7 @@ void MediaDecoderStateMachine::AdvanceFrame() mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING && HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) && mDecoder->IsExpectingMoreData()) { - if (JustExitedQuickBuffering() || HasLowUndecodedData()) { + if (!mReader->UseBufferingHeuristics() || JustExitedQuickBuffering() || HasLowUndecodedData()) { if (currentFrame) { VideoQueue().PushFront(currentFrame); }