Bug 1126465 - Use a MediaPromiseConsumerHolders to track subdecoder seeks. r=mattwoodrow, a=sledru
authorBobby Holley <bobbyholley@gmail.com>
Thu, 29 Jan 2015 22:11:12 -0800
changeset 243649 169b4de5b199
parent 243648 cc2a8374de88
child 243650 361d53acbf3a
push id4421
push userryanvm@gmail.com
push date2015-02-02 19:52 +0000
treeherdermozilla-beta@08a02585bc60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, sledru
bugs1126465
milestone36.0
Bug 1126465 - Use a MediaPromiseConsumerHolders to track subdecoder seeks. r=mattwoodrow, a=sledru This combines part 10 and part 10.5 in the bug.
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/MediaSourceReader.h
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -46,18 +46,16 @@ using mozilla::dom::TimeRanges;
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mLastAudioTime(0)
   , mLastVideoTime(0)
   , mPendingSeekTime(-1)
   , mWaitingForSeekData(false)
-  , mAudioIsSeeking(false)
-  , mVideoIsSeeking(false)
   , mTimeThreshold(0)
   , mDropAudioBeforeThreshold(false)
   , mDropVideoBeforeThreshold(false)
   , mEnded(false)
   , mMediaSourceDuration(0)
   , mHasEssentialTrackBuffers(false)
 #ifdef MOZ_FMP4
   , mSharedDecoderManager(new SharedDecoderManager())
@@ -120,63 +118,48 @@ MediaSourceReader::RequestAudioData()
     mAudioPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   if (IsSeeking()) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called mid-seek. Rejecting.", this);
     mAudioPromise.Reject(CANCELED, __func__);
     return p;
   }
+  MOZ_RELEASE_ASSERT(!mAudioSeekRequest.Exists());
+
   SwitchReaderResult ret = SwitchAudioReader(mLastAudioTime);
   switch (ret) {
     case READER_NEW:
-      mAudioReader->Seek(mLastAudioTime, 0)
-                  ->Then(GetTaskQueue(), __func__, this,
-                         &MediaSourceReader::RequestAudioDataComplete,
-                         &MediaSourceReader::RequestAudioDataFailed);
+      mAudioSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
+                              ->RefableThen(GetTaskQueue(), __func__, this,
+                                            &MediaSourceReader::CompleteAudioSeekAndDoRequest,
+                                            &MediaSourceReader::CompleteAudioSeekAndRejectPromise));
       break;
     case READER_ERROR:
       if (mLastAudioTime) {
         CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
         break;
       }
       // Fallback to using current reader
     default:
       DoAudioRequest();
       break;
   }
   return p;
 }
 
-void
-MediaSourceReader::RequestAudioDataComplete(int64_t aTime)
-{
-  if (IsSeeking()) {
-    MSE_DEBUG("MediaSourceReader(%p)::RequestAudioDataComplete called mid-seek. Rejecting.", this);
-    MOZ_RELEASE_ASSERT(mAudioPromise.IsEmpty()); // Already rejected in ::Seek().
-    return;
-  }
-  DoAudioRequest();
-}
-
 void MediaSourceReader::DoAudioRequest()
 {
   mAudioRequest.Begin(mAudioReader->RequestAudioData()
                       ->RefableThen(GetTaskQueue(), __func__, this,
                                     &MediaSourceReader::OnAudioDecoded,
                                     &MediaSourceReader::OnAudioNotDecoded));
 }
 
 void
-MediaSourceReader::RequestAudioDataFailed(nsresult aResult)
-{
-  mAudioPromise.Reject(DECODE_ERROR, __func__);
-}
-
-void
 MediaSourceReader::OnAudioDecoded(AudioData* aSample)
 {
   MOZ_RELEASE_ASSERT(!IsSeeking());
   mAudioRequest.Complete();
 
   MSE_DEBUGV("MediaSourceReader(%p)::OnAudioDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropAudioBeforeThreshold) {
@@ -239,20 +222,20 @@ MediaSourceReader::OnAudioNotDecoded(Not
   // switching to the end of the buffered range.
   MOZ_ASSERT(aReason == END_OF_STREAM);
   if (mAudioReader) {
     AdjustEndTime(&mLastAudioTime, mAudioReader);
   }
 
   // See if we can find a different reader that can pick up where we left off.
   if (SwitchAudioReader(mLastAudioTime) == READER_NEW) {
-    mAudioReader->Seek(mLastAudioTime, 0)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::RequestAudioDataComplete,
-                       &MediaSourceReader::RequestAudioDataFailed);
+    mAudioSeekRequest.Begin(mAudioReader->Seek(mLastAudioTime, 0)
+                            ->RefableThen(GetTaskQueue(), __func__, this,
+                                          &MediaSourceReader::CompleteAudioSeekAndDoRequest,
+                                          &MediaSourceReader::CompleteAudioSeekAndRejectPromise));
     return;
   }
 
   CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
 }
 
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
@@ -271,65 +254,50 @@ MediaSourceReader::RequestVideoData(bool
     mDropAudioBeforeThreshold = true;
     mDropVideoBeforeThreshold = true;
   }
   if (IsSeeking()) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called mid-seek. Rejecting.", this);
     mVideoPromise.Reject(CANCELED, __func__);
     return p;
   }
