Bug 1302045. Check if we have [GetMediaTime(), GetMediaTime() + aUsecs] in the buffer ranges to decide whether we are in low buffered data. draft
authorJW Wang <jwwang@mozilla.com>
Mon, 12 Sep 2016 16:20:11 +0800
changeset 415328 702dbbbfcd193e7c88e5912af81e1653dbb05dd5
parent 415273 d5e34b7cb30221c3e93e089b8db7f28cd7845987
child 415329 e660acc2b4b19c41f52ca7f40e508a995354135e
push id29847
push userjwwang@mozilla.com
push dateTue, 20 Sep 2016 06:12:15 +0000
bugs1302045
milestone51.0a1
Bug 1302045. Check if we have [GetMediaTime(), GetMediaTime() + aUsecs] in the buffer ranges to decide whether we are in low buffered data. Note we consider [endOfDecodedData, GetMediaTime()] is always in the buffer ranges. MozReview-Commit-ID: F6ez3KYMjht
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -911,21 +911,21 @@ MediaDecoderStateMachine::NeedToSkipToNe
   // task queue it should never run low and skipping won't help their decode.
   bool isLowOnDecodedAudio = !mReader->IsAsync() &&
                              !mIsAudioPrerolling && IsAudioDecoding() &&
                              (GetDecodedAudioDuration() <
                               mLowAudioThresholdUsecs * mPlaybackRate);
   bool isLowOnDecodedVideo = !mIsVideoPrerolling &&
                              ((GetClock() - mDecodedVideoEndTime) * mPlaybackRate >
                               LOW_VIDEO_THRESHOLD_USECS);
-  bool lowUndecoded = HasLowUndecodedData();
-
-  if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowUndecoded) {
+  bool lowBuffered = HasLowBufferedData();
+
+  if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowBuffered) {
     DECODER_LOG("Skipping video decode to the next keyframe lowAudio=%d lowVideo=%d lowUndecoded=%d async=%d",
-                isLowOnDecodedAudio, isLowOnDecodedVideo, lowUndecoded, mReader->IsAsync());
+                isLowOnDecodedAudio, isLowOnDecodedVideo, lowBuffered, mReader->IsAsync());
     return true;
   }
 
   return false;
 }
 
 bool
 MediaDecoderStateMachine::NeedToDecodeAudio()
@@ -1168,17 +1168,17 @@ MediaDecoderStateMachine::OnVideoDecoded
       // don't run out of audio. This is unnecessary for async readers,
       // since they decode audio and video on different threads so they
       // are unlikely to run out of decoded audio.
       if (mReader->IsAsync()) {
         return;
       }
       TimeDuration decodeTime = TimeStamp::Now() - aDecodeStartTime;
       if (THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
-          !HasLowUndecodedData())
+          !HasLowBufferedData())
       {
         mLowAudioThresholdUsecs =
           std::min(THRESHOLD_FACTOR * DurationToUsecs(decodeTime), mAmpleAudioThresholdUsecs);
         mAmpleAudioThresholdUsecs = std::max(THRESHOLD_FACTOR * mLowAudioThresholdUsecs,
                                               mAmpleAudioThresholdUsecs);
         DECODER_LOG("Slow video decode, set mLowAudioThresholdUsecs=%lld mAmpleAudioThresholdUsecs=%lld",
                     mLowAudioThresholdUsecs, mAmpleAudioThresholdUsecs);
       }
@@ -1381,17 +1381,17 @@ MediaDecoderStateMachine::MaybeStartBuff
   // No more data to download. No need to enter buffering.
   if (!mResource->IsExpectingMoreData()) {
     return;
   }
 
   bool shouldBuffer;
   if (mReader->UseBufferingHeuristics()) {
     shouldBuffer = HasLowDecodedData(EXHAUSTED_DATA_MARGIN_USECS) &&
-                   (JustExitedQuickBuffering() || HasLowUndecodedData());
+                   (JustExitedQuickBuffering() || HasLowBufferedData());
   } else {
     MOZ_ASSERT(mReader->IsWaitForDataSupported());
     shouldBuffer = (OutOfDecodedAudio() && mReader->IsWaitingAudioData()) ||
                    (OutOfDecodedVideo() && mReader->IsWaitingVideoData());
   }
   if (shouldBuffer) {
     SetState(DECODER_STATE_BUFFERING);
   }
