Bug 1125970 - Reject promises in MediaDecoderReader::ResetDecode and don't re-request audio and video when the promises have been rejected. v1 r=cpearce a=lmandel
authorBobby Holley <bobbyholley@gmail.com>
Fri, 13 Feb 2015 16:53:34 -0800
changeset 249934 0804aec59497d8bade6237362f95ed0939c1bc4b
parent 249933 2580e92051c630c7d7f387e859e43975f2ccaee8
child 249935 74c5dedf63e9e38baf52980e4116b7bc5945c870
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)
reviewerscpearce, lmandel
bugs1125970
milestone37.0a2
Bug 1125970 - Reject promises in MediaDecoderReader::ResetDecode and don't re-request audio and video when the promises have been rejected. v1 r=cpearce a=lmandel
dom/media/MediaDecoderReader.cpp
dom/media/MediaDecoderReader.h
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -111,25 +111,26 @@ size_t MediaDecoderReader::SizeOfVideoQu
 
 size_t MediaDecoderReader::SizeOfAudioQueueInFrames()
 {
   return mAudioQueue.GetSize();
 }
 
 nsresult MediaDecoderReader::ResetDecode()
 {
-  nsresult res = NS_OK;
-
   VideoQueue().Reset();
   AudioQueue().Reset();
 
   mAudioDiscontinuity = true;
   mVideoDiscontinuity = true;
 
-  return res;
+  mBaseAudioPromise.RejectIfExists(CANCELED, __func__);
+  mBaseVideoPromise.RejectIfExists(CANCELED, __func__);
+
+  return NS_OK;
 }
 
 VideoData* MediaDecoderReader::DecodeToFirstVideoData()
 {
   bool eof = false;
   while (!eof && VideoQueue().GetSize() == 0) {
     {
       ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
@@ -176,32 +177,65 @@ MediaDecoderReader::ComputeStartTime(con
     startTime = 0;
   }
   DECODER_LOG("ComputeStartTime first video frame start %lld", aVideo ? aVideo->mTime : -1);
   DECODER_LOG("ComputeStartTime first audio frame start %lld", aAudio ? aAudio->mTime : -1);
   MOZ_ASSERT(startTime >= 0);
   return startTime;
 }
 
-class RequestVideoWithSkipTask : public nsRunnable {
+class ReRequestVideoWithSkipTask : public nsRunnable
+{
 public:
-  RequestVideoWithSkipTask(MediaDecoderReader* aReader,
-                           int64_t aTimeThreshold)
+  ReRequestVideoWithSkipTask(MediaDecoderReader* aReader,
+                             int64_t aTimeThreshold)
     : mReader(aReader)
     , mTimeThreshold(aTimeThreshold)
   {
   }
-  NS_METHOD Run() {
-    bool skip = true;
-    mReader->RequestVideoData(skip, mTimeThreshold);
+
+  NS_METHOD Run()
+  {
+    MOZ_ASSERT(mReader->GetTaskQueue()->IsCurrentThreadIn());
+
+    // Make sure ResetDecode hasn't been called in the mean time.
+    if (!mReader->mBaseVideoPromise.IsEmpty()) {
+      mReader->RequestVideoData(/* aSkip = */ true, mTimeThreshold);
+    }
+
     return NS_OK;
   }
+
 private:
   nsRefPtr<MediaDecoderReader> mReader;
-  int64_t mTimeThreshold;
+  const int64_t mTimeThreshold;
+};
+
+class ReRequestAudioTask : public nsRunnable
+{
+public:
+  explicit ReRequestAudioTask(MediaDecoderReader* aReader)
+    : mReader(aReader)
+  {
+  }
+
+  NS_METHOD Run()
+  {
+    MOZ_ASSERT(mReader->GetTaskQueue()->IsCurrentThreadIn());
+
+    // Make sure ResetDecode hasn't been called in the mean time.
+    if (!mReader->mBaseAudioPromise.IsEmpty()) {
+      mReader->RequestAudioData();
+    }
+
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<MediaDecoderReader> mReader;
 };
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MediaDecoderReader::RequestVideoData(bool aSkipToNextKeyframe,
                                      int64_t aTimeThreshold)
 {
   nsRefPtr<VideoDataPromise> p = mBaseVideoPromise.Ensure(__func__);
   bool skip = aSkipToNextKeyframe;
@@ -209,17 +243,17 @@ MediaDecoderReader::RequestVideoData(boo
          !VideoQueue().IsFinished()) {
     if (!DecodeVideoFrame(skip, aTimeThreshold)) {
       VideoQueue().Finish();
     } else if (skip) {
       // We still need to decode more data in order to skip to the next
       // keyframe. Post another task to the decode task queue to decode
       // again. We don't just decode straight in a loop here, as that
       // would hog the decode task queue.
-      RefPtr<nsIRunnable> task(new RequestVideoWithSkipTask(this, aTimeThreshold));
+      RefPtr<nsIRunnable> task(new ReRequestVideoWithSkipTask(this, aTimeThreshold));
       mTaskQueue->Dispatch(task);
       return p;
     }
   }
   if (VideoQueue().GetSize() > 0) {
     nsRefPtr<VideoData> v = VideoQueue().PopFront();
     if (v && mVideoDiscontinuity) {
       v->mDiscontinuity = true;
@@ -245,19 +279,18 @@ MediaDecoderReader::RequestAudioData()
       AudioQueue().Finish();
       break;
     }
     // AudioQueue size is still zero, post a task to try again. Don't spin
     // waiting in this while loop since it somehow prevents audio EOS from
     // coming in gstreamer 1.x when there is still video buffer waiting to be
     // consumed. (|mVideoSinkBufferCount| > 0)
     if (AudioQueue().GetSize() == 0 && mTaskQueue) {
-      RefPtr<nsIRunnable> task(NS_NewRunnableMethod(
-          this, &MediaDecoderReader::RequestAudioData));
-      mTaskQueue->Dispatch(task.forget());
+      RefPtr<nsIRunnable> task(new ReRequestAudioTask(this));
+      mTaskQueue->Dispatch(task);
       return p;
     }
   }
   if (AudioQueue().GetSize() > 0) {
     nsRefPtr<AudioData> a = AudioQueue().PopFront();
     if (mAudioDiscontinuity) {
       a->mDiscontinuity = true;
       mAudioDiscontinuity = false;
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -128,16 +128,19 @@ public:
   //
   // Don't hold the decoder monitor while calling this, as the implementation
   // may try to wait on something that needs the monitor and deadlock.
   // If aSkipToKeyframe is true, the decode should skip ahead to the
   // the next keyframe at or after aTimeThreshold microseconds.
   virtual nsRefPtr<VideoDataPromise>
   RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
 
+  friend class ReRequestVideoWithSkipTask;
+  friend class ReRequestAudioTask;
+
   // By default, the state machine polls the reader once per second when it's
   // in buffering mode. Some readers support a promise-based mechanism by which
   // they notify the state machine when the data arrives.
   virtual bool IsWaitForDataSupported() { return false; }
   virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) { MOZ_CRASH(); }
 
   virtual bool HasAudio() = 0;
   virtual bool HasVideo() = 0;