Bug 1300479. Part 3 - extract RunStateMachine() cases to its own function. r=kaku

MozReview-Commit-ID: LNLu7X8VD3s

--HG--
extra : rebase_source : 05c6ff7546d334e32bb3f57c17298f323f5a7111
This commit is contained in:
JW Wang 2016-09-05 15:48:37 +08:00
Родитель 69c466b569
Коммит d2fd8a9859
2 изменённых файлов: 124 добавлений и 105 удалений

Просмотреть файл

@ -2275,120 +2275,133 @@ MediaDecoderStateMachine::RunStateMachine()
mDelayedScheduler.Reset(); // Must happen on state machine task queue.
mDispatchedStateMachine = false;
MediaResource* resource = mResource;
NS_ENSURE_TRUE_VOID(resource);
switch (mState) {
case DECODER_STATE_DECODING: {
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying())
{
// We're playing, but the element/decoder is in paused state. Stop
// playing!
StopPlayback();
}
// Start playback if necessary so that the clock can be properly queried.
MaybeStartPlayback();
UpdatePlaybackPositionPeriodically();
NS_ASSERTION(!IsPlaying() ||
IsStateMachineScheduled(),
"Must have timer scheduled");
MaybeStartBuffering();
case DECODER_STATE_DECODING:
StepDecoding();
return;
}
case DECODER_STATE_BUFFERING: {
TimeStamp now = TimeStamp::Now();
NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time.");
// 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->IsLiveStream();
if ((isLiveStream || !CanPlayThrough()) &&
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
(mQuickBuffering ? HasLowDecodedData(mQuickBufferingLowDataThresholdUsecs)
: HasLowUndecodedData(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()) {
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Don't yet have a strategy for non-heuristic + non-WaitForData");
DispatchDecodeTasksIfNeeded();
MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mReader->IsWaitingAudioData());
MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVideoData() || mReader->IsWaitingVideoData());
DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
"mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
OutOfDecodedAudio(), AudioRequestStatus(),
OutOfDecodedVideo(), VideoRequestStatus());
return;
}
DECODER_LOG("Changed state from BUFFERING to DECODING");
DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
SetState(DECODER_STATE_DECODING);
NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
case DECODER_STATE_BUFFERING:
StepBuffering();
return;
}
case DECODER_STATE_COMPLETED: {
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
StopPlayback();
}
// Play the remaining media. We want to run AdvanceFrame() at least
// once to ensure the current playback position is advanced to the
// end of the media, and so that we update the readyState.
if ((HasVideo() && !mVideoCompleted) ||
(HasAudio() && !mAudioCompleted)) {
// Start playback if necessary to play the remaining media.
MaybeStartPlayback();
UpdatePlaybackPositionPeriodically();
NS_ASSERTION(!IsPlaying() ||
IsStateMachineScheduled(),
"Must have timer scheduled");
return;
}
// StopPlayback in order to reset the IsPlaying() state so audio
// is restarted correctly.
StopPlayback();
if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
!mSentPlaybackEndedEvent)
{
int64_t clockTime = std::max(AudioEndTime(), VideoEndTime());
clockTime = std::max(int64_t(0), std::max(clockTime, Duration().ToMicroseconds()));
UpdatePlaybackPosition(clockTime);
// Ensure readyState is updated before firing the 'ended' event.
UpdateNextFrameStatus();
mOnPlaybackEvent.Notify(MediaEventType::PlaybackEnded);
mSentPlaybackEndedEvent = true;
// MediaSink::GetEndTime() must be called before stopping playback.
StopMediaSink();
}
case DECODER_STATE_COMPLETED:
StepCompleted();
return;
}
default:
return;
}
}
void
MediaDecoderStateMachine::StepDecoding()
{
MOZ_ASSERT(OnTaskQueue());
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
// We're playing, but the element/decoder is in paused state. Stop
// playing!
StopPlayback();
}
// Start playback if necessary so that the clock can be properly queried.
MaybeStartPlayback();
UpdatePlaybackPositionPeriodically();
NS_ASSERTION(!IsPlaying() ||
IsStateMachineScheduled(),
"Must have timer scheduled");
MaybeStartBuffering();
}
void
MediaDecoderStateMachine::StepBuffering()
{
MOZ_ASSERT(OnTaskQueue());
TimeStamp now = TimeStamp::Now();
NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time.");
// 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 = mResource->IsLiveStream();
if ((isLiveStream || !CanPlayThrough()) &&
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
(mQuickBuffering ? HasLowDecodedData(mQuickBufferingLowDataThresholdUsecs)
: HasLowUndecodedData(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()) {
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Don't yet have a strategy for non-heuristic + non-WaitForData");
DispatchDecodeTasksIfNeeded();
MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mReader->IsWaitingAudioData());
MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVideoData() || mReader->IsWaitingVideoData());
DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
"mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
OutOfDecodedAudio(), AudioRequestStatus(),
OutOfDecodedVideo(), VideoRequestStatus());
return;
}
DECODER_LOG("Changed state from BUFFERING to DECODING");
DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds());
SetState(DECODER_STATE_DECODING);
NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled");
}
void
MediaDecoderStateMachine::StepCompleted()
{
MOZ_ASSERT(OnTaskQueue());
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying()) {
StopPlayback();
}
// Play the remaining media. We want to run AdvanceFrame() at least
// once to ensure the current playback position is advanced to the
// end of the media, and so that we update the readyState.
if ((HasVideo() && !mVideoCompleted) ||
(HasAudio() && !mAudioCompleted)) {
// Start playback if necessary to play the remaining media.
MaybeStartPlayback();
UpdatePlaybackPositionPeriodically();
NS_ASSERTION(!IsPlaying() ||
IsStateMachineScheduled(),
"Must have timer scheduled");
return;
}
// StopPlayback in order to reset the IsPlaying() state so audio
// is restarted correctly.
StopPlayback();
if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
!mSentPlaybackEndedEvent) {
int64_t clockTime = std::max(AudioEndTime(), VideoEndTime());
clockTime = std::max(int64_t(0), std::max(clockTime, Duration().ToMicroseconds()));
UpdatePlaybackPosition(clockTime);
// Ensure readyState is updated before firing the 'ended' event.
UpdateNextFrameStatus();
mOnPlaybackEvent.Notify(MediaEventType::PlaybackEnded);
mSentPlaybackEndedEvent = true;
// MediaSink::GetEndTime() must be called before stopping playback.
StopMediaSink();
}
}
void
MediaDecoderStateMachine::Reset(TrackSet aTracks)
{

Просмотреть файл

@ -556,6 +556,12 @@ protected:
// Performs one "cycle" of the state machine.
void RunStateMachine();
// Perform one cycle of the DECODING state.
void StepDecoding();
// Perform one cycle of the BUFFERING state.
void StepBuffering();
// Perform one cycle of the COMPLETED state.
void StepCompleted();
bool IsStateMachineScheduled() const;