Bug 1125469: Part1. Don't attempt to seek on time found with fuzz search. r=mattwoodrow a=lmandel
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 06 Feb 2015 23:51:46 +1100
changeset 249945 d1446f0958fc76015393f951e38315b1c7c950e4
parent 249944 9fb98996305ce5c4a79a511fc1ddba25c6946685
child 249946 6460ad2e3ecd8487de53eb801f4d5b3d0ae198d6
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)
reviewersmattwoodrow, lmandel
bugs1125469
milestone37.0a2
Bug 1125469: Part1. Don't attempt to seek on time found with fuzz search. r=mattwoodrow a=lmandel Instead seek to the actual time available.
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/MediaSourceReader.h
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -121,17 +121,17 @@ MediaSourceReader::RequestAudioData()
   }
   if (IsSeeking()) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called mid-seek. Rejecting.", this);
     mAudioPromise.Reject(CANCELED, __func__);
     return p;
   }
   MOZ_DIAGNOSTIC_ASSERT(!mAudioSeekRequest.Exists());
 
-  SwitchSourceResult ret = SwitchAudioSource(mLastAudioTime);
+  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:
@@ -228,17 +228,17 @@ MediaSourceReader::OnAudioNotDecoded(Not
   // End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
   MOZ_ASSERT(aReason == END_OF_STREAM);
   if (mAudioSourceDecoder) {
     AdjustEndTime(&mLastAudioTime, mAudioSourceDecoder);
   }
 
   // See if we can find a different source that can pick up where we left off.
-  if (SwitchAudioSource(mLastAudioTime) == SOURCE_NEW) {
+  if (SwitchAudioSource(&mLastAudioTime) == SOURCE_NEW) {
     mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mLastAudioTime), 0)
                             ->RefableThen(GetTaskQueue(), __func__, this,
                                           &MediaSourceReader::CompleteAudioSeekAndDoRequest,
                                           &MediaSourceReader::CompleteAudioSeekAndRejectPromise));
     return;
   }
 
   CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
@@ -262,17 +262,17 @@ MediaSourceReader::RequestVideoData(bool
   }
   if (IsSeeking()) {
     MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called mid-seek. Rejecting.", this);
     mVideoPromise.Reject(CANCELED, __func__);
     return p;
   }
   MOZ_DIAGNOSTIC_ASSERT(!mVideoSeekRequest.Exists());
 
-  SwitchSourceResult ret = SwitchVideoSource(mLastVideoTime);
+  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:
@@ -346,17 +346,17 @@ MediaSourceReader::OnVideoNotDecoded(Not
   // End of stream. Force switching past this stream to another reader by
   // switching to the end of the buffered range.
   MOZ_ASSERT(aReason == END_OF_STREAM);
   if (mVideoSourceDecoder) {
     AdjustEndTime(&mLastVideoTime, mVideoSourceDecoder);
   }
 
   // See if we can find a different reader that can pick up where we left off.
-  if (SwitchVideoSource(mLastVideoTime) == SOURCE_NEW) {
+  if (SwitchVideoSource(&mLastVideoTime) == SOURCE_NEW) {
     mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mLastVideoTime), 0)
                            ->RefableThen(GetTaskQueue(), __func__, this,
                                          &MediaSourceReader::CompleteVideoSeekAndDoRequest,
                                          &MediaSourceReader::CompleteVideoSeekAndRejectPromise));
     return;
   }
 
   CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
@@ -462,64 +462,90 @@ MediaSourceReader::HaveData(int64_t aTar
 {
   TrackBuffer* trackBuffer = aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
   MOZ_ASSERT(trackBuffer);
   nsRefPtr<SourceBufferDecoder> decoder = SelectDecoder(aTarget, EOS_FUZZ_US, trackBuffer->Decoders());
   return !!decoder;
 }
 
 MediaSourceReader::SwitchSourceResult
-MediaSourceReader::SwitchAudioSource(int64_t aTarget)
+MediaSourceReader::SwitchAudioSource(int64_t* aTarget)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding an audio track after ReadMetadata.
   if (!mAudioTrack) {
     return SOURCE_ERROR;
   }
 
   // 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());
+    SelectDecoder(*aTarget, /* aTolerance = */ 0, mAudioTrack->Decoders());
   if (!newDecoder) {
-    newDecoder = SelectDecoder(aTarget, EOS_FUZZ_US, mAudioTrack->Decoders());
+    newDecoder = SelectDecoder(*aTarget, EOS_FUZZ_US, mAudioTrack->Decoders());
+    usedFuzz = true;
   }
   if (newDecoder && newDecoder != mAudioSourceDecoder) {
     GetAudioReader()->SetIdle();
     mAudioSourceDecoder = newDecoder;
-    MSE_DEBUGV("MediaSourceReader(%p)::SwitchAudioSource switched decoder to %p",
-               this, mAudioSourceDecoder.get());
+    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("MediaSourceReader(%p)::SwitchAudioSource switched decoder to %p (fuzz:%d)",
+               this, mAudioSourceDecoder.get(), usedFuzz);
     return SOURCE_NEW;
   }
   return newDecoder ? SOURCE_EXISTING : SOURCE_ERROR;
 }
 
 MediaSourceReader::SwitchSourceResult
