Bug 1054831 - Improve state transition about decoding metadata by removing |mDispatchedDecodeMetadataTask|. r=cpearce
authorJW Wang <jwwang@mozilla.com>
Wed, 20 Aug 2014 23:37:00 -0400
changeset 201665 ad84c1e95b9981e8af6d334fb00db448047c3c1f
parent 201664 c70db30dc93269693c957c1e2493c1d761937c2e
child 201666 2e86e0ecbd89d724d896aa9538f181cf1b17b05d
push id27375
push userryanvm@gmail.com
push dateTue, 26 Aug 2014 19:56:59 +0000
treeherdermozilla-central@f9bfe115fee5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1054831
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1054831 - Improve state transition about decoding metadata by removing |mDispatchedDecodeMetadataTask|. r=cpearce
content/media/MediaDecoderStateMachine.cpp
content/media/MediaDecoderStateMachine.h
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -175,17 +175,17 @@ static int64_t DurationToUsecs(TimeDurat
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
   mScheduler(new MediaDecoderStateMachineScheduler(
       aDecoder->GetReentrantMonitor(),
       &MediaDecoderStateMachine::TimeoutExpired,
       MOZ_THIS_IN_INITIALIZER_LIST(), aRealTime)),
-  mState(DECODER_STATE_DECODING_METADATA),
+  mState(DECODER_STATE_DECODING_NONE),
   mSyncPointInMediaStream(-1),
   mSyncPointInDecodedStream(-1),
   mPlayDuration(0),
   mStartTime(-1),
   mEndTime(-1),
   mFragmentEndTime(-1),
   mReader(aReader),
   mCurrentFrameTime(0),
@@ -204,17 +204,16 @@ MediaDecoderStateMachine::MediaDecoderSt
   mPositionChangeQueued(false),
   mAudioCompleted(false),
   mGotDurationFromMetaData(false),
   mDispatchedEventToDecode(false),
   mStopAudioThread(true),
   mQuickBuffering(false),
   mMinimizePreroll(false),
   mDecodeThreadWaiting(false),
-  mDispatchedDecodeMetadataTask(false),
   mDropAudioUntilNextDiscontinuity(false),
   mDropVideoUntilNextDiscontinuity(false),
   mDecodeToSeekTarget(false),
   mCurrentTimeBeforeSeek(0),
   mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@@ -353,32 +352,36 @@ static void WriteVideoToMediaStream(laye
 }
 
 static const TrackID TRACK_AUDIO = 1;
 static const TrackID TRACK_VIDEO = 2;
 static const TrackRate RATE_VIDEO = USECS_PER_S;
 
 void MediaDecoderStateMachine::SendStreamData()
 {
-  NS_ASSERTION(OnDecodeThread() ||
-               OnStateMachineThread(), "Should be on decode thread or state machine thread");
+  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
+               "Should be on decode thread or state machine thread");
   AssertCurrentThreadInMonitor();
+  MOZ_ASSERT(mState != DECODER_STATE_DECODING_NONE);
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
-  if (!stream)
+  if (!stream) {
     return;
-
-  if (mState == DECODER_STATE_DECODING_METADATA)
+  }
+
+  if (mState == DECODER_STATE_DECODING_METADATA) {
     return;
+  }
 
   // If there's still an audio sink alive, then we can't send any stream
   // data yet since both SendStreamData and the audio sink want to be in
   // charge of popping the audio queue. We're waiting for the audio sink
-  if (mAudioSink)
+  if (mAudioSink) {
     return;
+  }
 
   int64_t minLastAudioPacketTime = INT64_MAX;
   bool finished =
       (!mInfo.HasAudio() || AudioQueue().IsFinished()) &&
       (!mInfo.HasVideo() || VideoQueue().IsFinished());
   if (mDecoder->IsSameOriginMedia()) {
     SourceMediaStream* mediaStream = stream->mStream;
     StreamTime endPosition = 0;
@@ -1325,17 +1328,17 @@ void MediaDecoderStateMachine::SetDorman
   if (aDormant) {
     ScheduleStateMachine();
     mState = DECODER_STATE_DORMANT;
     mDecoder->GetReentrantMonitor().NotifyAll();
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
     ScheduleStateMachine();
     mStartTime = 0;
     mCurrentFrameTime = 0;
-    mState = DECODER_STATE_DECODING_METADATA;
+    mState = DECODER_STATE_DECODING_NONE;
     mDecoder->GetReentrantMonitor().NotifyAll();
   }
 }
 
 void MediaDecoderStateMachine::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
@@ -1394,18 +1397,18 @@ void MediaDecoderStateMachine::NotifyWai
   AssertCurrentThreadInMonitor();
   if (mState != DECODER_STATE_WAIT_FOR_RESOURCES ||
       mReader->IsWaitingMediaResources()) {
     return;
   }
   DECODER_LOG("NotifyWaitingForResourcesStatusChanged");
   // The reader is no longer waiting for resources (say a hardware decoder),
   // we can now proceed to decode metadata.
-  mState = DECODER_STATE_DECODING_METADATA;
-  EnqueueDecodeMetadataTask();
+  mState = DECODER_STATE_DECODING_NONE;
+  ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::Play()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   // When asked to play, switch to decoding state only if
   // we are currently buffering. In other cases, we'll start playing anyway
   // when the state machine notices the decoder's state change to PLAYING.
@@ -1526,31 +1529,23 @@ void MediaDecoderStateMachine::StopAudio
     SendStreamData();
   }
 }
 
 nsresult
 MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
 {
   AssertCurrentThreadInMonitor();
-
-  if (mState != DECODER_STATE_DECODING_METADATA ||
-      mDispatchedDecodeMetadataTask) {
-    return NS_OK;
-  }
-
-  mDispatchedDecodeMetadataTask = true;
+  MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
+
   RefPtr<nsIRunnable> task(
     NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
   nsresult rv = mDecodeTaskQueue->Dispatch(task);
-  if (NS_FAILED(rv)) {
-    DECODER_WARN("Dispatch ReadMetadata task failed.");
-    mDispatchedDecodeMetadataTask = false;
-  }
-  return rv;
+  NS_ENSURE_SUCCESS(rv, rv);
+  return NS_OK;
 }
 
 void
 MediaDecoderStateMachine::SetReaderIdle()
 {
 #ifdef PR_LOGGING
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
@@ -1867,35 +1862,32 @@ MediaDecoderStateMachine::CallDecodeMeta
     DecodeError();
   }
 }
 
 nsresult MediaDecoderStateMachine::DecodeMetadata()
 {
   AssertCurrentThreadInMonitor();
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
+  MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
   DECODER_LOG("Decoding Media Headers");
-  if (mState != DECODER_STATE_DECODING_METADATA) {
-    return NS_ERROR_FAILURE;
-  }
 
   nsresult res;
   MediaInfo info;
   {
     ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
     res = mReader->ReadMetadata(&info, getter_Transfers(mMetadataTags));
   }
 
   if (NS_SUCCEEDED(res)) {
     if (mState == DECODER_STATE_DECODING_METADATA &&
         mReader->IsWaitingMediaResources()) {
       // change state to DECODER_STATE_WAIT_FOR_RESOURCES
       StartWaitForResources();
       // affect values only if ReadMetadata succeeds
-      mDispatchedDecodeMetadataTask = false;
       return NS_OK;
     }
   }
 
   if (NS_SUCCEEDED(res)) {
     mDecoder->SetMediaSeekable(mReader->IsMediaSeekable());
   }
 
@@ -2007,17 +1999,16 @@ MediaDecoderStateMachine::FinishDecodeMe
 
   if ((mState == DECODER_STATE_DECODING || mState == DECODER_STATE_COMPLETED) &&
       mDecoder->GetState() == MediaDecoder::PLAY_STATE_PLAYING &&
       !IsPlaying())
   {
     StartPlayback();
   }
 
-  mDispatchedDecodeMetadataTask = false;
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::DecodeSeek()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   if (mState != DECODER_STATE_SEEKING) {
@@ -2138,16 +2129,18 @@ MediaDecoderStateMachine::SeekCompleted(
         RenderVideoFrame(video, TimeStamp::Now());
       }
       nsCOMPtr<nsIRunnable> event =
         NS_NewRunnableMethod(mDecoder, &MediaDecoder::Invalidate);
       NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
     }
   }
 
