Bug 1134064 - Part 1: Don't hold on reader when we stop needing it. r=mattwoodrow, a=lsblakk
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 24 Feb 2015 16:38:41 +1100
changeset 250099 2e539009f86e
parent 250098 963bd7dabda0
child 250100 5f400332977d
push id4502
push userryanvm@gmail.com
push date2015-02-27 21:16 +0000
treeherdermozilla-beta@9fb3cc1f7ff6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, lsblakk
bugs1134064
milestone37.0
Bug 1134064 - Part 1: Don't hold on reader when we stop needing it. r=mattwoodrow, a=lsblakk
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/MediaSourceReader.h
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -105,18 +105,18 @@ MediaSourceReader::SizeOfAudioQueueInFra
   return GetAudioReader()->SizeOfAudioQueueInFrames();
 }
 
 nsRefPtr<MediaDecoderReader::AudioDataPromise>
 MediaSourceReader::RequestAudioData()
 {
   nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__);
   MSE_DEBUGV("");
-  if (!GetAudioReader()) {
-    MSE_DEBUG("called with no audio reader");
+  if (!mAudioTrack) {
+    MSE_DEBUG("called with no audio track");
     mAudioPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   if (IsSeeking()) {
     MSE_DEBUG("called mid-seek. Rejecting.");
     mAudioPromise.Reject(CANCELED, __func__);
     return p;
   }
@@ -125,22 +125,23 @@ MediaSourceReader::RequestAudioData()
   SwitchSourceResult ret = SwitchAudioSource(&mLastAudioTime);
   switch (ret) {
     case SOURCE_NEW:
       mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mLastAudioTime), 0)
                               ->RefableThen(GetTaskQueue(), __func__, this,
                                             &MediaSourceReader::CompleteAudioSeekAndDoRequest,
                                             &MediaSourceReader::CompleteAudioSeekAndRejectPromise));
       break;
-    case SOURCE_ERROR:
+    case SOURCE_NONE:
       if (mLastAudioTime) {
         CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
         break;
       }
-      // Fallback to using current reader
+      // Fallback to using first reader
+      mAudioSourceDecoder = mAudioTrack->Decoders()[0];
     default:
       DoAudioRequest();
       break;
   }
   return p;
 }
 
 void MediaSourceReader::DoAudioRequest()
@@ -248,18 +249,18 @@ MediaSourceReader::OnAudioNotDecoded(Not
 }
 
 nsRefPtr<MediaDecoderReader::VideoDataPromise>
 MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
 {
   nsRefPtr<VideoDataPromise> p = mVideoPromise.Ensure(__func__);
   MSE_DEBUGV("RequestVideoData(%d, %lld)",
              aSkipToNextKeyframe, aTimeThreshold);
-  if (!GetVideoReader()) {
-    MSE_DEBUG("called with no video reader");
+  if (!mVideoTrack) {
+    MSE_DEBUG("called with no video track");
     mVideoPromise.Reject(DECODE_ERROR, __func__);
     return p;
   }
   if (aSkipToNextKeyframe) {
     mTimeThreshold = aTimeThreshold;
     mDropAudioBeforeThreshold = true;
     mDropVideoBeforeThreshold = true;
   }
@@ -273,22 +274,23 @@ MediaSourceReader::RequestVideoData(bool
   SwitchSourceResult ret = SwitchVideoSource(&mLastVideoTime);
   switch (ret) {
     case SOURCE_NEW:
       mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0)
                              ->RefableThen(GetTaskQueue(), __func__, this,
                                            &MediaSourceReader::CompleteVideoSeekAndDoRequest,
                                            &MediaSourceReader::CompleteVideoSeekAndRejectPromise));
       break;
-    case SOURCE_ERROR:
+    case SOURCE_NONE:
       if (mLastVideoTime) {
         CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
         break;
       }
-      // Fallback to using current reader.
+      // Fallback to using first reader.
+      mVideoSourceDecoder = mVideoTrack->Decoders()[0];
     default:
       DoVideoRequest();
       break;
   }
 
   return p;
 }
 