+  MOZ_RELEASE_ASSERT(!mVideoSeekRequest.Exists());
+
   SwitchReaderResult ret = SwitchVideoReader(mLastVideoTime);
   switch (ret) {
     case READER_NEW:
-      mVideoReader->Seek(mLastVideoTime, 0)
-                  ->Then(GetTaskQueue(), __func__, this,
-                         &MediaSourceReader::RequestVideoDataComplete,
-                         &MediaSourceReader::RequestVideoDataFailed);
+      mVideoSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
+                             ->RefableThen(GetTaskQueue(), __func__, this,
+                                           &MediaSourceReader::CompleteVideoSeekAndDoRequest,
+                                           &MediaSourceReader::CompleteVideoSeekAndRejectPromise));
       break;
     case READER_ERROR:
       if (mLastVideoTime) {
         CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
         break;
       }
       // Fallback to using current reader.
     default:
       DoVideoRequest();
       break;
   }
 
   return p;
 }
 
 void
-MediaSourceReader::RequestVideoDataComplete(int64_t aTime)
-{
-  if (IsSeeking()) {
-    MSE_DEBUG("MediaSourceReader(%p)::RequestVideoDataComplete called mid-seek. Rejecting.", this);
-    MOZ_ASSERT(mVideoPromise.IsEmpty()); // Already rejected in ::Seek().
-    return;
-  }
-  DoVideoRequest();
-}
-
-void
 MediaSourceReader::DoVideoRequest()
 {
   mVideoRequest.Begin(mVideoReader->RequestVideoData(mDropVideoBeforeThreshold, mTimeThreshold)
                       ->RefableThen(GetTaskQueue(), __func__, this,
                                     &MediaSourceReader::OnVideoDecoded,
                                     &MediaSourceReader::OnVideoNotDecoded));
 }
 
 void
-MediaSourceReader::RequestVideoDataFailed(nsresult aResult)
-{
-  mVideoPromise.Reject(DECODE_ERROR, __func__);
-}
-
-void
 MediaSourceReader::OnVideoDecoded(VideoData* aSample)
 {
   MOZ_RELEASE_ASSERT(!IsSeeking());
   mVideoRequest.Complete();
 
   MSE_DEBUGV("MediaSourceReader(%p)::OnVideoDecoded [mTime=%lld mDuration=%lld mDiscontinuity=%d]",
              this, aSample->mTime, aSample->mDuration, aSample->mDiscontinuity);
   if (mDropVideoBeforeThreshold) {
@@ -364,20 +332,20 @@ MediaSourceReader::OnVideoNotDecoded(Not
   // switching to the end of the buffered range.
   MOZ_ASSERT(aReason == END_OF_STREAM);
   if (mVideoReader) {
     AdjustEndTime(&mLastVideoTime, mVideoReader);
   }
 
   // See if we can find a different reader that can pick up where we left off.
   if (SwitchVideoReader(mLastVideoTime) == READER_NEW) {
-    mVideoReader->Seek(mLastVideoTime, 0)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::RequestVideoDataComplete,
-                       &MediaSourceReader::RequestVideoDataFailed);
+    mVideoSeekRequest.Begin(mVideoReader->Seek(mLastVideoTime, 0)
+                           ->RefableThen(GetTaskQueue(), __func__, this,
+                                         &MediaSourceReader::CompleteVideoSeekAndDoRequest,
+                                         &MediaSourceReader::CompleteVideoSeekAndRejectPromise));
     return;
   }
 
   CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
 }
 
 void
 MediaSourceReader::CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime)
@@ -688,16 +656,21 @@ MediaSourceReader::Seek(int64_t aTime, i
   mAudioRequest.DisconnectIfExists();
   mVideoRequest.DisconnectIfExists();
 
   // Additionally, reject any outstanding promises _we_ made that we might have
   // been waiting on the above to fulfill.
   mAudioPromise.RejectIfExists(CANCELED, __func__);
   mVideoPromise.RejectIfExists(CANCELED, __func__);
 
+  // Finally, if we were midway seeking a new reader to find a sample, abandon
+  // that too.
+  mAudioSeekRequest.DisconnectIfExists();
+  mVideoSeekRequest.DisconnectIfExists();
+
   // Store pending seek target in case the track buffers don't contain
   // the desired time and we delay doing the seek.
   mPendingSeekTime = aTime;
 
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     mWaitingForSeekData = true;
   }
