Bug 1062134 - Freeze decoding when back from Dormant state. r=jwwang
authorBenjamin Chen <bechen@mozilla.com>
Fri, 24 Oct 2014 17:25:45 +0800
changeset 212429 5e7e2144257259ac26be3396ecf1aa8db4f1ebc4
parent 212428 bf825ec5f56b641338d248ca14ead00d73284715
child 212430 8f5051232a06a814289fb9967f4c2b7f2394aa9b
push id27710
push usercbook@mozilla.com
push dateMon, 27 Oct 2014 14:52:01 +0000
treeherdermozilla-central@d65d20dc0ac2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwwang
bugs1062134
milestone36.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 1062134 - Freeze decoding when back from Dormant state. r=jwwang
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
dom/media/omx/RtspMediaCodecReader.cpp
dom/media/omx/RtspMediaCodecReader.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -208,17 +208,19 @@ MediaDecoderStateMachine::MediaDecoderSt
   mStopAudioThread(true),
   mQuickBuffering(false),
   mMinimizePreroll(false),
   mDecodeThreadWaiting(false),
   mDropAudioUntilNextDiscontinuity(false),
   mDropVideoUntilNextDiscontinuity(false),
   mDecodeToSeekTarget(false),
   mCurrentTimeBeforeSeek(0),
-  mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
+  mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
+  mDecodingFrozenAtStateMetadata(false),
+  mDecodingFrozenAtStateDecoding(false)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   mAmpleVideoFrames =
     std::max<uint32_t>(Preferences::GetUint("media.video-queue.default-size", 10), 3);
 
   mBufferingWait = mScheduler->IsRealTime() ? 0 : BUFFERING_WAIT_S;
@@ -1351,18 +1353,19 @@ void MediaDecoderStateMachine::SetDorman
 
   DECODER_LOG("SetDormant=%d", aDormant);
 
   if (aDormant) {
     ScheduleStateMachine();
     SetState(DECODER_STATE_DORMANT);
     mDecoder->GetReentrantMonitor().NotifyAll();
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
+    mDecodingFrozenAtStateMetadata = true;
+    mDecodingFrozenAtStateDecoding = true;
     ScheduleStateMachine();
-    mStartTime = 0;
     mCurrentFrameTime = 0;
     SetState(DECODER_STATE_DECODING_NONE);
     mDecoder->GetReentrantMonitor().NotifyAll();
   }
 }
 
 void MediaDecoderStateMachine::Shutdown()
 {
@@ -1449,16 +1452,20 @@ void MediaDecoderStateMachine::Play()
   // we are currently buffering. In other cases, we'll start playing anyway
   // when the state machine notices the decoder's state change to PLAYING.
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (mState == DECODER_STATE_BUFFERING) {
     DECODER_LOG("Changed state from BUFFERING to DECODING");
     SetState(DECODER_STATE_DECODING);
     mDecodeStartTime = TimeStamp::Now();
   }
+  if (mDecodingFrozenAtStateDecoding) {
+    mDecodingFrozenAtStateDecoding = false;
+    DispatchDecodeTasksIfNeeded();
+  }
   // Once we start playing, we don't want to minimize our prerolling, as we
   // assume the user is likely to want to keep playing in future.
   mMinimizePreroll = false;
   ScheduleStateMachine();
 }
 
 void MediaDecoderStateMachine::ResetPlayback()
 {
@@ -1510,16 +1517,18 @@ void MediaDecoderStateMachine::NotifyDat
   }
 }
 
 void MediaDecoderStateMachine::Seek(const SeekTarget& aTarget)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
