Bug 1128397: Work around EOS detection in MSE. r=mattwoodrow
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 02 Mar 2015 10:47:54 +1100
changeset 249538 afa562ac56af6b8ff132e8b3846181f03e954e6f
parent 249537 c12d73654aa7ea7b752e7b799aad7178d14f584c
child 249539 c6e173b28ecae3617d303bf2218253d3e20f54ac
push id7860
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:46:02 +0000
treeherdermozilla-aurora@8ac636cd51f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1128397
milestone39.0a1
Bug 1128397: Work around EOS detection in MSE. r=mattwoodrow This attempts to handle video and audio sourcebuffer not having exactly the same duration, so the ended event is properly fired.
dom/media/mediasource/MediaSourceReader.cpp
dom/media/mediasource/MediaSourceReader.h
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -34,16 +34,22 @@ 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)
@@ -375,17 +381,17 @@ MediaSourceReader::OnVideoNotDecoded(Not
 
   CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
 }
 
 void
 MediaSourceReader::CheckForWaitOrEndOfStream(MediaData::Type aType, int64_t aTime)
 {
   // If the entire MediaSource is done, generate an EndOfStream.
-  if (IsNearEnd(aTime)) {
+  if (IsNearEnd(aType, aTime)) {
     if (aType == MediaData::AUDIO_DATA) {
       mAudioPromise.Reject(END_OF_STREAM, __func__);
     } else {
       mVideoPromise.Reject(END_OF_STREAM, __func__);
     }
     return;
   }
 
@@ -1042,20 +1048,37 @@ MediaSourceReader::Ended()
 bool
 MediaSourceReader::IsEnded()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   return mEnded;
 }
 
 bool
-MediaSourceReader::IsNearEnd(int64_t aTime)
+MediaSourceReader::IsNearEnd(MediaData::Type aType, int64_t aTime)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  return mEnded && aTime >= (mMediaSourceDuration * USECS_PER_S - EOS_FUZZ_US);
+  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;
 }
 
 void
 MediaSourceReader::SetMediaSourceDuration(double aDuration)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mMediaSourceDuration = aDuration;
 }
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -127,17 +127,17 @@ public:
   // 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
   bool IsEnded();
-  bool IsNearEnd(int64_t aTime /* microseconds */);
+  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