Bug 1209850: Only attempt to initialize decoders as they are required. r=alfredo
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 30 Sep 2015 14:35:11 +1000
changeset 265619 f13301365de3b5caa0376ae57d0fed73b70d1692
parent 265618 bf38814617d728e9db39749d018cde81b33dd5a3
child 265620 4f43cdaedec3f184d54699078ed245b16027770d
push id15472
push usercbook@mozilla.com
push dateFri, 02 Oct 2015 11:51:34 +0000
treeherderfx-team@2c33ef6b27e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersalfredo
bugs1209850
milestone44.0a1
Bug 1209850: Only attempt to initialize decoders as they are required. r=alfredo
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -434,36 +434,69 @@ MediaFormatReader::EnsureDecodersCreated
                                mDecoder->GetImageContainer());
     NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false);
   }
 
   return true;
 }
 
 bool
+MediaFormatReader::EnsureDecoderInitialized(TrackType aTrack)
+{
+  MOZ_ASSERT(OnTaskQueue());
+  auto& decoder = GetDecoderData(aTrack);
+
+  if (!decoder.mDecoder || decoder.mInitPromise.Exists()) {
+    MOZ_ASSERT(decoder.mDecoder);
+    return false;
+  }
+  if (decoder.mDecoderInitialized) {
+    return true;
+  }
+  nsRefPtr<MediaFormatReader> self = this;
+  decoder.mInitPromise.Begin(decoder.mDecoder->Init()
+       ->Then(OwnerThread(), __func__,
+              [self] (TrackType aTrack) {
+                auto& decoder = self->GetDecoderData(aTrack);
+                decoder.mInitPromise.Complete();
+                decoder.mDecoderInitialized = true;
+                self->ScheduleUpdate(aTrack);
+              },
+              [self, aTrack] (MediaDataDecoder::DecoderFailureReason aResult) {
+                auto& decoder = self->GetDecoderData(aTrack);
+                decoder.mInitPromise.Complete();
+                self->NotifyError(aTrack);
+              }));
+  return false;
+}
+
+bool
 MediaFormatReader::EnsureDecodersInitialized()
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(mVideo.mDecoder || mAudio.mDecoder);
 
   // DecodeDemuxedSample() could call this function before mDecodersInitRequest
   // is completed. And it is ok to return false here because DecodeDemuxedSample
   // will call ScheduleUpdate() again.
   // It also avoids calling decoder->Init() multiple times.
   if (mDecodersInitRequest.Exists()) {
+    MOZ_ASSERT(false);
     return false;
   }
 
   nsTArray<nsRefPtr<MediaDataDecoder::InitPromise>> promises;
 
   if (mVideo.mDecoder && !mVideo.mDecoderInitialized) {
+    MOZ_ASSERT(!mVideo.mInitPromise.Exists());
     promises.AppendElement(mVideo.mDecoder->Init());
   }
 
   if (mAudio.mDecoder && !mAudio.mDecoderInitialized) {
+    MOZ_ASSERT(!mAudio.mInitPromise.Exists());
     promises.AppendElement(mAudio.mDecoder->Init());
   }
 
   if (promises.Length()) {
     mDecodersInitRequest.Begin(MediaDataDecoder::InitPromise::All(OwnerThread(), promises)
       ->Then(OwnerThread(), __func__, this,
              &MediaFormatReader::OnDecoderInitDone,
              &MediaFormatReader::OnDecoderInitFailed));
@@ -481,27 +514,24 @@ void
 MediaFormatReader::OnDecoderInitDone(const nsTArray<TrackType>& aTrackTypes)
 {
   MOZ_ASSERT(OnTaskQueue());
   mDecodersInitRequest.Complete();
 
   for (const auto& track : aTrackTypes) {
     auto& decoder = GetDecoderData(track);
     decoder.mDecoderInitialized = true;
-
-    ScheduleUpdate(track);
   }
 
-  if (!mMetadataPromise.IsEmpty()) {
-    mInitDone = true;
-    nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
-    metadata->mInfo = mInfo;
-    metadata->mTags = nullptr;
-    mMetadataPromise.Resolve(metadata, __func__);
-  }
+  MOZ_ASSERT(!mMetadataPromise.IsEmpty());
+  mInitDone = true;
+  nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
+  metadata->mInfo = mInfo;
+  metadata->mTags = nullptr;
+  mMetadataPromise.Resolve(metadata, __func__);
 }
 
 void
 MediaFormatReader::OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason)
 {
   MOZ_ASSERT(OnTaskQueue());
   mDecodersInitRequest.Complete();
 
@@ -905,18 +935,17 @@ MediaFormatReader::DecodeDemuxedSamples(
   }
 
   if (!EnsureDecodersCreated()) {
     NS_WARNING("Error constructing decoders");
     NotifyError(aTrack);
     return;
   }
 
-  if (!EnsureDecodersInitialized()) {
-    ScheduleUpdate(aTrack);
+  if (!EnsureDecoderInitialized(aTrack)) {
     return;
   }
 
   LOGV("Giving %s input to decoder", TrackTypeToStr(aTrack));
 
   // Decode all our demuxed frames.
   bool samplesPending = false;
   while (decoder.mQueuedSamples.Length()) {
@@ -1035,17 +1064,17 @@ MediaFormatReader::DrainDecoder(TrackTyp
   LOG("Requesting %s decoder to drain", TrackTypeToStr(aTrack));
 }
 
 void
 MediaFormatReader::Update(TrackType aTrack)
 {
   MOZ_ASSERT(OnTaskQueue());
 
-  if (mShutdown) {
+  if (mShutdown || !mInitDone) {
     return;
   }
 
   LOGV("Processing update for %s", TrackTypeToStr(aTrack));
 
   bool needInput = false;
   bool needOutput = false;
   auto& decoder = GetDecoderData(aTrack);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -106,16 +106,17 @@ private:
   // buffered ranges.
   void NotifyDemuxer(uint32_t aLength, int64_t aOffset);
   void ReturnOutput(MediaData* aData, TrackType aTrack);
 
   bool EnsureDecodersCreated();
   // It returns true when all decoders are initialized. False when there is pending
   // initialization.
   bool EnsureDecodersInitialized();
+  bool EnsureDecoderInitialized(TrackType aTrack);
 
   // Enqueues a task to call Update(aTrack) on the decoder task queue.
   // Lock for corresponding track must be held.
   void ScheduleUpdate(TrackType aTrack);
   void Update(TrackType aTrack);
   // Handle actions should more data be received.
   // Returns true if no more action is required.
   bool UpdateReceivedNewData(TrackType aTrack);
@@ -244,16 +245,18 @@ private:
     MozPromiseHolder<WaitForDataPromise> mWaitingPromise;
     bool HasWaitingPromise()
     {
       MOZ_ASSERT(mOwner->OnTaskQueue());
       return !mWaitingPromise.IsEmpty();
     }
 
     // MediaDataDecoder handler's variables.
+    // Decoder initialization promise holder.
+    MozPromiseRequestHolder<MediaDataDecoder::InitPromise> mInitPromise;
     // False when decoder is created. True when decoder Init() promise is resolved.
     bool mDecoderInitialized;
     bool mDecodingRequested;
     bool mOutputRequested;
     bool mInputExhausted;
     bool mError;
     bool mNeedDraining;
     bool mDraining;