Bug 1297037: [MSE] Update Duration Change algorithm as per latest spec. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 26 Aug 2016 16:39:36 +1200
changeset 406609 202aa7032c019c329bc4ea3bea8cc7290c84af8c
parent 406450 1a5b53a831e5a6c20de1b081c774feb3ff76756c
child 406610 817a6d1d3368ce8f44161cb839e476854ed62928
push id27776
push userbmo:jyavenard@mozilla.com
push dateMon, 29 Aug 2016 07:12:53 +0000
reviewersgerald
bugs1297037
milestone51.0a1
Bug 1297037: [MSE] Update Duration Change algorithm as per latest spec. r?gerald The MSE spec was recently updated to use the highest end time across tracks rather than across the buffered ranges. See https://github.com/w3c/media-source/issues/124 and the fix described in https://github.com/w3c/media-source/pull/154 MozReview-Commit-ID: 4CqI8d2e9gu
dom/media/mediasource/MediaSource.cpp
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBuffer.h
dom/media/mediasource/SourceBufferList.cpp
dom/media/mediasource/SourceBufferList.h
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -531,26 +531,23 @@ MediaSource::DurationChange(double aNewD
   // 2. If new duration is less than the highest starting presentation timestamp
   // of any buffered coded frames for all SourceBuffer objects in sourceBuffers,
   // then throw an InvalidStateError exception and abort these steps.
   if (aNewDuration < mSourceBuffers->HighestStartTime()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  // 3. Update duration to new duration.
-  // 4. If a user agent is unable to partially render audio frames or text cues
-  // that start before and end after the duration, then run the following steps:
-  // Update new duration to the highest end time reported by the buffered
-  // attribute across all SourceBuffer objects in sourceBuffers.
-  //   1. Update new duration to the highest end time reported by the buffered
-  //      attribute across all SourceBuffer objects in sourceBuffers.
-  //   2. Update duration to new duration.
+  // 3. Let highest end time be the largest track buffer ranges end time across
+  // all the track buffers across all SourceBuffer objects in sourceBuffers.
+  double highestEndTime = mSourceBuffers->HighestEndTime();
+  // 4. If new duration is less than highest end time, then
+  //    4.1 Update new duration to equal highest end time.
   aNewDuration =
-    std::max(aNewDuration, mSourceBuffers->GetHighestBufferedEndTime());
+    std::max(aNewDuration, highestEndTime);
 
   // 5. Update the media duration to new duration and run the HTMLMediaElement
   // duration change algorithm.
   mDecoder->SetMediaSourceDuration(aNewDuration);
 }
 
 void
 MediaSource::GetMozDebugReaderData(nsAString& aString)
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -549,16 +549,25 @@ double
 SourceBuffer::HighestStartTime()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mTrackBuffersManager
          ? mTrackBuffersManager->HighestStartTime().ToSeconds()
          : 0.0;
 }
 
+double
+SourceBuffer::HighestEndTime()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  return mTrackBuffersManager
+         ? mTrackBuffersManager->HighestEndTime().ToSeconds()
+         : 0.0;
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(SourceBuffer)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SourceBuffer)
   // Tell the TrackBuffer to end its current SourceBufferResource.
   TrackBuffersManager* manager = tmp->mTrackBuffersManager;
   if (manager) {
     manager->Detach();
   }
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -113,16 +113,17 @@ public:
     return mMediaSource != nullptr;
   }
 
   void Ended();
 
   double GetBufferedStart();
   double GetBufferedEnd();
   double HighestStartTime();
+  double HighestEndTime();
 
   // Runs the range removal algorithm as defined by the MSE spec.
   void RangeRemoval(double aStart, double aEnd);
 
   bool IsActive() const
   {
     return mActive;
   }
--- a/dom/media/mediasource/SourceBufferList.cpp
+++ b/dom/media/mediasource/SourceBufferList.cpp
@@ -186,16 +186,28 @@ SourceBufferList::HighestStartTime()
   double highestStartTime = 0;
   for (auto& sourceBuffer : mSourceBuffers) {
     highestStartTime =
       std::max(sourceBuffer->HighestStartTime(), highestStartTime);
   }
   return highestStartTime;
 }
 
+double
+SourceBufferList::HighestEndTime()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  double highestEndTime = 0;
+  for (auto& sourceBuffer : mSourceBuffers) {
+    highestEndTime =
+      std::max(sourceBuffer->HighestEndTime(), highestEndTime);
+  }
+  return highestEndTime;
+}
+
 JSObject*
 SourceBufferList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return SourceBufferListBinding::Wrap(aCx, this, aGivenProto);
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(SourceBufferList, DOMEventTargetHelper,
                                    mMediaSource, mSourceBuffers)
