Bug 1297036: [MSE] P4. Only report end of stream when reaching the end. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Sun, 28 Aug 2016 01:00:39 +1200
changeset 406637 ab629be2f396296c8295935964e4a84fe941d30c
parent 406636 20162730737c9918b6595403be9231057a4cc865
child 406638 b96f8193fe83c2520d6b9ce6181f0a389213a64e
push id27783
push userbmo:jyavenard@mozilla.com
push dateMon, 29 Aug 2016 07:55:20 +0000
reviewersgerald
bugs1297036
milestone51.0a1
Bug 1297036: [MSE] P4. Only report end of stream when reaching the end. r?gerald MozReview-Commit-ID: 5EWhBVnscXY
dom/media/mediasource/MediaSourceDemuxer.cpp
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/MediaSourceDemuxer.cpp
+++ b/dom/media/mediasource/MediaSourceDemuxer.cpp
@@ -374,92 +374,99 @@ MediaSourceTrackDemuxer::BreakCycles()
       self->mManager = nullptr;
     } );
   mParent->GetTaskQueue()->Dispatch(task.forget());
 }
 
 RefPtr<MediaSourceTrackDemuxer::SeekPromise>
 MediaSourceTrackDemuxer::DoSeek(media::TimeUnit aTime)
 {
+  typedef TrackBuffersManager::GetSampleResult Result;
+
   TimeIntervals buffered = mManager->Buffered(mType);
   // Fuzz factor represents a +/- threshold. So when seeking it allows the gap
   // to be twice as big as the fuzz value. We only want to allow EOS_FUZZ gap.
   buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
   TimeUnit seekTime = std::max(aTime - mPreRoll, TimeUnit::FromMicroseconds(0));
 
   if (mManager->IsEnded() && seekTime >= buffered.GetEnd()) {
     // We're attempting to seek past the end time. Cap seekTime so that we seek
     // to the last sample instead.
     seekTime =
       std::max(mManager->HighestStartTime(mType) - mPreRoll,
                TimeUnit::FromMicroseconds(0));
   }
   if (!buffered.Contains(seekTime)) {
     if (!buffered.Contains(aTime)) {
       // We don't have the data to seek to.
-      return SeekPromise::CreateAndReject(
-        mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM :
-                              DemuxerFailureReason::WAITING_FOR_DATA, __func__);
+      return SeekPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA,
+                                          __func__);
     }
     // Theoretically we should reject the promise with WAITING_FOR_DATA,
     // however, to avoid unwanted regressions we assume that if at this time
     // we don't have the wanted data it won't come later.
     // Instead of using the pre-rolled time, use the earliest time available in
     // the interval.
     TimeIntervals::IndexType index = buffered.Find(aTime);
     MOZ_ASSERT(index != TimeIntervals::NoIndex);
     seekTime = buffered[index].mStart;
   }
   seekTime = mManager->Seek(mType, seekTime, MediaSourceDemuxer::EOS_FUZZ / 2);
-  bool error;
+  Result result;
   RefPtr<MediaRawData> sample =
     mManager->GetSample(mType,
                         media::TimeUnit(),
-                        error);
-  MOZ_ASSERT(!error && sample);
+                        result);
+  MOZ_ASSERT(result != Result::ERROR && sample);
   mNextSample = Some(sample);
   mReset = false;
   {
     MonitorAutoLock mon(mMonitor);
     mNextRandomAccessPoint =
       mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ);
   }
   return SeekPromise::CreateAndResolve(seekTime, __func__);
 }
 
 RefPtr<MediaSourceTrackDemuxer::SamplesPromise>
 MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples)
 {
+  typedef TrackBuffersManager::GetSampleResult Result;
+
   if (mReset) {
     // If a seek (or reset) was recently performed, we ensure that the data
     // we are about to retrieve is still available.
     TimeIntervals buffered = mManager->Buffered(mType);
     buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ);
 
+    if (!buffered.Length() && mManager->IsEnded()) {
+      return SamplesPromise::CreateAndReject(DemuxerFailureReason::END_OF_STREAM,
+                                             __func__);
+    }
     if (!buffered.Contains(TimeUnit::FromMicroseconds(0))) {
-      return SamplesPromise::CreateAndReject(
-        mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM :
-                              DemuxerFailureReason::WAITING_FOR_DATA, __func__);
+      return SamplesPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA,
+                                             __func__);
     }
     mReset = false;
   }
