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
--- 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();