Bug 1144617: Part2. Allow seek to end of mediasource.duration. r=mattwoodrow
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 23 Mar 2015 21:08:05 +1100
changeset 263891 6604e8d39fc671b500736ef8c6a891e1a1e70d3a
parent 263890 5a679809898571a7bdbaeeb278fd4f75a259fe3b
child 263892 1fadcc2735db6a4791f5dbba144fb864523308ec
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1144617
milestone39.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 1144617: Part2. Allow seek to end of mediasource.duration. r=mattwoodrow When seeking to the end of a mediasource media data, we will instead seek to the last audio and video sample. The MediaDecoderStateMachine will then request more audio or video data that will make it hit End Of Stream and complete the seek.
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/MediaSourceReader.h
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -44,16 +44,17 @@ using mozilla::dom::TimeRanges;
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mLastAudioTime(0)
   , mLastVideoTime(0)
   , mPendingSeekTime(-1)
   , mWaitingForSeekData(false)
+  , mSeekToEnd(false)
   , mTimeThreshold(0)
   , mDropAudioBeforeThreshold(false)
   , mDropVideoBeforeThreshold(false)
   , mAudioDiscontinuity(false)
   , mVideoDiscontinuity(false)
   , mEnded(false)
   , mMediaSourceDuration(0)
   , mHasEssentialTrackBuffers(false)
@@ -883,24 +884,28 @@ MediaSourceReader::OnVideoSeekFailed(nsr
   mVideoSeekRequest.Complete();
   mPendingSeekTime = -1;
   mSeekPromise.Reject(aResult, __func__);
 }
 
 void
 MediaSourceReader::DoAudioSeek()
 {
-  if (SwitchAudioSource(&mPendingSeekTime) == SOURCE_NONE) {
+  int64_t seekTime = mPendingSeekTime;
+  if (mSeekToEnd) {
+    seekTime = LastSampleTime(MediaData::AUDIO_DATA);
+  }
+  if (SwitchAudioSource(&seekTime) == SOURCE_NONE) {
     // Data we need got evicted since the last time we checked for data
     // availability. Abort current seek attempt.
     mWaitingForSeekData = true;
     return;
   }
   GetAudioReader()->ResetDecode();
-  mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mPendingSeekTime), 0)
+  mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(seekTime), 0)
                          ->RefableThen(GetTaskQueue(), __func__, this,
                                        &MediaSourceReader::OnAudioSeekCompleted,
                                        &MediaSourceReader::OnAudioSeekFailed));
   MSE_DEBUG("reader=%p", GetAudioReader());
 }
 
 void
 MediaSourceReader::OnAudioSeekCompleted(int64_t aTime)
@@ -925,17 +930,19 @@ MediaSourceReader::AttemptSeek()
 {
   // Make sure we don't hold the monitor while calling into the reader
   // Seek methods since it can deadlock.
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     if (!mWaitingForSeekData) {
       return;
     }
-    if (!TrackBuffersContainTime(mPendingSeekTime)) {
+
+    mSeekToEnd = IsEnded() && mPendingSeekTime >= mMediaSourceDuration * USECS_PER_S;
+    if (!mSeekToEnd && !TrackBuffersContainTime(mPendingSeekTime)) {
       mVideoSourceDecoder = nullptr;
       mAudioSourceDecoder = nullptr;
       return;
     }
     mWaitingForSeekData = false;
   }
 
   // Decoding discontinuity upon seek, reset last times to seek target.
@@ -949,24 +956,28 @@ MediaSourceReader::AttemptSeek()
   } else {
     MOZ_CRASH();
   }
 }
 
 void
 MediaSourceReader::DoVideoSeek()
 {
-  if (SwitchVideoSource(&mPendingSeekTime) == SOURCE_NONE) {
+  int64_t seekTime = mPendingSeekTime;
+  if (mSeekToEnd) {
+    seekTime = LastSampleTime(MediaData::VIDEO_DATA);
+  }
+  if (SwitchVideoSource(&seekTime) == SOURCE_NONE) {
     // Data we need got evicted since the last time we checked for data
     // availability. Abort current seek attempt.
     mWaitingForSeekData = true;
     return;
   }
   GetVideoReader()->ResetDecode();
-  mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mPendingSeekTime), 0)
+  mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(seekTime), 0)
                           ->RefableThen(GetTaskQueue(), __func__, this,
                                         &MediaSourceReader::OnVideoSeekCompleted,
                                         &MediaSourceReader::OnVideoSeekFailed));
   MSE_DEBUG("reader=%p", GetVideoReader());
 }
 
 nsresult
 MediaSourceReader::GetBuffered(dom::TimeRanges* aBuffered)
@@ -1160,16 +1171,28 @@ MediaSourceReader::IsNearEnd(MediaData::
   }
   TrackBuffer* trackBuffer =
     aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
   nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
   trackBuffer->Buffered(buffered);
   return aTime >= (buffered->GetEndTime() * USECS_PER_S - EOS_FUZZ_US);
 }
 
+int64_t
+MediaSourceReader::LastSampleTime(MediaData::Type aType)
+{
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+
+  TrackBuffer* trackBuffer =
+  aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
+  nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
+  trackBuffer->Buffered(buffered);
+  return buffered->GetEndTime() * USECS_PER_S - 1;
+}
+
 void
 MediaSourceReader::SetMediaSourceDuration(double aDuration)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mMediaSourceDuration = aDuration;
 }
 
 void
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -223,16 +223,17 @@ private:
                                                       int64_t aTolerance /* microseconds */,
                                                       const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
   bool HaveData(int64_t aTarget, MediaData::Type aType);
 
   void AttemptSeek();
   bool IsSeeking() { return mPendingSeekTime != -1; }
 
   bool IsNearEnd(MediaData::Type aType, int64_t aTime /* microseconds */);
+  int64_t LastSampleTime(MediaData::Type aType);
 
   nsRefPtr<SourceBufferDecoder> mAudioSourceDecoder;
   nsRefPtr<SourceBufferDecoder> mVideoSourceDecoder;
 
   nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
   nsRefPtr<TrackBuffer> mAudioTrack;
@@ -262,16 +263,17 @@ private:
   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.
   int64_t mPendingSeekTime;
   bool mWaitingForSeekData;
+  bool mSeekToEnd;
 
   int64_t mTimeThreshold;
   bool mDropAudioBeforeThreshold;
   bool mDropVideoBeforeThreshold;
 
   bool mAudioDiscontinuity;
   bool mVideoDiscontinuity;