-  bool error = false;
   RefPtr<MediaRawData> sample;
   if (mNextSample) {
     sample = mNextSample.ref();
     mNextSample.reset();
   } else {
-    sample = mManager->GetSample(mType, MediaSourceDemuxer::EOS_FUZZ, error);
+    Result result;
+    sample = mManager->GetSample(mType, MediaSourceDemuxer::EOS_FUZZ, result);
     if (!sample) {
-      if (error) {
+      if (result == Result::ERROR) {
         return SamplesPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__);
       }
       return SamplesPromise::CreateAndReject(
-        mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM :
-                              DemuxerFailureReason::WAITING_FOR_DATA, __func__);
+        (result == Result::EOS && mManager->IsEnded())
+        ? DemuxerFailureReason::END_OF_STREAM
+        : DemuxerFailureReason::WAITING_FOR_DATA, __func__);
     }
   }
   RefPtr<SamplesHolder> samples = new SamplesHolder;
   samples->mSamples.AppendElement(sample);
   if (mNextRandomAccessPoint.ToMicroseconds() <= sample->mTime) {
     MonitorAutoLock mon(mMonitor);
     mNextRandomAccessPoint =
       mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ);
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -2133,79 +2133,95 @@ TrackBuffersManager::GetSample(TrackInfo
   // TODO, check that we have continuous data based on the sanitized buffered
   // range instead.
   return nullptr;
 }
 
 already_AddRefed<MediaRawData>
 TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack,
                                const TimeUnit& aFuzz,
-                               bool& aError)
+                               GetSampleResult& aResult)
 {
   MOZ_ASSERT(OnTaskQueue());
   auto& trackData = GetTracksData(aTrack);
   const TrackBuffer& track = GetTrackBuffer(aTrack);
 
-  aError = false;
+  aResult = GetSampleResult::WAITING_FOR_DATA;
 
   if (!track.Length()) {
+    aResult = GetSampleResult::EOS;
     return nullptr;
   }
+
   if (trackData.mNextGetSampleIndex.isNothing() &&
       trackData.mNextSampleTimecode == TimeUnit()) {
     // First demux, get first sample.
     trackData.mNextGetSampleIndex = Some(0u);
   }
 
   if (trackData.mNextGetSampleIndex.isSome()) {
+    if (trackData.mNextGetSampleIndex.ref() >= track.Length()) {
+      aResult = GetSampleResult::EOS;
+      return nullptr;
+    }
     const MediaRawData* sample =
       GetSample(aTrack,
                 trackData.mNextGetSampleIndex.ref(),
                 trackData.mNextSampleTimecode,
                 trackData.mNextSampleTime,
                 aFuzz);
     if (!sample) {
       return nullptr;
     }
 
     RefPtr<MediaRawData> p = sample->Clone();
     if (!p) {
-      aError = true;
+      aResult = GetSampleResult::ERROR;
       return nullptr;
     }
     trackData.mNextGetSampleIndex.ref()++;
     // Estimate decode timestamp of the next sample.
     trackData.mNextSampleTimecode =
       TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
     trackData.mNextSampleTime =
       TimeUnit::FromMicroseconds(sample->GetEndTime());
+    aResult = GetSampleResult::NO_ERROR;
     return p.forget();
   }
 
+  if (trackData.mNextSampleTimecode.ToMicroseconds() >
+      track.LastElement()->mTimecode + track.LastElement()->mDuration) {
+    // The next element is past our last sample. We're done.
+    trackData.mNextGetSampleIndex = Some(uint32_t(track.Length()));
+    aResult = GetSampleResult::EOS;
+    return nullptr;
+  }
+
   // Our previous index has been overwritten, attempt to find the new one.
   int32_t pos = FindCurrentPosition(aTrack, aFuzz);
   if (pos < 0) {
     MSE_DEBUG("Couldn't find sample (pts:%lld dts:%lld)",
               trackData.mNextSampleTime.ToMicroseconds(),
               trackData.mNextSampleTimecode.ToMicroseconds());
     return nullptr;
   }
 
   const RefPtr<MediaRawData>& sample = track[pos];
   RefPtr<MediaRawData> p = sample->Clone();
   if (!p) {
     // OOM
-    aError = true;
+    aResult = GetSampleResult::ERROR;
     return nullptr;
   }
   trackData.mNextGetSampleIndex = Some(uint32_t(pos)+1);
   trackData.mNextSampleTimecode =
     TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
   trackData.mNextSampleTime =
     TimeUnit::FromMicroseconds(sample->GetEndTime());
+  aResult = GetSampleResult::NO_ERROR;
   return p.forget();
 }
 
 int32_t
 TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack,
                                          const TimeUnit& aFuzz)
 {
   MOZ_ASSERT(OnTaskQueue());
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -148,19 +148,28 @@ public:
   }
   media::TimeUnit Seek(TrackInfo::TrackType aTrack,
                        const media::TimeUnit& aTime,
                        const media::TimeUnit& aFuzz);
   uint32_t SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack,
                                        const media::TimeUnit& aTimeThreadshold,
                                        const media::TimeUnit& aFuzz,
                                        bool& aFound);
+
+  enum class GetSampleResult
+  {
+    NO_ERROR,
+    ERROR,
+    WAITING_FOR_DATA,
+    EOS
+  };
+
   already_AddRefed<MediaRawData> GetSample(TrackInfo::TrackType aTrack,
                                            const media::TimeUnit& aFuzz,
-                                           bool& aError);
+                                           GetSampleResult& aResult);
   int32_t FindCurrentPosition(TrackInfo::TrackType aTrack,
                               const media::TimeUnit& aFuzz);
   media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack,
                                            const media::TimeUnit& aFuzz);
 
   void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes);
 
 private: