Bug 1336431: P2. Asynchronously flush and shutdown decoder when SPS changes. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 13 Feb 2017 00:04:56 +0100
changeset 342743 e6f6b3736d93fe08db97c0f7d33a4be38a938270
parent 342742 c5ae7452946b40972dae6afaa2f051400679997d
child 342744 355c874066813dadcfb3f5f11c78f8e42434f00a
push id31362
push userkwierso@gmail.com
push dateTue, 14 Feb 2017 20:55:38 +0000
treeherdermozilla-central@c5a25b056d1e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1336431, 1319987
milestone54.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 1336431: P2. Asynchronously flush and shutdown decoder when SPS changes. r=cpearce Those steps were missed in bug 1319987. This is an area of the code rarely used under normal circumstances, asadaptive playback is only used with MSE. MozReview-Commit-ID: HZn3UxDy2GX
dom/media/platforms/wrappers/H264Converter.cpp
dom/media/platforms/wrappers/H264Converter.h
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -130,19 +130,27 @@ H264Converter::Drain()
     return mDecoder->Drain();
   }
   return DecodePromise::CreateAndResolve(DecodedData(), __func__);
 }
 
 RefPtr<ShutdownPromise>
 H264Converter::Shutdown()
 {
+  mInitPromiseRequest.DisconnectIfExists();
+  mDecodePromiseRequest.DisconnectIfExists();
+  mFlushRequest.DisconnectIfExists();
+  mShutdownRequest.DisconnectIfExists();
+  mPendingSample = nullptr;
+  if (mShutdownPromise) {
+    // We have a shutdown in progress, return that promise instead as we can't
+    // shutdown a decoder twice.
+    return mShutdownPromise.forget();
+  }
   if (mDecoder) {
-    mInitPromiseRequest.DisconnectIfExists();
-    mDecodePromiseRequest.DisconnectIfExists();
     RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
     return decoder->Shutdown();
   }
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 bool
 H264Converter::IsHardwareAccelerated(nsACString& aFailureReason) const
@@ -238,46 +246,46 @@ H264Converter::CreateDecoderAndInit(Medi
 }
 
 void
 H264Converter::OnDecoderInitDone(const TrackType aTrackType)
 {
   mInitPromiseRequest.Complete();
   RefPtr<MediaRawData> sample = mPendingSample.forget();
   if (mNeedKeyframe && !sample->mKeyframe) {
-    mDecodePromise.ResolveIfExists(DecodedData(), __func__);
+    mDecodePromise.Resolve(DecodedData(), __func__);
   }
   mNeedKeyframe = false;
   if (!mNeedAVCC
       && !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(sample, mNeedKeyframe)) {
-    mDecodePromise.RejectIfExists(
+    mDecodePromise.Reject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY,
                   RESULT_DETAIL("ConvertSampleToAnnexB")),
       __func__);
     return;
   }
   RefPtr<H264Converter> self = this;
   mDecoder->Decode(sample)
     ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
            [self, this](const MediaDataDecoder::DecodedData& aResults) {
              mDecodePromiseRequest.Complete();
-             mDecodePromise.ResolveIfExists(aResults, __func__);
+             mDecodePromise.Resolve(aResults, __func__);
            },
            [self, this](const MediaResult& aError) {
              mDecodePromiseRequest.Complete();
-             mDecodePromise.RejectIfExists(aError, __func__);
+             mDecodePromise.Reject(aError, __func__);
            })
     ->Track(mDecodePromiseRequest);
 }
 
 void
 H264Converter::OnDecoderInitFailed(const MediaResult& aError)
 {
   mInitPromiseRequest.Complete();
-  mDecodePromise.RejectIfExists(
+  mDecodePromise.Reject(
     MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                 RESULT_DETAIL("Unable to initialize H264 decoder")),
     __func__);
 }
 
 nsresult
 H264Converter::CheckForSPSChange(MediaRawData* aSample)
 {
@@ -293,19 +301,49 @@ H264Converter::CheckForSPSChange(MediaRa
       && mDecoder->SupportDecoderRecycling()) {
     // Do not recreate the decoder, reuse it.
     UpdateConfigFromExtraData(extra_data);
     mNeedKeyframe = true;
     return NS_OK;
   }
   // The SPS has changed, signal to flush the current decoder and create a
   // new one.
-  mDecoder->Flush();
-  Shutdown();
-  return CreateDecoderAndInit(aSample);
+  mPendingSample = aSample;
+  RefPtr<H264Converter> self = this;
+  mDecoder->Flush()
+    ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
+           __func__,
+           [self, this]() {
+             mFlushRequest.Complete();
+             mShutdownPromise = Shutdown();
+             mShutdownPromise
+               ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
+                      __func__,
+                      [self, this]() {
+                        mShutdownRequest.Complete();
+                        mShutdownPromise = nullptr;
+                        RefPtr<MediaRawData> sample = mPendingSample.forget();
+                        nsresult rv = CreateDecoderAndInit(sample);
+                        if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
+                          // All good so far, will continue later.
+                          return;
+                        }
+                        MOZ_ASSERT(NS_FAILED(rv));
+                        mDecodePromise.Reject(rv, __func__);
+                        return;
+                      },
+                      [] { MOZ_CRASH("Can't reach here'"); })
+               ->Track(mShutdownRequest);
+           },
+           [self, this](const MediaResult& aError) {
+             mFlushRequest.Complete();
+             mDecodePromise.Reject(aError, __func__);
+           })
+    ->Track(mFlushRequest);
+  return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER;
 }
 
 void
 H264Converter::UpdateConfigFromExtraData(MediaByteBuffer* aExtraData)
 {
   mp4_demuxer::SPSData spsdata;
   if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata)
       && spsdata.pic_width > 0
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -67,16 +67,20 @@ private:
   RefPtr<layers::KnowsCompositor> mKnowsCompositor;
   RefPtr<layers::ImageContainer> mImageContainer;
   const RefPtr<TaskQueue> mTaskQueue;
   RefPtr<MediaRawData> mPendingSample;
   RefPtr<MediaDataDecoder> mDecoder;
   MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
   MozPromiseRequestHolder<DecodePromise> mDecodePromiseRequest;
   MozPromiseHolder<DecodePromise> mDecodePromise;
+  MozPromiseRequestHolder<FlushPromise> mFlushRequest;
+  MozPromiseRequestHolder<ShutdownPromise> mShutdownRequest;
+  RefPtr<ShutdownPromise> mShutdownPromise;
+
   RefPtr<GMPCrashHelper> mGMPCrashHelper;
   bool mNeedAVCC;
   nsresult mLastError;
   bool mNeedKeyframe = true;
   const TrackInfo::TrackType mType;
   MediaEventProducer<TrackInfo::TrackType>* const mOnWaitingForKeyEvent;
 };