@@ -706,86 +679,74 @@ MediaSourceReader::Seek(int64_t aTime, i
   return p;
 }
 
 void
 MediaSourceReader::CancelSeek()
 {
   MOZ_ASSERT(OnDecodeThread());
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  if (mWaitingForSeekData) {
-    mSeekPromise.Reject(NS_OK, __func__);
-    mWaitingForSeekData = false;
-    mPendingSeekTime = -1;
-  } else if (mVideoIsSeeking) {
-    // NB: Currently all readers have sync Seeks(), so this is a no-op.
+  mWaitingForSeekData = false;
+  mPendingSeekTime = -1;
+  if (mAudioReader) {
+    mAudioSeekRequest.DisconnectIfExists();
+    mAudioReader->CancelSeek();
+  }
+  if (mVideoReader) {
+    mVideoSeekRequest.DisconnectIfExists();
     mVideoReader->CancelSeek();
-  } else if (mAudioIsSeeking) {
-    // NB: Currently all readers have sync Seeks(), so this is a no-op.
-    mAudioReader->CancelSeek();
-  } else {
-    MOZ_ASSERT(mSeekPromise.IsEmpty());
   }
+  mSeekPromise.RejectIfExists(NS_OK, __func__);
 }
 
 void
 MediaSourceReader::OnVideoSeekCompleted(int64_t aTime)
 {
-  MOZ_ASSERT(mVideoIsSeeking);
-  MOZ_ASSERT(!mAudioIsSeeking);
-  mVideoIsSeeking = false;
+  mVideoSeekRequest.Complete();
 
   if (mAudioTrack) {
     mPendingSeekTime = aTime;
     DoAudioSeek();
   } else {
     mPendingSeekTime = -1;
     mSeekPromise.Resolve(aTime, __func__);
   }
 }
 
 void
+MediaSourceReader::OnVideoSeekFailed(nsresult aResult)
+{
+  mVideoSeekRequest.Complete();
+  mPendingSeekTime = -1;
+  mSeekPromise.Reject(aResult, __func__);
+}
+
+void
 MediaSourceReader::DoAudioSeek()
 {
-    mAudioIsSeeking = true;
     SwitchAudioReader(mPendingSeekTime);
-    mAudioReader->Seek(mPendingSeekTime, 0)
-                ->Then(GetTaskQueue(), __func__, this,
-                       &MediaSourceReader::OnAudioSeekCompleted,
-                       &MediaSourceReader::OnSeekFailed);
+    mAudioSeekRequest.Begin(mAudioReader->Seek(mPendingSeekTime, 0)
+                           ->RefableThen(GetTaskQueue(), __func__, this,
+                                         &MediaSourceReader::OnAudioSeekCompleted,
+                                         &MediaSourceReader::OnAudioSeekFailed));
     MSE_DEBUG("MediaSourceReader(%p)::DoAudioSeek reader=%p", this, mAudioReader.get());
 }
 
 void
 MediaSourceReader::OnAudioSeekCompleted(int64_t aTime)
 {
-  mPendingSeekTime = aTime;
-  MOZ_ASSERT(mAudioIsSeeking);
-  MOZ_ASSERT(!mVideoIsSeeking);
-  mAudioIsSeeking = false;
-
+  mAudioSeekRequest.Complete();
   mPendingSeekTime = -1;
   mSeekPromise.Resolve(aTime, __func__);
 }
 
 void
-MediaSourceReader::OnSeekFailed(nsresult aResult)
+MediaSourceReader::OnAudioSeekFailed(nsresult aResult)
 {
-  MOZ_ASSERT(mVideoIsSeeking || mAudioIsSeeking);
-
-  if (mVideoIsSeeking) {
-    MOZ_ASSERT(!mAudioIsSeeking);
-    mVideoIsSeeking = false;
-  }
-
-  if (mAudioIsSeeking) {
-    MOZ_ASSERT(!mVideoIsSeeking);
-    mAudioIsSeeking = false;
-  }
-
+  mAudioSeekRequest.Complete();
   mPendingSeekTime = -1;
   mSeekPromise.Reject(aResult, __func__);
 }
 
 void
 MediaSourceReader::AttemptSeek()
 {
   // Make sure we don't hold the monitor while calling into the reader
@@ -814,22 +775,21 @@ MediaSourceReader::AttemptSeek()
   } else {
     MOZ_CRASH();
   }
 }
 
 void
 MediaSourceReader::DoVideoSeek()
 {
-  mVideoIsSeeking = true;
   SwitchVideoReader(mPendingSeekTime);
-  mVideoReader->Seek(mPendingSeekTime, 0)
-              ->Then(GetTaskQueue(), __func__, this,
-                     &MediaSourceReader::OnVideoSeekCompleted,
-                     &MediaSourceReader::OnSeekFailed);
+  mVideoSeekRequest.Begin(mVideoReader->Seek(mPendingSeekTime, 0)
+                          ->RefableThen(GetTaskQueue(), __func__, this,
+                                        &MediaSourceReader::OnVideoSeekCompleted,
+                                        &MediaSourceReader::OnVideoSeekFailed));
   MSE_DEBUG("MediaSourceReader(%p)::DoVideoSeek reader=%p", this, mVideoReader.get());
 }
 
 nsresult
 MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   MOZ_ASSERT(aBuffered->Length() == 0);
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -56,18 +56,19 @@ public:
   void OnAudioDecoded(AudioData* aSample);
   void OnAudioNotDecoded(NotDecodedReason aReason);
   void OnVideoDecoded(VideoData* aSample);
   void OnVideoNotDecoded(NotDecodedReason aReason);
 
   void DoVideoSeek();
   void DoAudioSeek();
   void OnVideoSeekCompleted(int64_t aTime);