@@ -2260,23 +2260,23 @@ bool MediaDecoderStateMachine::HasLowDec
 bool MediaDecoderStateMachine::OutOfDecodedAudio()
 {
     MOZ_ASSERT(OnTaskQueue());
     return IsAudioDecoding() && !AudioQueue().IsFinished() &&
            AudioQueue().GetSize() == 0 &&
            !mMediaSink->HasUnplayedFrames(TrackInfo::kAudioTrack);
 }
 
-bool MediaDecoderStateMachine::HasLowUndecodedData()
+bool MediaDecoderStateMachine::HasLowBufferedData()
 {
   MOZ_ASSERT(OnTaskQueue());
-  return HasLowUndecodedData(mLowDataThresholdUsecs);
+  return HasLowBufferedData(mLowDataThresholdUsecs);
 }
 
-bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
+bool MediaDecoderStateMachine::HasLowBufferedData(int64_t aUsecs)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(mState >= DECODER_STATE_DECODING,
              "Must have loaded first frame for mBuffered to be valid");
 
   // If we don't have a duration, mBuffered is probably not going to have
   // a useful buffered range. Return false here so that we don't get stuck in
   // buffering mode for live streams.
@@ -2299,19 +2299,27 @@ bool MediaDecoderStateMachine::HasLowUnd
       ? mDecodedAudioEndTime
       : INT64_MAX;
 
   int64_t endOfDecodedData = std::min(endOfDecodedVideoData, endOfDecodedAudioData);
   if (Duration().ToMicroseconds() < endOfDecodedData) {
     // Our duration is not up to date. No point buffering.
     return false;
   }
-  media::TimeInterval interval(media::TimeUnit::FromMicroseconds(endOfDecodedData),
-                               media::TimeUnit::FromMicroseconds(std::min(endOfDecodedData + aUsecs, Duration().ToMicroseconds())));
-  return endOfDecodedData != INT64_MAX && !mBuffered.Ref().Contains(interval);
+
+  if (endOfDecodedData == INT64_MAX) {
+    // Have decoded all samples. No point buffering.
+    return false;
+  }
+
+  int64_t start = endOfDecodedData;
+  int64_t end = std::min(GetMediaTime() + aUsecs, Duration().ToMicroseconds());
+  media::TimeInterval interval(media::TimeUnit::FromMicroseconds(start),
+                               media::TimeUnit::FromMicroseconds(end));
+  return !mBuffered.Ref().Contains(interval);
 }
 
 void
 MediaDecoderStateMachine::DecodeError(const MediaResult& aError)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(!IsShutdown());
   DECODER_WARN("Decode error");
@@ -2538,17 +2546,17 @@ MediaDecoderStateMachine::StepBuffering(
   // 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 = mResource->IsLiveStream();
     if ((isLiveStream || !CanPlayThrough()) &&
         elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
         (mQuickBuffering ? HasLowDecodedData(mQuickBufferingLowDataThresholdUsecs)
-                         : HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
+                         : HasLowBufferedData(mBufferingWait * USECS_PER_S)) &&
         mResource->IsExpectingMoreData()) {
       DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
                   mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
                   (mQuickBuffering ? "(quick exit)" : ""));
       ScheduleStateMachineIn(USECS_PER_S);
       return;
     }
   } else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -396,22 +396,21 @@ protected:
 
   bool OutOfDecodedVideo()
   {
     MOZ_ASSERT(OnTaskQueue());
     return IsVideoDecoding() && VideoQueue().GetSize() <= 1;
   }
 
 
-  // Returns true if we're running low on data which is not yet decoded.
-  // The decoder monitor must be held.
-  bool HasLowUndecodedData();
+  // Returns true if we're running low on buffered data.
+  bool HasLowBufferedData();
 
-  // Returns true if we have less than aUsecs of undecoded data available.
-  bool HasLowUndecodedData(int64_t aUsecs);
+  // Returns true if we have less than aUsecs of buffered data available.
+  bool HasLowBufferedData(int64_t aUsecs);
 
   // Returns true when there's decoded audio waiting to play.
   // The decoder monitor must be held.
   bool HasFutureAudio();
 
   // Returns true if we recently exited "quick buffering" mode.
   bool JustExitedQuickBuffering();