@@ -477,88 +479,100 @@ MediaSourceReader::HaveData(int64_t aTar
 }
 
 MediaSourceReader::SwitchSourceResult
 MediaSourceReader::SwitchAudioSource(int64_t* aTarget)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding an audio track after ReadMetadata.
   if (!mAudioTrack) {
-    return SOURCE_ERROR;
+    return SOURCE_NONE;
   }
 
   // We first search without the tolerance and then search with it, so that, in
   // the case of perfectly-aligned data, we don't prematurely jump to a new
   // reader and skip the last few samples of the current one.
   bool usedFuzz = false;
   nsRefPtr<SourceBufferDecoder> newDecoder =
     SelectDecoder(*aTarget, /* aTolerance = */ 0, mAudioTrack->Decoders());
   if (!newDecoder) {
     newDecoder = SelectDecoder(*aTarget, EOS_FUZZ_US, mAudioTrack->Decoders());
     usedFuzz = true;
   }
-  if (newDecoder && newDecoder != mAudioSourceDecoder) {
+  if (GetAudioReader() && mAudioSourceDecoder != newDecoder) {
     GetAudioReader()->SetIdle();
-    mAudioSourceDecoder = newDecoder;
-    if (usedFuzz) {
-      // A decoder buffered range is continuous. We would have failed the exact
-      // search but succeeded the fuzzy one if our target was shortly before
-      // start time.
-      nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
-      newDecoder->GetBuffered(ranges);
-      int64_t startTime = ranges->GetStartTime() * USECS_PER_S;
-      if (*aTarget < startTime) {
-        *aTarget = startTime;
-      }
+  }
+  if (!newDecoder) {
+    mAudioSourceDecoder = nullptr;
+    return SOURCE_NONE;
+  }
+  if (newDecoder == mAudioSourceDecoder) {
+    return SOURCE_EXISTING;
+  }
+  mAudioSourceDecoder = newDecoder;
+  if (usedFuzz) {
+    // A decoder buffered range is continuous. We would have failed the exact
+    // search but succeeded the fuzzy one if our target was shortly before
+    // start time.
+    nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
+    newDecoder->GetBuffered(ranges);
+    int64_t startTime = ranges->GetStartTime() * USECS_PER_S;
+    if (*aTarget < startTime) {
+      *aTarget = startTime;
     }
-    MSE_DEBUGV("switched decoder to %p (fuzz:%d)",
-               mAudioSourceDecoder.get(), usedFuzz);
-    return SOURCE_NEW;
   }
-  return newDecoder ? SOURCE_EXISTING : SOURCE_ERROR;
+  MSE_DEBUGV("switched decoder to %p (fuzz:%d)",
+             mAudioSourceDecoder.get(), usedFuzz);
+  return SOURCE_NEW;
 }
 
 MediaSourceReader::SwitchSourceResult
 MediaSourceReader::SwitchVideoSource(int64_t* aTarget)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding a video track after ReadMetadata.
   if (!mVideoTrack) {
-    return SOURCE_ERROR;
+    return SOURCE_NONE;
   }
 
   // We first search without the tolerance and then search with it, so that, in
   // the case of perfectly-aligned data, we don't prematurely jump to a new
   // reader and skip the last few samples of the current one.
   bool usedFuzz = false;
   nsRefPtr<SourceBufferDecoder> newDecoder =
     SelectDecoder(*aTarget, /* aTolerance = */ 0, mVideoTrack->Decoders());
   if (!newDecoder) {
     newDecoder = SelectDecoder(*aTarget, EOS_FUZZ_US, mVideoTrack->Decoders());
     usedFuzz = true;
   }
-  if (newDecoder && newDecoder != mVideoSourceDecoder) {
+  if (GetVideoReader() && mVideoSourceDecoder != newDecoder) {
     GetVideoReader()->SetIdle();
-    mVideoSourceDecoder = newDecoder;
-    if (usedFuzz) {
-      // A decoder buffered range is continuous. We would have failed the exact
-      // search but succeeded the fuzzy one if our target was shortly before
-      // start time.
-      nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
-      newDecoder->GetBuffered(ranges);
-      int64_t startTime = ranges->GetStartTime() * USECS_PER_S;
-      if (*aTarget < startTime) {
-        *aTarget = startTime;
-      }
+  }
+  if (!newDecoder) {
+    mVideoSourceDecoder = nullptr;
+    return SOURCE_NONE;
+  }
+  if (newDecoder == mVideoSourceDecoder) {
+    return SOURCE_EXISTING;
+  }
+  mVideoSourceDecoder = newDecoder;
+  if (usedFuzz) {
+    // A decoder buffered range is continuous. We would have failed the exact
+    // search but succeeded the fuzzy one if our target was shortly before
+    // start time.
+    nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges();
+    newDecoder->GetBuffered(ranges);
+    int64_t startTime = ranges->GetStartTime() * USECS_PER_S;
+    if (*aTarget < startTime) {
+      *aTarget = startTime;
     }
-    MSE_DEBUGV("switched decoder to %p (fuzz:%d)",
-               mVideoSourceDecoder.get(), usedFuzz);
-    return SOURCE_NEW;
   }
-  return newDecoder ? SOURCE_EXISTING : SOURCE_ERROR;
+  MSE_DEBUGV("switched decoder to %p (fuzz:%d)",
+             mVideoSourceDecoder.get(), usedFuzz);
+  return SOURCE_NEW;
 }
 
 bool
 MediaSourceReader::IsDormantNeeded()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (GetVideoReader()) {
     return GetVideoReader()->IsDormantNeeded();
@@ -792,16 +806,17 @@ MediaSourceReader::OnVideoSeekFailed(nsr
   mPendingSeekTime = -1;
   mSeekPromise.Reject(aResult, __func__);
 }
 
 void
 MediaSourceReader::DoAudioSeek()
 {
   SwitchAudioSource(&mPendingSeekTime);
+  MOZ_ASSERT(GetAudioReader());
   mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mPendingSeekTime), 0)
                          ->RefableThen(GetTaskQueue(), __func__, this,
                                        &MediaSourceReader::OnAudioSeekCompleted,
                                        &MediaSourceReader::OnAudioSeekFailed));
   MSE_DEBUG("reader=%p", GetAudioReader());
 }
 
 void
