Bug 1293646: [MSE] P2. Only reject a seek request with EOS if it's passed the explicit duration. r=gerald, a=ritu
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 10 Aug 2016 15:30:12 +1000
changeset 349783 da5b828c39ceb7dca3fa4e221e62970188599533
parent 349782 252ceee6fee8ee4d525df6707466911e6b6a5f76
child 349784 0fda1a94617401c79765aacf86020e610aaf29d7
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald, ritu
bugs1293646
milestone50.0a2
Bug 1293646: [MSE] P2. Only reject a seek request with EOS if it's passed the explicit duration. r=gerald, a=ritu With MSE, the actual duration is always exact as it is amended when data is added. We do not want to fire ended when we attempt to seek to unbuffered data once endOfStream has been called. Instead we will fire the waiting event. MozReview-Commit-ID: Cl2uBLk2qRQ
dom/media/AbstractMediaDecoder.h
dom/media/MediaDecoder.h
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- a/dom/media/AbstractMediaDecoder.h
+++ b/dom/media/AbstractMediaDecoder.h
@@ -56,16 +56,17 @@ public:
   virtual MediaResource* GetResource() const = 0;
 
   // Increments the parsed, decoded and dropped frame counters by the passed in
   // counts.
   // Can be called on any thread.
   virtual void NotifyDecodedFrames(const FrameStatisticsData& aStats) = 0;
 
   virtual AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() { return nullptr; };