--- a/dom/media/mediasource/SourceBufferList.h
+++ b/dom/media/mediasource/SourceBufferList.h
@@ -81,16 +81,17 @@ public:
   // Append a SourceBuffer to the list. No event is fired.
   void AppendSimple(SourceBuffer* aSourceBuffer);
 
   // Remove all SourceBuffers from mSourceBuffers.
   //  No event is fired and no action is performed on the sourcebuffers.
   void ClearSimple();
 
   double HighestStartTime();
+  double HighestEndTime();
 
 private:
   ~SourceBufferList();
 
   friend class AsyncEventRunner<SourceBufferList>;
   void DispatchSimpleEvent(const char* aName);
   void QueueAsyncSimpleEvent(const char* aName);
 
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -295,31 +295,28 @@ TrackBuffersManager::EvictData(const Tim
 
   return EvictDataResult::NO_DATA_EVICTED;
 }
 
 TimeIntervals
 TrackBuffersManager::Buffered()
 {
   MSE_DEBUG("");
-  MonitorAutoLock mon(mMonitor);
   // http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
   // 2. Let highest end time be the largest track buffer ranges end time across all the track buffers managed by this SourceBuffer object.
-  TimeUnit highestEndTime;
+  TimeUnit highestEndTime = HighestEndTime();
 
+  MonitorAutoLock mon(mMonitor);
   nsTArray<TimeIntervals*> tracks;
   if (HasVideo()) {
     tracks.AppendElement(&mVideoBufferedRanges);
   }
   if (HasAudio()) {
     tracks.AppendElement(&mAudioBufferedRanges);
   }
-  for (auto trackRanges : tracks) {
-    highestEndTime = std::max(trackRanges->GetEnd(), highestEndTime);
-  }
 
   // 3. Let intersection ranges equal a TimeRange object containing a single range from 0 to highest end time.
   TimeIntervals intersection{TimeInterval(TimeUnit::FromSeconds(0), highestEndTime)};
 
   // 4. For each track buffer managed by this SourceBuffer, run the following steps:
   //   1. Let track ranges equal the track buffer ranges for the current track buffer.
   for (auto trackRanges : tracks) {
     // 2. If readyState is "ended", then set the end time on the last range in track ranges to highest end time.
@@ -1912,16 +1909,35 @@ TrackBuffersManager::HighestStartTime()
   TimeUnit highestStartTime;
   for (auto& track : GetTracksList()) {
     highestStartTime =
       std::max(track->mHighestStartTimestamp, highestStartTime);
   }
   return highestStartTime;
 }
 
+TimeUnit
+TrackBuffersManager::HighestEndTime()
+{
+  MonitorAutoLock mon(mMonitor);
+  TimeUnit highestEndTime;
+
+  nsTArray<TimeIntervals*> tracks;
+  if (HasVideo()) {
+    tracks.AppendElement(&mVideoBufferedRanges);
+  }
+  if (HasAudio()) {
+    tracks.AppendElement(&mAudioBufferedRanges);
+  }
+  for (auto trackRanges : tracks) {
+    highestEndTime = std::max(trackRanges->GetEnd(), highestEndTime);
+  }
+  return highestEndTime;
+}
+
 const TrackBuffersManager::TrackBuffer&
 TrackBuffersManager::GetTrackBuffer(TrackInfo::TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
   return GetTracksData(aTrack).mBuffers.LastElement();
 }
 
 uint32_t TrackBuffersManager::FindSampleIndex(const TrackBuffer& aTrackBuffer,
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -118,16 +118,17 @@ public:
   // and if still more space is needed remove from the end.
   EvictDataResult EvictData(const media::TimeUnit& aPlaybackTime, int64_t aSize);
 
   // Returns the buffered range currently managed.
   // This may be called on any thread.
   // Buffered must conform to http://w3c.github.io/media-source/index.html#widl-SourceBuffer-buffered
   media::TimeIntervals Buffered();
   media::TimeUnit HighestStartTime();
+  media::TimeUnit HighestEndTime();
 
   // Return the size of the data managed by this SourceBufferContentManager.
   int64_t GetSize() const;
 
   // Indicate that the MediaSource parent object got into "ended" state.
   void Ended();
 
   // The parent SourceBuffer is about to be destroyed.