@@ -852,16 +867,17 @@ MediaSourceReader::AttemptSeek()
     MOZ_CRASH();
   }
 }
 
 void
 MediaSourceReader::DoVideoSeek()
 {
   SwitchVideoSource(&mPendingSeekTime);
+  MOZ_ASSERT(GetVideoReader());
   mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mPendingSeekTime), 0)
                           ->RefableThen(GetTaskQueue(), __func__, this,
                                         &MediaSourceReader::OnVideoSeekCompleted,
                                         &MediaSourceReader::OnVideoSeekFailed));
   MSE_DEBUG("reader=%p", GetVideoReader());
 }
 
 nsresult
@@ -1078,17 +1094,17 @@ MediaSourceReader::SetCDMProxy(CDMProxy*
   return NS_OK;
 }
 #endif
 
 bool
 MediaSourceReader::IsActiveReader(MediaDecoderReader* aReader)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  return aReader == GetVideoReader() || aReader == GetAudioReader();
+  return aReader && (aReader == GetVideoReader() || aReader == GetAudioReader());
 }
 
 MediaDecoderReader*
 MediaSourceReader::GetAudioReader() const
 {
   return mAudioSourceDecoder ? mAudioSourceDecoder->GetReader() : nullptr;
 }
 
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -155,17 +155,17 @@ public:
 
 private:
   // Switch the current audio/video source to the source that
   // contains aTarget (or up to aTolerance after target). Both
   // aTarget and aTolerance are in microseconds.
   // Search can be made using a fuzz factor. Should an approximated value be
   // found instead, aTarget will be updated to the actual target found.
   enum SwitchSourceResult {
-    SOURCE_ERROR = -1,
+    SOURCE_NONE = -1,
     SOURCE_EXISTING = 0,
     SOURCE_NEW = 1,
   };
 
   SwitchSourceResult SwitchAudioSource(int64_t* aTarget);
   SwitchSourceResult SwitchVideoSource(int64_t* aTarget);
 
   void DoAudioRequest();