Bug 973408 - Set MediaDecoderReaders idle when they're not decoding. r=kinetik

This commit is contained in:
Chris Pearce
2014-03-11 11:44:10 +08:00
parent 1e8a8b1865
commit 20e7f810e4
12 changed files with 145 additions and 102 deletions

View File

@@ -175,6 +175,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mAmpleAudioThresholdUsecs(AMPLE_AUDIO_USECS),
mDispatchedAudioDecodeTask(false),
mDispatchedVideoDecodeTask(false),
mIsReaderIdle(false),
mAudioCaptured(false),
mTransportSeekable(true),
mMediaSeekable(true),
@@ -559,6 +560,7 @@ MediaDecoderStateMachine::DecodeVideo()
mDispatchedVideoDecodeTask = false;
return;
}
EnsureActive();
// We don't want to consider skipping to the next keyframe if we've
// only just started up the decode loop, so wait until we've decoded
@@ -628,6 +630,8 @@ MediaDecoderStateMachine::DecodeVideo()
mDispatchedVideoDecodeTask = false;
if (NeedToDecodeVideo()) {
EnsureVideoDecodeTaskQueued();
} else {
UpdateIdleState();
}
}
@@ -651,6 +655,7 @@ MediaDecoderStateMachine::DecodeAudio()
mDispatchedAudioDecodeTask = false;
return;
}
EnsureActive();
// We don't want to consider skipping to the next keyframe if we've
// only just started up the decode loop, so wait until we've decoded
@@ -683,6 +688,8 @@ MediaDecoderStateMachine::DecodeAudio()
mDispatchedAudioDecodeTask = false;
if (NeedToDecodeAudio()) {
EnsureAudioDecodeTaskQueued();
} else {
UpdateIdleState();
}
}
@@ -702,6 +709,7 @@ MediaDecoderStateMachine::CheckIfDecodeComplete()
// We've finished decoding all active streams,
// so move to COMPLETED state.
mState = DECODER_STATE_COMPLETED;
UpdateIdleState();
ScheduleStateMachine();
}
DECODER_LOG(PR_LOG_DEBUG,
@@ -1053,6 +1061,8 @@ void MediaDecoderStateMachine::StopPlayback()
mDecoder->GetReentrantMonitor().NotifyAll();
NS_ASSERTION(!IsPlaying(), "Should report not playing at end of StopPlayback()");
mDecoder->UpdateStreamBlockingForStateMachinePlaying();
UpdateIdleState();
}
void MediaDecoderStateMachine::SetSyncPointForMediaStream()
@@ -1317,6 +1327,11 @@ void MediaDecoderStateMachine::StartDecoding()
mIsVideoDecoding = HasVideo() && !mReader->VideoQueue().IsFinished();
mIsAudioDecoding = HasAudio() && !mReader->AudioQueue().IsFinished();
CheckIfDecodeComplete();
if (mState == DECODER_STATE_COMPLETED) {
return;
}
// Reset other state to pristine values before starting decode.
mSkipToNextKeyFrame = false;
mIsAudioPrerolling = true;
@@ -1482,6 +1497,64 @@ MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
return NS_OK;
}
void
MediaDecoderStateMachine::EnsureActive()
{
AssertCurrentThreadInMonitor();
MOZ_ASSERT(OnDecodeThread());
if (!mIsReaderIdle) {
return;
}
mIsReaderIdle = false;
SetReaderActive();
}
void
MediaDecoderStateMachine::SetReaderIdle()
{
DECODER_LOG(PR_LOG_DEBUG, ("%p SetReaderIdle()", mDecoder.get()));
MOZ_ASSERT(OnDecodeThread());
mReader->SetIdle();
}
void
MediaDecoderStateMachine::SetReaderActive()
{
DECODER_LOG(PR_LOG_DEBUG, ("%p SetReaderActive()", mDecoder.get()));
MOZ_ASSERT(OnDecodeThread());
mReader->SetActive();
}
void
MediaDecoderStateMachine::UpdateIdleState()
{
AssertCurrentThreadInMonitor();
// If we're in completed state, we should not need to decode anything else.
MOZ_ASSERT(mState != DECODER_STATE_COMPLETED ||
(!NeedToDecodeAudio() && !NeedToDecodeVideo()));
bool needIdle = mDecoder->GetState() == MediaDecoder::PLAY_STATE_PAUSED &&
!NeedToDecodeAudio() &&
!NeedToDecodeVideo() &&
!IsPlaying();
if (mIsReaderIdle == needIdle) {
return;
}
mIsReaderIdle = needIdle;
nsRefPtr<nsIRunnable> event;
if (mIsReaderIdle) {
event = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SetReaderIdle);
} else {
event = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::SetReaderActive);
}
if (NS_FAILED(mDecodeTaskQueue->Dispatch(event)) &&
mState != DECODER_STATE_SHUTDOWN) {
NS_WARNING("Failed to dispatch event to set decoder idle state");
}
}
nsresult
MediaDecoderStateMachine::EnqueueDecodeSeekTask()
{
@@ -1698,6 +1771,7 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
if (mState != DECODER_STATE_DECODING_METADATA) {
return NS_ERROR_FAILURE;
}
EnsureActive();
nsresult res;
MediaInfo info;
@@ -1803,6 +1877,7 @@ void MediaDecoderStateMachine::DecodeSeek()
if (mState != DECODER_STATE_SEEKING) {
return;
}
EnsureActive();
// During the seek, don't have a lock on the decoder state,
// otherwise long seek operations can block the main thread.
@@ -1905,7 +1980,12 @@ void MediaDecoderStateMachine::DecodeSeek()
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED",
mDecoder.get(), seekTime));
stopEvent = NS_NewRunnableMethod(mDecoder, &MediaDecoder::SeekingStoppedAtEnd);
// Explicitly set our state so we don't decode further, and so
// we report playback ended to the media element.
mState = DECODER_STATE_COMPLETED;
mIsAudioDecoding = false;
mIsVideoDecoding = false;
UpdateIdleState();
} else {
DECODER_LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to DECODING",
mDecoder.get(), seekTime));
@@ -2508,11 +2588,11 @@ void MediaDecoderStateMachine::StartBuffering()
mDecoder.get(), decodeDuration.ToSeconds()));
#ifdef PR_LOGGING
MediaDecoder::Statistics stats = mDecoder->GetStatistics();
#endif
DECODER_LOG(PR_LOG_DEBUG, ("%p Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
mDecoder.get(),
stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)",
stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)"));
#endif
}
nsresult MediaDecoderStateMachine::GetBuffered(dom::TimeRanges* aBuffered) {