+  mDecodingFrozenAtStateDecoding = false;
+
   if (mState == DECODER_STATE_SHUTDOWN) {
     return;
   }
 
   // We need to be able to seek both at a transport level and at a media level
   // to seek.
   if (!mDecoder->IsMediaSeekable()) {
     DECODER_WARN("Seek() function should not be called on a non-seekable state machine");
@@ -1617,16 +1626,21 @@ MediaDecoderStateMachine::DispatchDecode
   AssertCurrentThreadInMonitor();
 
   if (mState != DECODER_STATE_DECODING &&
       mState != DECODER_STATE_BUFFERING &&
       mState != DECODER_STATE_SEEKING) {
     return;
   }
 
+  if (mState == DECODER_STATE_DECODING && mDecodingFrozenAtStateDecoding) {
+    DECODER_LOG("DispatchDecodeTasksIfNeeded return due to "
+                "mFreezeDecodingAtStateDecoding");
+    return;
+  }
   // NeedToDecodeAudio() can go from false to true while we hold the
   // monitor, but it can't go from true to false. This can happen because
   // NeedToDecodeAudio() takes into account the amount of decoded audio
   // that's been written to the AudioStream but not played yet. So if we
   // were calling NeedToDecodeAudio() twice and we thread-context switch
   // between the calls, audio can play, which can affect the return value
   // of NeedToDecodeAudio() giving inconsistent results. So we cache the
   // value returned by NeedToDecodeAudio(), and make decisions
@@ -1967,16 +1981,20 @@ nsresult MediaDecoderStateMachine::Decod
       NS_NewRunnableMethod(this, &MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded));
     VideoQueue().AddPopListener(decodeTask, mDecodeTaskQueue);
   }
 
   if (mScheduler->IsRealTime()) {
     SetStartTime(0);
     res = FinishDecodeMetadata();
     NS_ENSURE_SUCCESS(res, res);
+  } else if (mDecodingFrozenAtStateMetadata) {
+    SetStartTime(mStartTime);
+    res = FinishDecodeMetadata();
+    NS_ENSURE_SUCCESS(res, res);
   } else {
     if (HasAudio()) {
       ReentrantMonitorAutoExit unlock(mDecoder->GetReentrantMonitor());
       mReader->RequestAudioData();
     }
     if (HasVideo()) {
       ReentrantMonitorAutoExit unlock(mDecoder->GetReentrantMonitor());
       mReader->RequestVideoData(false, 0);
@@ -1992,17 +2010,17 @@ MediaDecoderStateMachine::FinishDecodeMe
   AssertCurrentThreadInMonitor();
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   DECODER_LOG("FinishDecodeMetadata");
 
   if (mState == DECODER_STATE_SHUTDOWN) {
     return NS_ERROR_FAILURE;
   }
 
-  if (!mScheduler->IsRealTime()) {
+  if (!mScheduler->IsRealTime() && !mDecodingFrozenAtStateMetadata) {
 
     const VideoData* v = VideoQueue().PeekFront();
     const AudioData* a = AudioQueue().PeekFront();
 
     int64_t startTime = std::min<int64_t>(a ? a->mTime : INT64_MAX,
                                           v ? v->mTime : INT64_MAX);
     if (startTime == INT64_MAX) {
       startTime = 0;
@@ -2024,16 +2042,18 @@ MediaDecoderStateMachine::FinishDecodeMe
   MOZ_ASSERT(!(mDecoder->IsMediaSeekable() && mDecoder->IsTransportSeekable()) ||
                GetDuration() != -1,
              "Seekable media should have duration");
   DECODER_LOG("Media goes from %lld to %lld (duration %lld) "
               "transportSeekable=%d, mediaSeekable=%d",
               mStartTime, mEndTime, GetDuration(),
               mDecoder->IsTransportSeekable(), mDecoder->IsMediaSeekable());
 
+  mDecodingFrozenAtStateMetadata = false;
+
   if (HasAudio() && !HasVideo()) {
     // We're playing audio only. We don't need to worry about slow video
     // decodes causing audio underruns, so don't buffer so much audio in
     // order to reduce memory usage.
     mAmpleAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
     mLowAudioThresholdUsecs /= NO_VIDEO_AMPLE_AUDIO_DIVISOR;
   }
 
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -916,12 +916,23 @@ protected:
 
   // Stores presentation info required for playback. The decoder monitor
   // must be held when accessing this.
   MediaInfo mInfo;
 
   mozilla::MediaMetadataManager mMetadataManager;
 
   MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
+
+  // True if we are back from DECODER_STATE_DORMANT state, and we can skip
+  // SetStartTime because the mStartTime already set before. Also we don't need
+  // to decode any audio/video since the MediaDecoder will trigger a seek
+  // operation soon.
+  // mDecodingFrozenAtStateMetadata: turn on/off at
+  //                                 SetDormant/FinishDecodeMetadata.
+  // mDecodingFrozenAtStateDecoding: turn on/off at
+  //                                 SetDormant/Seek,Play.
+  bool mDecodingFrozenAtStateMetadata;
+  bool mDecodingFrozenAtStateDecoding;
 };
 
 } // namespace mozilla;
 #endif
--- a/dom/media/omx/RtspMediaCodecReader.cpp
+++ b/dom/media/omx/RtspMediaCodecReader.cpp
@@ -96,21 +96,9 @@ RtspMediaCodecReader::ReadMetadata(Media
   nsresult rv = MediaCodecReader::ReadMetadata(aInfo, aTags);
   if (rv == NS_OK && !IsWaitingMediaResources()) {
     EnsureActive();
   }
 
   return rv;
 }
 
-// Called on Binder thread.
-void
-RtspMediaCodecReader::codecReserved(Track& aTrack)
-{
-  // TODO: fix me, we need a SeekTime(0) here because the
-  // MediaDecoderStateMachine will update the mStartTime after ReadMetadata.
-  MediaCodecReader::codecReserved(aTrack);
-  if (aTrack.mCodec != nullptr) {
-    mRtspResource->SeekTime(0);
-  }
-}
-
 } // namespace mozilla
--- a/dom/media/omx/RtspMediaCodecReader.h
+++ b/dom/media/omx/RtspMediaCodecReader.h
@@ -60,18 +60,16 @@ public:
                                 int64_t aTimeThreshold) MOZ_OVERRIDE;
 
   // Disptach a DecodeAudioDataTask to decode audio data.
   virtual void RequestAudioData() MOZ_OVERRIDE;
 
   virtual nsresult ReadMetadata(MediaInfo* aInfo,
                                 MetadataTags** aTags) MOZ_OVERRIDE;
 
-  virtual void codecReserved(Track& aTrack) MOZ_OVERRIDE;
-
 private:
   // A pointer to RtspMediaResource for calling the Rtsp specific function.
   // The lifetime of mRtspResource is controlled by MediaDecoder. MediaDecoder
   // holds the MediaDecoderStateMachine and RtspMediaResource.
   // And MediaDecoderStateMachine holds this RtspMediaCodecReader.
   RtspMediaResource* mRtspResource;
 };