Bug 1128411. Part 2 - call SendStreamData() in AdvanceFrame() to simplify the code of SendStreamData(). r=roc. a=lmandel
authorJW Wang <jwwang@mozilla.com>
Mon, 02 Feb 2015 13:58:31 +0800
changeset 249762 636a4a911276cd861b60eb6a2db87c9cc5769f53
parent 249761 d89186268fb48a66a04d71f4a0a69c96a847eaa8
child 249763 982276da601721e6c361ef8b09c0cff202216ca5
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, lmandel
bugs1128411
milestone37.0a2
Bug 1128411. Part 2 - call SendStreamData() in AdvanceFrame() to simplify the code of SendStreamData(). r=roc. a=lmandel
dom/media/MediaDecoderStateMachine.cpp
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -389,39 +389,22 @@ static void WriteVideoToMediaStream(Medi
   StreamTime duration =
       aStream->MicrosecondsToStreamTimeRoundDown(aEndMicroseconds) -
       aStream->MicrosecondsToStreamTimeRoundDown(aStartMicroseconds);
   aOutput->AppendFrame(image.forget(), duration, aIntrinsicSize);
 }
 
 void MediaDecoderStateMachine::SendStreamData()
 {
-  NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
-               "Should be on decode thread or state machine thread");
+  MOZ_ASSERT(OnStateMachineThread(), "Should be on state machine thread");
   AssertCurrentThreadInMonitor();
-  MOZ_ASSERT(mState != DECODER_STATE_DECODING_NONE);
+  MOZ_ASSERT(!mAudioSink, "Should've been stopped in CallRunStateMachine()");
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
-  if (!stream) {
-    return;
-  }
-
-  if (mState == DECODER_STATE_DECODING_METADATA ||
-      mState == DECODER_STATE_DECODING_FIRSTFRAME) {
-    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) {
-    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;
 
     if (!stream->mStreamInitialized) {
@@ -577,22 +560,16 @@ bool MediaDecoderStateMachine::HaveEnoug
     return false;
   }
   if (!mAudioCaptured) {
     return true;
   }
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
 
-  // Since stream is initialized in SendStreamData() which is called when
-  // audio/video samples are received, we need to keep decoding to ensure
-  // the stream is initialized.
-  if (stream && !stream->mStreamInitialized) {
-    return false;
-  }
   if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
     if (!stream->mStream->HaveEnoughBuffered(kAudioTrack)) {
       return false;
     }
     stream->mStream->DispatchWhenNotEnoughBuffered(kAudioTrack,
         GetStateMachineThread(), GetWakeDecoderRunnable());
   }
 
@@ -604,20 +581,16 @@ bool MediaDecoderStateMachine::HaveEnoug
   AssertCurrentThreadInMonitor();
 
   if (static_cast<uint32_t>(VideoQueue().GetSize()) < mAmpleVideoFrames * mPlaybackRate) {
     return false;
   }
 
   DecodedStreamData* stream = mDecoder->GetDecodedStream();
 
-  if (stream && !stream->mStreamInitialized) {
-    return false;
-  }
-
   if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
     if (!stream->mStream->HaveEnoughBuffered(kVideoTrack)) {
       return false;
     }
     stream->mStream->DispatchWhenNotEnoughBuffered(kVideoTrack,
         GetStateMachineThread(), GetWakeDecoderRunnable());
   }
 
