зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
69c466b569
Коммит
d2fd8a9859
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче