Bug 1141333: Mark reader has ended when EndOfStream explicit. r=mattwoodrow a=sledru
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 23 Mar 2015 21:08:05 +1100
changeset 257999 dcc5ad62d9b263302e4ca9205b87f1ad2e6f60d3
parent 257998 d543a39ac7b26a2846c21cf7353c162f5900c6ec
child 258000 c29c4393b55e101a513be112bcc6480845601cd0
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, sledru
bugs1141333
milestone38.0a2
Bug 1141333: Mark reader has ended when EndOfStream explicit. r=mattwoodrow a=sledru
dom/media/mediasource/MediaSource.cpp
dom/media/mediasource/MediaSourceDecoder.cpp
dom/media/mediasource/MediaSourceDecoder.h
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/MediaSourceReader.h
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -276,25 +276,24 @@ MediaSource::EndOfStream(const Optional<
   if (mReadyState != MediaSourceReadyState::Open ||
       mSourceBuffers->AnyUpdating()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   SetReadyState(MediaSourceReadyState::Ended);
   mSourceBuffers->Ended();
-  mDecoder->Ended();
   if (!aError.WasPassed()) {
     mDecoder->SetMediaSourceDuration(mSourceBuffers->GetHighestBufferedEndTime(),
                                      MSRangeRemovalAction::SKIP);
     if (aRv.Failed()) {
       return;
     }
-    // TODO:
-    //   Notify media element that all data is now available.
+    // Notify reader that all data is now available.
+    mDecoder->Ended(true);
     return;
   }
   switch (aError.Value()) {
   case MediaSourceEndOfStreamError::Network:
     // TODO: If media element has a readyState of:
     //   HAVE_NOTHING -> run resource fetch algorithm
     // > HAVE_NOTHING -> run "interrupted" steps of resource fetch
     break;
@@ -435,16 +434,20 @@ MediaSource::SetReadyState(MediaSourceRe
 
   MediaSourceReadyState oldState = mReadyState;
   mReadyState = aState;
 
   if (mReadyState == MediaSourceReadyState::Open &&
       (oldState == MediaSourceReadyState::Closed ||
        oldState == MediaSourceReadyState::Ended)) {
     QueueAsyncSimpleEvent("sourceopen");
+    if (oldState == MediaSourceReadyState::Ended) {
+      // Notify reader that more data may come.
+      mDecoder->Ended(false);
+    }
     return;
   }
 
   if (mReadyState == MediaSourceReadyState::Ended &&
       oldState == MediaSourceReadyState::Open) {
     QueueAsyncSimpleEvent("sourceended");
     return;
   }
--- a/dom/media/mediasource/MediaSourceDecoder.cpp
+++ b/dom/media/mediasource/MediaSourceDecoder.cpp
@@ -151,20 +151,20 @@ MediaSourceDecoder::RemoveTrackBuffer(Tr
 void
 MediaSourceDecoder::OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo)
 {
   MOZ_ASSERT(mReader);
   mReader->OnTrackBufferConfigured(aTrackBuffer, aInfo);
 }
 
 void
-MediaSourceDecoder::Ended()
+MediaSourceDecoder::Ended(bool aEnded)
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
-  mReader->Ended();
+  mReader->Ended(aEnded);
   mon.NotifyAll();
 }
 
 bool
 MediaSourceDecoder::IsExpectingMoreData()
 {
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   return !mReader->IsEnded();
--- a/dom/media/mediasource/MediaSourceDecoder.h
+++ b/dom/media/mediasource/MediaSourceDecoder.h
@@ -48,17 +48,17 @@ public:
   void DetachMediaSource();
 
   already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType,
                                                          int64_t aTimestampOffset /* microseconds */);
   void AddTrackBuffer(TrackBuffer* aTrackBuffer);
   void RemoveTrackBuffer(TrackBuffer* aTrackBuffer);
   void OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo);
 
-  void Ended();
+  void Ended(bool aEnded);
   bool IsExpectingMoreData() override;
 
   // Return the duration of the video in seconds.
   virtual double GetDuration() override;
 
   void SetInitialDuration(int64_t aDuration);
   void SetMediaSourceDuration(double aDuration, MSRangeRemovalAction aAction);
   double GetMediaSourceDuration();
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -34,22 +34,16 @@ extern PRLogModuleInfo* GetMediaSourceLo
 
 // When a stream hits EOS it needs to decide what other stream to switch to. Due
 // to inaccuracies is determining buffer end frames (Bug 1065207) and rounding
 // issues we use a fuzz factor to determine the end time of this stream for
 // switching to the new stream. This value is based on the end of frame
 // default value used in Blink, kDefaultBufferDurationInMs.
 #define EOS_FUZZ_US 125000
 
-// Audio and video source buffers often have a slight duration
-// discrepency. We want to handle the case where a source buffer is smaller than
-// another by more than EOS_FUZZ_US so we can properly detect EOS in IsNearEnd().
-// This value was chosen at random, to cater for most streams seen in the wild.
-#define DURATION_DIFFERENCE_FUZZ 300000
-
 using mozilla::dom::TimeRanges;
 
 namespace mozilla {
 
 MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
   : MediaDecoderReader(aDecoder)
   , mLastAudioTime(0)
   , mLastVideoTime(0)
@@ -1043,51 +1037,41 @@ MediaSourceReader::ReadUpdatedMetadata(M
     const MediaInfo& info = GetVideoReader()->GetMediaInfo();
     MOZ_ASSERT(info.HasVideo());
     mInfo.mVideo = info.mVideo;
   }
   *aInfo = mInfo;
 }
 
 void
-MediaSourceReader::Ended()
+MediaSourceReader::Ended(bool aEnded)
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
-  mEnded = true;
+  mEnded = aEnded;
 }
 
 bool
 MediaSourceReader::IsEnded()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   return mEnded;
 }
 
 bool
 MediaSourceReader::IsNearEnd(MediaData::Type aType, int64_t aTime)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   if (!mEnded) {
     return false;
   }
-  if (aTime >= (mMediaSourceDuration * USECS_PER_S - EOS_FUZZ_US)) {
-    return true;
-  }
-  // We may have discrepencies between the mediasource duration and the
-  // sourcebuffer end time (mMediaSourceDuration == max(audio.EndTime, video.EndTime)
-  // If the sourcebuffer duration is close enough to the mediasource duration,
-  // then use it instead to determine if we're near the end.
   TrackBuffer* trackBuffer =
     aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
   nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
   trackBuffer->Buffered(buffered);
-  if ((mMediaSourceDuration - buffered->GetEndTime()) * USECS_PER_S <= DURATION_DIFFERENCE_FUZZ) {
-    return aTime >= std::floor(buffered->GetEndTime() * USECS_PER_S);
-  }
-  return false;
+  return aTime >= (buffered->GetEndTime() * USECS_PER_S - EOS_FUZZ_US);
 }
 
 void
 MediaSourceReader::SetMediaSourceDuration(double aDuration)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mMediaSourceDuration = aDuration;
 }
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -129,21 +129,21 @@ public:
     ReentrantMonitorAutoEnter decoderMon(mDecoder->GetReentrantMonitor());
     return mDecoder->IsShutdown();
   }
 
   // Return true if all of the active tracks contain data for the specified time.
   bool TrackBuffersContainTime(int64_t aTime);
 
   // Mark the reader to indicate that EndOfStream has been called on our MediaSource
-  void Ended();
-
-  // Return true if the Ended method has been called
+  // and that the media element has all the media data.
+  // If called with true, the reader will come out of ended mode.
+  void Ended(bool aEnded);
+  // Return true if reader has all of the media data.
   bool IsEnded();
-  bool IsNearEnd(MediaData::Type aType, int64_t aTime /* microseconds */);
 
   // Set the duration of the attached mediasource element.
   void SetMediaSourceDuration(double aDuration /* seconds */);
 
 #ifdef MOZ_EME
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
@@ -215,16 +215,18 @@ private:
   already_AddRefed<SourceBufferDecoder> SelectDecoder(int64_t aTarget /* microseconds */,
                                                       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 */);
+
   nsRefPtr<SourceBufferDecoder> mAudioSourceDecoder;
   nsRefPtr<SourceBufferDecoder> mVideoSourceDecoder;
 
   nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mShutdownTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
   nsRefPtr<TrackBuffer> mAudioTrack;
   nsRefPtr<TrackBuffer> mVideoTrack;