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 260109 afa562ac56af6b8ff132e8b3846181f03e954e6f
parent 260108 c12d73654aa7ea7b752e7b799aad7178d14f584c
child 260110 c6e173b28ecae3617d303bf2218253d3e20f54ac
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1128397
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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