Bug 1107274 - Don't return EOS from MP4Reader until all frames have been output. r=cpearce, a=sledru
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 04 Dec 2014 11:51:30 -0800
changeset 242439 683b0185016af350adbbb14611a8f990c9f7d525
parent 242438 fae568d40c7224131bb6e2a7540e26cccc5b310e
child 242440 8408727d213edfb81df2be9dd945a6533a43e3f5
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, sledru
bugs1107274
milestone36.0a2
Bug 1107274 - Don't return EOS from MP4Reader until all frames have been output. r=cpearce, a=sledru
dom/media/fmp4/MP4Reader.cpp
dom/media/fmp4/MP4Reader.h
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -564,71 +564,75 @@ MP4Reader::NeedInput(DecoderData& aDecod
   aDecoder.mMonitor.AssertCurrentThreadOwns();
   // We try to keep a few more compressed samples input than decoded samples
   // have been output, provided the state machine has requested we send it a
   // decoded sample. To account for H.264 streams which may require a longer
   // run of input than we input, decoders fire an "input exhausted" callback,
   // which overrides our "few more samples" threshold.
   return
     !aDecoder.mError &&
-    !aDecoder.mEOS &&
+    !aDecoder.mDemuxEOS &&
     aDecoder.mOutputRequested &&
     aDecoder.mOutput.IsEmpty() &&
     (aDecoder.mInputExhausted ||
      aDecoder.mNumSamplesInput - aDecoder.mNumSamplesOutput < aDecoder.mDecodeAhead);
 }
 
 void
 MP4Reader::Update(TrackType aTrack)
 {
   MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn());
 
   bool needInput = false;
   bool needOutput = false;
+  bool eos = false;
   auto& decoder = GetDecoderData(aTrack);
   nsRefPtr<MediaData> output;
   {
     MonitorAutoLock lock(decoder.mMonitor);
     decoder.mUpdateScheduled = false;
     if (NeedInput(decoder)) {
       needInput = true;
       decoder.mInputExhausted = false;
       decoder.mNumSamplesInput++;
     }
     needOutput = decoder.mOutputRequested;
     if (needOutput && !decoder.mOutput.IsEmpty()) {
       output = decoder.mOutput[0];
       decoder.mOutput.RemoveElementAt(0);
     }
+    eos = decoder.mDrainComplete;
   }
   VLOG("Update(%s) ni=%d no=%d iex=%d or=%d fl=%d",
        TrackTypeToStr(aTrack),
        needInput,
        needOutput,
        decoder.mInputExhausted,
        decoder.mOutputRequested,
        decoder.mIsFlushing);
 
   if (needInput) {
     MP4Sample* sample = PopSample(aTrack);
     if (sample) {
       decoder.mDecoder->Input(sample);
     } else {
       {
         MonitorAutoLock lock(decoder.mMonitor);
-        MOZ_ASSERT(!decoder.mEOS);
-        decoder.mEOS = true;
+        MOZ_ASSERT(!decoder.mDemuxEOS);
+        decoder.mDemuxEOS = true;
       }
       // DrainComplete takes care of reporting EOS upwards
       decoder.mDecoder->Drain();
     }
   }
   if (needOutput) {
     if (output) {
       ReturnOutput(output, aTrack);
+    } else if (eos) {
+      ReturnEOS(aTrack);
     }
   }
 }
 
 void
 MP4Reader::ReturnOutput(MediaData* aData, TrackType aTrack)
 {
   auto& decoder = GetDecoderData(aTrack);
@@ -722,24 +726,19 @@ MP4Reader::Output(TrackType aTrack, Medi
     ScheduleUpdate(aTrack);
   }
 }
 
 void
 MP4Reader::DrainComplete(TrackType aTrack)
 {
   DecoderData& data = GetDecoderData(aTrack);
-  bool eos;
-  {
-    MonitorAutoLock mon(data.mMonitor);
-    eos = data.mEOS;
-  }
-  if (eos) {
-    ReturnEOS(aTrack);
-  }
+  MonitorAutoLock mon(data.mMonitor);
+  data.mDrainComplete = true;
+  ScheduleUpdate(aTrack);
 }
 
 void
 MP4Reader::InputExhausted(TrackType aTrack)
 {
   DecoderData& data = GetDecoderData(aTrack);
   MonitorAutoLock mon(data.mMonitor);
   data.mInputExhausted = true;
@@ -768,17 +767,18 @@ MP4Reader::Flush(TrackType aTrack)
     return;
   }
   // Purge the current decoder's state.
   // Set a flag so that we ignore all output while we call
   // MediaDataDecoder::Flush().
   {
     MonitorAutoLock mon(data.mMonitor);
     data.mIsFlushing = true;
-    data.mEOS = false;
+    data.mDemuxEOS = false;
+    data.mDrainComplete = false;
   }
   data.mDecoder->Flush();
   {
     MonitorAutoLock mon(data.mMonitor);
     data.mIsFlushing = false;
     data.mOutput.Clear();
     data.mNumSamplesInput = 0;
     data.mNumSamplesOutput = 0;
@@ -809,17 +809,17 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame(
   while (true) {
     nsAutoPtr<MP4Sample> compressed(PopSample(kVideo));
     if (!compressed) {
       // EOS, or error. Let the state machine know.
       GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA,
                                   RequestSampleCallback::END_OF_STREAM);
       {
         MonitorAutoLock mon(mVideo.mMonitor);
-        mVideo.mEOS = true;
+        mVideo.mDemuxEOS = true;
       }
       return false;
     }
     parsed++;
     if (!compressed->is_sync_point ||
         compressed->composition_timestamp < aTimeThreshold) {
       continue;
     }
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -153,17 +153,18 @@ private:
       , mNumSamplesOutput(0)
       , mDecodeAhead(aDecodeAhead)
       , mActive(false)
       , mInputExhausted(false)
       , mError(false)
       , mIsFlushing(false)
       , mOutputRequested(false)
       , mUpdateScheduled(false)
-      , mEOS(false)
+      , mDemuxEOS(false)
+      , mDrainComplete(false)
       , mDiscontinuity(false)
     {
     }
 
     // The platform decoder.
     nsRefPtr<MediaDataDecoder> mDecoder;
     // TaskQueue on which decoder can choose to decode.
     // Only non-null up until the decoder is created.
@@ -182,17 +183,18 @@ private:
     uint32_t mDecodeAhead;
     // Whether this stream exists in the media.
     bool mActive;
     bool mInputExhausted;
     bool mError;
     bool mIsFlushing;
     bool mOutputRequested;
     bool mUpdateScheduled;
-    bool mEOS;
+    bool mDemuxEOS;
+    bool mDrainComplete;
     bool mDiscontinuity;
   };
   DecoderData mAudio;
   DecoderData mVideo;
   // Queued samples extracted by the demuxer, but not yet sent to the platform
   // decoder.
   nsAutoPtr<mp4_demuxer::MP4Sample> mQueuedVideoSample;