+  MOZ_ASSERT(mState != DECODER_STATE_DECODING_NONE);
+
   mDecoder->StartProgressUpdates();
   if (mState == DECODER_STATE_DECODING_METADATA ||
       mState == DECODER_STATE_DORMANT ||
       mState == DECODER_STATE_SHUTDOWN) {
     return;
   }
 
   // Change state to DECODING or COMPLETED now. SeekingStopped will
@@ -2324,21 +2317,26 @@ nsresult MediaDecoderStateMachine::RunSt
       }
       return NS_OK;
     }
 
     case DECODER_STATE_WAIT_FOR_RESOURCES: {
       return NS_OK;
     }
 
-    case DECODER_STATE_DECODING_METADATA: {
+    case DECODER_STATE_DECODING_NONE: {
+      mState = DECODER_STATE_DECODING_METADATA;
       // Ensure we have a decode thread to decode metadata.
       return EnqueueDecodeMetadataTask();
     }
 
+    case DECODER_STATE_DECODING_METADATA: {
+      return NS_OK;
+    }
+
     case DECODER_STATE_DECODING: {
       if (mDecoder->GetState() != MediaDecoder::PLAY_STATE_PLAYING &&
           IsPlaying())
       {
         // We're playing, but the element/decoder is in paused state. Stop
         // playing!
         StopPlayback();
       }
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -130,16 +130,17 @@ public:
   MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                MediaDecoderReader* aReader,
                                bool aRealTime = false);
 
   nsresult Init(MediaDecoderStateMachine* aCloneDonor);
 
   // Enumeration for the valid decoding states
   enum State {
+    DECODER_STATE_DECODING_NONE,
     DECODER_STATE_DECODING_METADATA,
     DECODER_STATE_WAIT_FOR_RESOURCES,
     DECODER_STATE_DORMANT,
     DECODER_STATE_DECODING,
     DECODER_STATE_SEEKING,
     DECODER_STATE_BUFFERING,
     DECODER_STATE_COMPLETED,
     DECODER_STATE_SHUTDOWN
@@ -888,21 +889,16 @@ protected:
   // memory and CPU overhead.
   bool mMinimizePreroll;
 
   // True if the decode thread has gone filled its buffers and is now
   // waiting to be awakened before it continues decoding. Synchronized
   // by the decoder monitor.
   bool mDecodeThreadWaiting;
 
-  // True if we've dispatched a task to the decode task queue to call
-  // ReadMetadata on the reader. We maintain a flag to ensure that we don't
-  // dispatch multiple tasks to re-do the metadata loading.
-  bool mDispatchedDecodeMetadataTask;
-
   // These two flags are true when we need to drop decoded samples that
   // we receive up to the next discontinuity. We do this when we seek;
   // the first sample in each stream after the seek is marked as being
   // a "discontinuity".
   bool mDropAudioUntilNextDiscontinuity;
   bool mDropVideoUntilNextDiscontinuity;
 
   // True if we need to decode forwards to the seek target inside