Bug 654787 - part7: Stop playing and decoding when looping is cancelled; r=jwwang
MozReview-Commit-ID: BQKVsmDSqpJ
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -603,37 +603,17 @@ public:
TimeDuration decodeDuration = TimeStamp::Now() - mDecodeStartTime;
SLOG("Exiting DECODING, decoded for %.3lfs", decodeDuration.ToSeconds());
}
mDormantTimer.Reset();
mOnAudioPopped.DisconnectIfExists();
mOnVideoPopped.DisconnectIfExists();
}
- void Step() override
- {
- if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING &&
- mMaster->IsPlaying()) {
- // We're playing, but the element/decoder is in paused state. Stop
- // playing!
- mMaster->StopPlayback();
- }
-
- // Start playback if necessary so that the clock can be properly queried.
- if (!mIsPrerolling) {
- mMaster->MaybeStartPlayback();
- }
-
- mMaster->UpdatePlaybackPositionPeriodically();
-
- MOZ_ASSERT(!mMaster->IsPlaying() || mMaster->IsStateMachineScheduled(),
- "Must have timer scheduled");
-
- MaybeStartBuffering();
- }
+ void Step() override;
State GetState() const override
{
return DECODER_STATE_DECODING;
}
void HandleAudioDecoded(AudioData* aAudio) override
{
@@ -2307,16 +2287,61 @@ DecodingState::Enter()
// Will enter dormant when playback is paused for a while.
if (mMaster->mPlayState == MediaDecoder::PLAY_STATE_PAUSED) {
StartDormantTimer();
}
}
void
MediaDecoderStateMachine::
+DecodingState::Step()
+{
+ if (mMaster->mPlayState != MediaDecoder::PLAY_STATE_PLAYING &&
+ mMaster->IsPlaying()) {
+ // We're playing, but the element/decoder is in paused state. Stop
+ // playing!
+ mMaster->StopPlayback();
+ }
+
+ // Start playback if necessary so that the clock can be properly queried.
+ if (!mIsPrerolling) {
+ mMaster->MaybeStartPlayback();
+ }
+
+ TimeUnit before = mMaster->GetMediaTime();
+ mMaster->UpdatePlaybackPositionPeriodically();
+
+ // After looping is cancelled, the time won't be corrected, and therefore we
+ // can check it to see if the end of the media track is reached.
+ TimeUnit adjusted = mMaster->GetClock();
+ Reader()->AdjustByLooping(adjusted);
+ // Make sure the media is started before comparing the time, or it's
+ // meaningless. Without checking IsStarted(), the media will be terminated
+ // immediately after seeking forward. When the state is just transited from
+ // seeking state, GetClock() is smaller than GetMediaTime(), since
+ // GetMediaTime() is updated upon seek is completed while GetClock() will be
+ // updated after the media is started again.
+ if (mMaster->mMediaSink->IsStarted() && !mMaster->mLooping &&
+ adjusted < before) {
+ mMaster->StopPlayback();
+ mMaster->mAudioDataRequest.DisconnectIfExists();
+ AudioQueue().Finish();
+ mMaster->mAudioCompleted = true;
+ SetState<CompletedState>();
+ return;
+ }
+
+ MOZ_ASSERT(!mMaster->IsPlaying() || mMaster->IsStateMachineScheduled(),
+ "Must have timer scheduled");
+
+ MaybeStartBuffering();
+}
+
+void
+MediaDecoderStateMachine::
DecodingState::HandleEndOfAudio()
{
AudioQueue().Finish();
if (!mMaster->IsVideoDecoding()) {
SetState<CompletedState>();
} else {
MaybeStopPrerolling();
}
@@ -3474,17 +3499,17 @@ MediaDecoderStateMachine::UpdatePlayback
// advance the clock to after the media end time.
if (VideoEndTime() > TimeUnit::Zero() || AudioEndTime() > TimeUnit::Zero()) {
auto clockTime = GetClock();
// Once looping was turned on, the time is probably larger than the duration
// of the media track, so the time over the end should be corrected.
mReader->AdjustByLooping(clockTime);
- bool loopback = clockTime < GetMediaTime();
+ bool loopback = clockTime < GetMediaTime() && mLooping;
// Skip frames up to the frame at the playback position, and figure out
// the time remaining until it's time to display the next frame and drop
// the current frame.
NS_ASSERTION(clockTime >= TimeUnit::Zero(), "Should have positive clock time.");
// These will be non -1 if we've displayed a video frame, or played an audio
// frame.