+  virtual AbstractCanonical<Maybe<double>>* CanonicalExplicitDuration() { return nullptr; }
 
   // Return an event that will be notified when data arrives in MediaResource.
   // MediaDecoderReader will register with this event to receive notifications
   // in order to update buffer ranges.
   // Return null if this decoder doesn't support the event.
   virtual MediaEventSource<void>* DataArrivedEvent()
   {
     return nullptr;
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -823,31 +823,31 @@ protected:
   // True if the media is only seekable within its buffered ranges.
   Canonical<bool> mMediaSeekableOnlyInBufferedRanges;
 
   // True if the decoder is visible.
   Canonical<bool> mIsVisible;
 
 public:
   AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override;
+  AbstractCanonical<Maybe<double>>* CanonicalExplicitDuration() override {
+    return &mExplicitDuration;
+  }
   AbstractCanonical<double>* CanonicalVolume() {
     return &mVolume;
   }
   AbstractCanonical<double>* CanonicalPlaybackRate() {
     return &mPlaybackRate;
   }
   AbstractCanonical<bool>* CanonicalPreservesPitch() {
     return &mPreservesPitch;
   }
   AbstractCanonical<media::NullableTimeUnit>* CanonicalEstimatedDuration() {
     return &mEstimatedDuration;
   }
-  AbstractCanonical<Maybe<double>>* CanonicalExplicitDuration() {
-    return &mExplicitDuration;
-  }
   AbstractCanonical<PlayState>* CanonicalPlayState() {
     return &mPlayState;
   }
   AbstractCanonical<PlayState>* CanonicalNextPlayState() {
     return &mNextState;
   }
   AbstractCanonical<bool>* CanonicalLogicallySeeking() {
     return &mLogicallySeeking;
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -71,16 +71,17 @@ MediaFormatReader::MediaFormatReader(Abs
   , mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
   , mLayersBackendType(aLayersBackend)
   , mInitDone(false)
   , mIsEncrypted(false)
   , mTrackDemuxersMayBlock(false)
   , mDemuxOnly(false)
   , mSeekScheduled(false)
   , mVideoFrameContainer(aVideoFrameContainer)
+  , mExplicitDuration(mTaskQueue, Maybe<double>(), "MediaFormatReader::mExplicitDuration(Mirror)")
 {
   MOZ_ASSERT(aDemuxer);
   MOZ_COUNT_CTOR(MediaFormatReader);
 }
 
 MediaFormatReader::~MediaFormatReader()
 {
   MOZ_COUNT_DTOR(MediaFormatReader);
@@ -135,16 +136,18 @@ MediaFormatReader::Shutdown()
     mVideo.mTaskQueue = nullptr;
   }
   MOZ_ASSERT(!mVideo.HasPromise());
 
   mDemuxer = nullptr;
   mPlatform = nullptr;
   mVideoFrameContainer = nullptr;
 
+  mExplicitDuration.DisconnectIfConnected();
+
   return MediaDecoderReader::Shutdown();
 }
 
 void
 MediaFormatReader::InitLayersBackendType()
 {
   // Extract the layer manager backend type so that platform decoders
   // can determine whether it's worthwhile using hardware accelerated
@@ -247,16 +250,20 @@ MediaFormatReader::AsyncReadMetadata()
   if (mInitDone) {
     // We are returning from dormant.
     RefPtr<MetadataHolder> metadata = new MetadataHolder();
     metadata->mInfo = mInfo;
     metadata->mTags = nullptr;
     return MetadataPromise::CreateAndResolve(metadata, __func__);
   }
 
+  if (mDecoder->CanonicalExplicitDuration()) {
+    mExplicitDuration.Connect(mDecoder->CanonicalExplicitDuration());
+  }
+
   RefPtr<MetadataPromise> p = mMetadataPromise.Ensure(__func__);
 
   mDemuxerInitRequest.Begin(mDemuxer->Init()
                        ->Then(OwnerThread(), __func__, this,
                               &MediaFormatReader::OnDemuxerInitDone,
                               &MediaFormatReader::OnDemuxerInitFailed));
   return p;
 }
@@ -1061,16 +1068,30 @@ MediaFormatReader::InternalSeek(TrackTyp
                                  "Seek promise must be disconnected when timethreshold is reset");
                       decoder.mTimeThreshold.ref().mHasSeeked = true;
                       self->SetVideoDecodeThreshold();
                       self->NotifyDecodingRequested(aTrack);
                     },
                     [self, aTrack] (DemuxerFailureReason aResult) {
                       auto& decoder = self->GetDecoderData(aTrack);
                       decoder.mSeekRequest.Complete();
+
+                      if (aResult == DemuxerFailureReason::END_OF_STREAM) {
+                        // We want to enter EOS when performing an
+                        // internal seek only if we're attempting to seek past
+                        // the explicit duration to avoid unwanted ended
+                        // event to be fired.
+                        if (self->mExplicitDuration.Ref().isSome() &&
+                            decoder.mTimeThreshold.ref().Time() <
+                            TimeUnit::FromSeconds(
+                              self->mExplicitDuration.Ref().ref())) {
+                          aResult = DemuxerFailureReason::WAITING_FOR_DATA;
+                        }
+                      }
+
                       switch (aResult) {
                         case DemuxerFailureReason::WAITING_FOR_DATA:
                           self->NotifyWaitingForData(aTrack);
                           break;
                         case DemuxerFailureReason::END_OF_STREAM:
                           decoder.mTimeThreshold.reset();
                           self->NotifyEndOfStream(aTrack);
                           break;
@@ -1710,16 +1731,24 @@ MediaFormatReader::OnSeekFailed(TrackTyp
   MOZ_ASSERT(OnTaskQueue());
   LOGV("%s failure:%d", TrackTypeToStr(aTrack), aResult);
   if (aTrack == TrackType::kVideoTrack) {
     mVideo.mSeekRequest.Complete();
   } else {
     mAudio.mSeekRequest.Complete();
   }
 
+  // We want to enter EOS when performing a seek only if we're attempting to
+  // seek past the explicit duration to avoid unwanted ended
+  // event to be fired.
+  if (mExplicitDuration.Ref().isSome() &&
+      mPendingSeekTime.ref() < TimeUnit::FromSeconds(mExplicitDuration.Ref().ref())) {
+    aResult = DemuxerFailureReason::WAITING_FOR_DATA;
+  }
+
   if (aResult == DemuxerFailureReason::WAITING_FOR_DATA) {
     if (HasVideo() && aTrack == TrackType::kAudioTrack &&
         mFallbackSeekTime.isSome() &&
         mPendingSeekTime.ref() != mFallbackSeekTime.ref()) {
       // We have failed to seek audio where video seeked to earlier.
       // Attempt to seek instead to the closest point that we know we have in
       // order to limit A/V sync discrepency.
 
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -4,18 +4,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(MediaFormatReader_h_)
 #define MediaFormatReader_h_
 
 #include "mozilla/Atomics.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/StateMirroring.h"
 #include "mozilla/TaskQueue.h"
-#include "mozilla/Monitor.h"
 
 #include "MediaDataDemuxer.h"
 #include "MediaDecoderReader.h"
 #include "nsAutoPtr.h"
 #include "PDMFactory.h"
 
 namespace mozilla {
 
@@ -566,13 +567,16 @@ private:
 
   RefPtr<VideoFrameContainer> mVideoFrameContainer;
   layers::ImageContainer* GetImageContainer();
 
 #ifdef MOZ_EME
   RefPtr<CDMProxy> mCDMProxy;
 #endif
   RefPtr<GMPCrashHelper> mCrashHelper;
+
+  // The duration explicitly set by JS, mirrored from the main thread.
+  Mirror<Maybe<double>> mExplicitDuration;
 };
 
 } // namespace mozilla
 
 #endif