Bug 654787 - part7: Stop playing and decoding when looping is cancelled; r=jwwang draft
authorChun-Min Chang <chun.m.chang@gmail.com>
Tue, 21 Nov 2017 18:15:08 +0800
changeset 702947 09e395f88f355d64b4ece8f980540bec03fb80f6
parent 702946 c077338eb810dad0bcbe27db2b6663bd0b05fac2
child 702948 563a4b2af481f132638e4417e91db270975e0fb3
push id90643
push userbmo:cchang@mozilla.com
push dateFri, 24 Nov 2017 02:29:17 +0000
reviewersjwwang
bugs654787
milestone59.0a1
Bug 654787 - part7: Stop playing and decoding when looping is cancelled; r=jwwang MozReview-Commit-ID: BQKVsmDSqpJ
dom/media/MediaDecoderStateMachine.cpp
--- 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.