-MediaSourceReader::SwitchVideoSource(int64_t aTarget)
+MediaSourceReader::SwitchVideoSource(int64_t* aTarget)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   // XXX: Can't handle adding a video track after ReadMetadata.
   if (!mVideoTrack) {
     return SOURCE_ERROR;
   }
 
   // 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());
+    SelectDecoder(*aTarget, /* aTolerance = */ 0, mVideoTrack->Decoders());
   if (!newDecoder) {
-    newDecoder = SelectDecoder(aTarget, EOS_FUZZ_US, mVideoTrack->Decoders());
+    newDecoder = SelectDecoder(*aTarget, EOS_FUZZ_US, mVideoTrack->Decoders());
+    usedFuzz = true;
   }
   if (newDecoder && newDecoder != mVideoSourceDecoder) {
     GetVideoReader()->SetIdle();
     mVideoSourceDecoder = newDecoder;
-    MSE_DEBUGV("MediaSourceReader(%p)::SwitchVideoSource switched decoder to %p",
-               this, mVideoSourceDecoder.get());
+    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("MediaSourceReader(%p)::SwitchVideoSource switched decoder to %p (fuzz:%d)",
+               this, mVideoSourceDecoder.get(), usedFuzz);
     return SOURCE_NEW;
   }
   return newDecoder ? SOURCE_EXISTING : SOURCE_ERROR;
 }
 
 bool
 MediaSourceReader::IsDormantNeeded()
 {
@@ -752,17 +778,17 @@ MediaSourceReader::OnVideoSeekFailed(nsr
   mVideoSeekRequest.Complete();
   mPendingSeekTime = -1;
   mSeekPromise.Reject(aResult, __func__);
 }
 
 void
 MediaSourceReader::DoAudioSeek()
 {
-  SwitchAudioSource(mPendingSeekTime);
+  SwitchAudioSource(&mPendingSeekTime);
   mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mPendingSeekTime), 0)
                          ->RefableThen(GetTaskQueue(), __func__, this,
                                        &MediaSourceReader::OnAudioSeekCompleted,
                                        &MediaSourceReader::OnAudioSeekFailed));
   MSE_DEBUG("MediaSourceReader(%p)::DoAudioSeek reader=%p", this, GetAudioReader());
 }
 
 void
@@ -812,17 +838,17 @@ MediaSourceReader::AttemptSeek()
   } else {
     MOZ_CRASH();
   }
 }
 
 void
 MediaSourceReader::DoVideoSeek()
 {
-  SwitchVideoSource(mPendingSeekTime);
+  SwitchVideoSource(&mPendingSeekTime);
   mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mPendingSeekTime), 0)
                           ->RefableThen(GetTaskQueue(), __func__, this,
                                         &MediaSourceReader::OnVideoSeekCompleted,
                                         &MediaSourceReader::OnVideoSeekFailed));
   MSE_DEBUG("MediaSourceReader(%p)::DoVideoSeek reader=%p", this, GetVideoReader());
 }
 
 nsresult
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -152,24 +152,26 @@ public:
   // Returns a string describing the state of the MediaSource internal
   // buffered data. Used for debugging purposes.
   void GetMozDebugReaderData(nsAString& aString);
 
 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_EXISTING = 0,
     SOURCE_NEW = 1,
   };
 
-  SwitchSourceResult SwitchAudioSource(int64_t aTarget);
-  SwitchSourceResult SwitchVideoSource(int64_t aTarget);
+  SwitchSourceResult SwitchAudioSource(int64_t* aTarget);
+  SwitchSourceResult SwitchVideoSource(int64_t* aTarget);
 
   void DoAudioRequest();
   void DoVideoRequest();
 
   void CompleteAudioSeekAndDoRequest()
   {
     mAudioSeekRequest.Complete();
     DoAudioRequest();