Bug 654787 - part4: Keep decoding to MDSM in ReaderProxy when looping is on; r=jwwang draft
authorChun-Min Chang <chun.m.chang@gmail.com>
Wed, 22 Nov 2017 11:17:09 +0800
changeset 702944 844fe51cb6add26233c19cd2bb8f0954b177f154
parent 700495 7626916ad223574ea757a9c87d6e31950e07ef8f
child 702945 dd1ef89167825da69369a1c9c8d90241c00304aa
push id90643
push userbmo:cchang@mozilla.com
push dateFri, 24 Nov 2017 02:29:17 +0000
reviewersjwwang
bugs654787
milestone59.0a1
Bug 654787 - part4: Keep decoding to MDSM in ReaderProxy when looping is on; r=jwwang MozReview-Commit-ID: 4oVaUmDUeFJ
dom/media/ReaderProxy.cpp
dom/media/ReaderProxy.h
--- a/dom/media/ReaderProxy.cpp
+++ b/dom/media/ReaderProxy.cpp
@@ -14,16 +14,17 @@ namespace mozilla {
 ReaderProxy::ReaderProxy(AbstractThread* aOwnerThread,
                          MediaFormatReader* aReader)
   : mOwnerThread(aOwnerThread)
   , mReader(aReader)
   , mWatchManager(this, aReader->OwnerThread())
   , mDuration(aReader->OwnerThread(),
               media::NullableTimeUnit(),
               "ReaderProxy::mDuration (Mirror)")
+  , mSeamlessLoopingBlocked(false)
   , mSeamlessLoopingEnabled(false)
 {
   // Must support either heuristic buffering or WaitForData().
   MOZ_ASSERT(mReader->UseBufferingHeuristics() ||
              mReader->IsWaitForDataSupported());
 }
 
 ReaderProxy::~ReaderProxy()
@@ -62,25 +63,52 @@ ReaderProxy::OnAudioDataRequestCompleted
   return AudioDataPromise::CreateAndResolve(aAudio.forget(), __func__);
 }
 
 RefPtr<ReaderProxy::AudioDataPromise>
 ReaderProxy::OnAudioDataRequestFailed(const MediaResult& aError)
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
 
-  return AudioDataPromise::CreateAndReject(aError, __func__);
+  if (mSeamlessLoopingBlocked || !mSeamlessLoopingEnabled ||
+      aError.Code() != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
+    return AudioDataPromise::CreateAndReject(aError, __func__);
+  }
+
+  // For seamless looping, the demuxer is sought to the beginning and then
+  // keep requesting decoded data in advance, upon receiving EOS.
+  // The MDSM will not be aware of the EOS and keep receiving decoded data
+  // as usual while looping is on.
+  RefPtr<ReaderProxy> self = this;
+  RefPtr<MediaFormatReader> reader = mReader;
+  ResetDecode(TrackInfo::kAudioTrack);
+  return Seek(SeekTarget(media::TimeUnit::Zero(), SeekTarget::Accurate))
+    ->Then(mReader->OwnerThread(),
+           __func__,
+           [reader]() { return reader->RequestAudioData(); },
+           [](const SeekRejectValue& aReject) {
+             return AudioDataPromise::CreateAndReject(aReject.mError, __func__);
+           })
+    ->Then(mOwnerThread,
+           __func__,
+           [self](RefPtr<AudioData> aAudio) {
+             return self->OnAudioDataRequestCompleted(aAudio.forget());
+           },
+           [](const MediaResult& aError) {
+             return AudioDataPromise::CreateAndReject(aError, __func__);
+           });
 }
 
 RefPtr<ReaderProxy::AudioDataPromise>
 ReaderProxy::RequestAudioData()
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   MOZ_ASSERT(!mShutdown);
 
+  mSeamlessLoopingBlocked = false;
   return InvokeAsync(mReader->OwnerThread(),
                      mReader.get(),
                      __func__,
                      &MediaFormatReader::RequestAudioData)
     ->Then(mOwnerThread,
            __func__,
            this,
            &ReaderProxy::OnAudioDataRequestCompleted,
@@ -88,16 +116,17 @@ ReaderProxy::RequestAudioData()
 }
 
 RefPtr<ReaderProxy::VideoDataPromise>
 ReaderProxy::RequestVideoData(const media::TimeUnit& aTimeThreshold)
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
   MOZ_ASSERT(!mShutdown);
 
+  mSeamlessLoopingBlocked = false;
   const auto threshold = aTimeThreshold > media::TimeUnit::Zero()
                          ? aTimeThreshold + StartTime()
                          : aTimeThreshold;
 
   int64_t startTime = StartTime().ToMicroseconds();
   return InvokeAsync(mReader->OwnerThread(),
                      mReader.get(),
                      __func__,
@@ -114,16 +143,17 @@ ReaderProxy::RequestVideoData(const medi
              return VideoDataPromise::CreateAndReject(aError, __func__);
            });
 }
 
 RefPtr<ReaderProxy::SeekPromise>
 ReaderProxy::Seek(const SeekTarget& aTarget)
 {
   MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
+  mSeamlessLoopingBlocked = true;
   SeekTarget adjustedTarget = aTarget;
   adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
   return InvokeAsync(mReader->OwnerThread(),
                      mReader.get(),
                      __func__,
                      &MediaFormatReader::Seek,
                      Move(adjustedTarget));
 }
--- a/dom/media/ReaderProxy.h
+++ b/dom/media/ReaderProxy.h
@@ -104,15 +104,17 @@ private:
   Maybe<media::TimeUnit> mStartTime;
 
   // State-watching manager.
   WatchManager<ReaderProxy> mWatchManager;
 
   // Duration, mirrored from the state machine task queue.
   Mirror<media::NullableTimeUnit> mDuration;
 
+  // To prevent seamless looping while seeking.
+  bool mSeamlessLoopingBlocked;
   // Indicates whether we should loop the media.
   bool mSeamlessLoopingEnabled;
 };
 
 } // namespace mozilla
 
 #endif // ReaderProxy_h_