Bug 1306186. Part 5 - add MaybeStopPrerolling() to check if we can stop prerolling.
MozReview-Commit-ID: 15Y5e4DUr4S
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1044,20 +1044,17 @@ MediaDecoderStateMachine::OnAudioDecoded
case DECODER_STATE_DECODING_FIRSTFRAME: {
Push(audio, MediaData::AUDIO_DATA);
MaybeFinishDecodeFirstFrame();
return;
}
case DECODER_STATE_DECODING: {
Push(audio, MediaData::AUDIO_DATA);
- if (mIsPrerolling) {
- // Schedule next cycle to check if we can stop prerolling.
- ScheduleStateMachine();
- }
+ MaybeStopPrerolling();
return;
}
default: {
// Ignore other cases.
return;
}
}
@@ -1123,22 +1120,17 @@ MediaDecoderStateMachine::OnNotDecoded(M
}
// If the decoder is waiting for data, we tell it to call us back when the
// data arrives.
if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
mReader->WaitForData(aType);
-
- if (mIsPrerolling) {
- // Schedule next cycle to stop prerolling so we can play the frames we've
- // decoded so far.
- ScheduleStateMachine();
- }
+ MaybeStopPrerolling();
return;
}
if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
if (isAudio) {
EnsureAudioDecodeTaskQueued();
} else {
EnsureVideoDecodeTaskQueued();
@@ -1155,21 +1147,17 @@ MediaDecoderStateMachine::OnNotDecoded(M
// This is an EOS. Finish off the queue, and then handle things based on our
// state.
if (isAudio) {
AudioQueue().Finish();
} else {
VideoQueue().Finish();
}
- if (mIsPrerolling) {
- // No more data to decode. Schedule next cycle to stop prerolling
- // and start playback.
- ScheduleStateMachine();
- }
+ MaybeStopPrerolling();
switch (mState) {
case DECODER_STATE_DECODING_FIRSTFRAME:
MaybeFinishDecodeFirstFrame();
return;
case DECODER_STATE_BUFFERING:
case DECODER_STATE_DECODING: {
if (CheckIfDecodeComplete()) {
@@ -1235,20 +1223,17 @@ MediaDecoderStateMachine::OnVideoDecoded
case DECODER_STATE_DECODING_FIRSTFRAME: {
Push(video, MediaData::VIDEO_DATA);
MaybeFinishDecodeFirstFrame();
return;
}
case DECODER_STATE_DECODING: {
Push(video, MediaData::VIDEO_DATA);
- if (mIsPrerolling) {
- // Schedule next cycle to check if we can stop prerolling.
- ScheduleStateMachine();
- }
+ MaybeStopPrerolling();
// For non async readers, if the requested video sample was slow to
// arrive, increase the amount of audio we buffer to ensure that we
// 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;
@@ -1400,35 +1385,42 @@ void MediaDecoderStateMachine::StopPlayb
if (IsPlaying()) {
mMediaSink->SetPlaying(false);
MOZ_ASSERT(!IsPlaying());
}
DispatchDecodeTasksIfNeeded();
}
+void
+MediaDecoderStateMachine::MaybeStopPrerolling()
+{
+ MOZ_ASSERT(OnTaskQueue());
+ if (mIsPrerolling &&
+ (DonePrerollingAudio() || mReader->IsWaitingAudioData()) &&
+ (DonePrerollingVideo() || mReader->IsWaitingVideoData())) {
+ mIsPrerolling = false;
+ // Check if we can start playback.
+ ScheduleStateMachine();
+ }
+}
+
void MediaDecoderStateMachine::MaybeStartPlayback()
{
MOZ_ASSERT(OnTaskQueue());
// Should try to start playback only after decoding first frames.
MOZ_ASSERT(mSentFirstFrameLoadedEvent);
MOZ_ASSERT(mState == DECODER_STATE_DECODING ||
mState == DECODER_STATE_COMPLETED);
if (IsPlaying()) {
// Logging this case is really spammy - don't do it.
return;
}
- if (mIsPrerolling &&
- (DonePrerollingAudio() || mReader->IsWaitingAudioData()) &&
- (DonePrerollingVideo() || mReader->IsWaitingVideoData())) {
- mIsPrerolling = false;
- }
-
bool playStatePermits = mPlayState == MediaDecoder::PLAY_STATE_PLAYING;
if (!playStatePermits || mIsPrerolling || mAudioOffloading) {
DECODER_LOG("Not starting playback [playStatePermits: %d, "
"mIsPrerolling: %d, mAudioOffloading: %d]",
playStatePermits, mIsPrerolling, mAudioOffloading);
return;
}
@@ -2927,20 +2919,17 @@ MediaDecoderStateMachine::SetAudioCaptur
ScheduleStateMachine();
// Don't buffer as much when audio is captured because we don't need to worry
// about high latency audio devices.
mAmpleAudioThresholdUsecs = mAudioCaptured ?
detail::AMPLE_AUDIO_USECS / 2 :
detail::AMPLE_AUDIO_USECS;
- if (mIsPrerolling) {
- // Schedule next cycle to check if we can stop prerolling.
- ScheduleStateMachine();
- }
+ MaybeStopPrerolling();
}
uint32_t MediaDecoderStateMachine::GetAmpleVideoFrames() const
{
MOZ_ASSERT(OnTaskQueue());
return (mReader->IsAsync() && mReader->VideoIsHardwareAccelerated())
? std::max<uint32_t>(sVideoQueueHWAccelSize, MIN_VIDEO_QUEUE_SIZE)
: std::max<uint32_t>(sVideoQueueDefaultSize, MIN_VIDEO_QUEUE_SIZE);
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -725,16 +725,18 @@ private:
{
MOZ_ASSERT(OnTaskQueue());
return !mIsVisible ||
!IsVideoDecoding() ||
static_cast<uint32_t>(VideoQueue().GetSize()) >=
VideoPrerollFrames() * mPlaybackRate + 1;
}
+ void MaybeStopPrerolling();
+
// When we start decoding (either for the first time, or after a pause)
// we may be low on decoded data. We don't want our "low data" logic to
// kick in and decide that we're low on decoded data because the download
// can't keep up with the decode, and cause us to pause playback. So we
// have a "preroll" stage, where we ignore the results of our "low data"
// logic during the first few frames of our decode. This occurs during
// playback.
bool mIsPrerolling = false;