+  void OnVideoSeekFailed(nsresult aResult);
   void OnAudioSeekCompleted(int64_t aTime);
-  void OnSeekFailed(nsresult aResult);
+  void OnAudioSeekFailed(nsresult aResult);
 
   virtual bool IsWaitForDataSupported() MOZ_OVERRIDE { return true; }
   virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) MOZ_OVERRIDE;
   void MaybeNotifyHaveData();
 
   bool HasVideo() MOZ_OVERRIDE
   {
     return mInfo.HasVideo();
@@ -160,20 +161,40 @@ private:
   };
 
   SwitchReaderResult SwitchAudioReader(int64_t aTarget);
   SwitchReaderResult SwitchVideoReader(int64_t aTarget);
 
   void DoAudioRequest();
   void DoVideoRequest();
 
-  void RequestAudioDataComplete(int64_t aTime);
-  void RequestAudioDataFailed(nsresult aResult);
-  void RequestVideoDataComplete(int64_t aTime);
-  void RequestVideoDataFailed(nsresult aResult);
+  void CompleteAudioSeekAndDoRequest()
+  {
+    mAudioSeekRequest.Complete();
+    DoAudioRequest();
+  }
+
+  void CompleteVideoSeekAndDoRequest()
+  {
+    mVideoSeekRequest.Complete();
+    DoVideoRequest();
+  }
+
+  void CompleteAudioSeekAndRejectPromise()
+  {
+    mAudioSeekRequest.Complete();
+    mAudioPromise.Reject(DECODE_ERROR, __func__);
+  }
+
+  void CompleteVideoSeekAndRejectPromise()
+  {
+    mVideoSeekRequest.Complete();
+    mVideoPromise.Reject(DECODE_ERROR, __func__);
+  }
+
   // Will reject the MediaPromise with END_OF_STREAM if mediasource has ended
   // or with WAIT_FOR_DATA otherwise.
   void CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime /* microseconds */);
 
   // Return a reader from the set available in aTrackDecoders that has data
   // available in the range requested by aTarget.
   already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
                                                     int64_t aTolerance,
@@ -208,23 +229,24 @@ private:
 #ifdef MOZ_EME
   nsRefPtr<CDMProxy> mCDMProxy;
 #endif
 
   // These are read and written on the decode task queue threads.
   int64_t mLastAudioTime;
   int64_t mLastVideoTime;
 
+  MediaPromiseConsumerHolder<SeekPromise> mAudioSeekRequest;
+  MediaPromiseConsumerHolder<SeekPromise> mVideoSeekRequest;
+  MediaPromiseHolder<SeekPromise> mSeekPromise;
+
   // Temporary seek information while we wait for the data
   // to be added to the track buffer.
-  MediaPromiseHolder<SeekPromise> mSeekPromise;
   int64_t mPendingSeekTime;
   bool mWaitingForSeekData;
-  bool mAudioIsSeeking;
-  bool mVideoIsSeeking;
 
   int64_t mTimeThreshold;
   bool mDropAudioBeforeThreshold;
   bool mDropVideoBeforeThreshold;
 
   bool mEnded;
   double mMediaSourceDuration;