@@ -819,16 +792,20 @@ MediaDecoderStateMachine::OnAudioDecoded
       return;
     }
 
     case DECODER_STATE_DECODING: {
       Push(audio);
       if (mIsAudioPrerolling && DonePrerollingAudio()) {
         StopPrerollingAudio();
       }
+      // Schedule the state machine to send stream data as soon as possible.
+      if (mAudioCaptured) {
+        ScheduleStateMachine();
+      }
       return;
     }
 
     case DECODER_STATE_SEEKING: {
       if (!mCurrentSeekTarget.IsValid()) {
         // We've received a sample from a previous decode. Discard it.
         return;
       }
@@ -875,17 +852,16 @@ void
 MediaDecoderStateMachine::Push(AudioData* aSample)
 {
   MOZ_ASSERT(aSample);
   // TODO: Send aSample to MSG and recalculate readystate before pushing,
   // otherwise AdvanceFrame may pop the sample before we have a chance
   // to reach playing.
   AudioQueue().Push(aSample);
   if (mState > DECODER_STATE_DECODING_FIRSTFRAME) {
-    SendStreamData();
     // The ready state can change when we've decoded data, so update the
     // ready state, so that DOM events can fire.
     UpdateReadyState();
     DispatchDecodeTasksIfNeeded();
     mDecoder->GetReentrantMonitor().NotifyAll();
   }
 }
 
@@ -893,17 +869,16 @@ void
 MediaDecoderStateMachine::Push(VideoData* aSample)
 {
   MOZ_ASSERT(aSample);
   // TODO: Send aSample to MSG and recalculate readystate before pushing,
   // otherwise AdvanceFrame may pop the sample before we have a chance
   // to reach playing.
   VideoQueue().Push(aSample);
   if (mState > DECODER_STATE_DECODING_FIRSTFRAME) {
-    SendStreamData();
     // The ready state can change when we've decoded data, so update the
     // ready state, so that DOM events can fire.
     UpdateReadyState();
     DispatchDecodeTasksIfNeeded();
     mDecoder->GetReentrantMonitor().NotifyAll();
   }
 }
 
@@ -965,21 +940,24 @@ MediaDecoderStateMachine::OnNotDecoded(M
     case DECODER_STATE_DECODING_FIRSTFRAME: {
       MaybeFinishDecodeFirstFrame();
       return;
     }
 
     case DECODER_STATE_BUFFERING:
     case DECODER_STATE_DECODING: {
       CheckIfDecodeComplete();
-      SendStreamData();
       // The ready state can change when we've decoded data, so update the
       // ready state, so that DOM events can fire.
       UpdateReadyState();
       mDecoder->GetReentrantMonitor().NotifyAll();
+      // Schedule the state machine to notify track ended as soon as possible.
+      if (mAudioCaptured) {
+        ScheduleStateMachine();
+      }
       return;
     }
     case DECODER_STATE_SEEKING: {
       if (!mCurrentSeekTarget.IsValid()) {
         // We've received a sample from a previous decode. Discard it.
         return;
       }
 
@@ -1067,16 +1045,21 @@ MediaDecoderStateMachine::OnVideoDecoded
       {
         mLowAudioThresholdUsecs =
           std::min(THRESHOLD_FACTOR * DurationToUsecs(decodeTime), mAmpleAudioThresholdUsecs);
         mAmpleAudioThresholdUsecs = std::max(THRESHOLD_FACTOR * mLowAudioThresholdUsecs,
                                               mAmpleAudioThresholdUsecs);
         DECODER_LOG("Slow video decode, set mLowAudioThresholdUsecs=%lld mAmpleAudioThresholdUsecs=%lld",
                     mLowAudioThresholdUsecs, mAmpleAudioThresholdUsecs);
       }
+
+      // Schedule the state machine to send stream data as soon as possible.
+      if (mAudioCaptured) {
+        ScheduleStateMachine();
+      }
       return;
     }
     case DECODER_STATE_SEEKING: {
       if (!mCurrentSeekTarget.IsValid()) {
         // We've received a sample from a previous decode. Discard it.
         return;
       }
       if (mDropVideoUntilNextDiscontinuity) {
@@ -1848,19 +1831,16 @@ void MediaDecoderStateMachine::StopAudio
   if (mAudioSink) {
     DECODER_LOG("Shutdown audio thread");
     mAudioSink->PrepareToShutdown();
     {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       mAudioSink->Shutdown();
     }
     mAudioSink = nullptr;
-    // Now that the audio sink is dead, try sending data to our MediaStream(s).
-    // That may have been waiting for the audio thread to stop.
-    SendStreamData();
   }
   // Wake up those waiting for audio sink to finish.
   mDecoder->GetReentrantMonitor().NotifyAll();
 }
 
 nsresult
 MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
 {
@@ -3110,21 +3090,17 @@ void MediaDecoderStateMachine::AdvanceFr
   }
 
   // If playbackRate is 0.0, we should stop the progress, but not be in paused
   // state, per spec.
   if (mPlaybackRate == 0.0) {
     return;
   }
 
-  DecodedStreamData* stream = mDecoder->GetDecodedStream();
-  if (stream && !stream->mStreamInitialized) {
-    // Output streams exist but are not initialized yet.
-    // Send the data we already have to allow stream clock to progress and
-    // avoid stalling playback.
+  if (mAudioCaptured) {
     SendStreamData();
   }
 
   const int64_t clock_time = GetClock();
   TimeStamp nowTime = TimeStamp::Now();
   // 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.
   int64_t remainingTime = AUDIO_DURATION_USECS;