Bug 1319269 - part2 : implement the promise usgaes for PDM's clients. draft
authorAlastor Wu <alwu@mozilla.com>
Fri, 17 Mar 2017 18:41:20 +0800
changeset 500689 d8f8cb857cdb1459982d60bbf313a205b70e31ce
parent 500688 2df28812395152df36acdb4730a937346a79892b
child 500690 ea4ca342e7ed7933fb831d2251418056bb991a28
push id49766
push useralwu@mozilla.com
push dateFri, 17 Mar 2017 13:17:01 +0000
bugs1319269
milestone55.0a1
Bug 1319269 - part2 : implement the promise usgaes for PDM's clients. MozReview-Commit-ID: HTwXwXfGs8E
dom/media/Benchmark.cpp
dom/media/MediaFormatReader.cpp
dom/media/fmp4/MP4Decoder.cpp
dom/media/ipc/PVideoDecoder.ipdl
dom/media/ipc/PVideoDecoderManager.ipdl
dom/media/ipc/RemoteVideoDecoder.cpp
dom/media/ipc/RemoteVideoDecoder.h
dom/media/ipc/VideoDecoderChild.cpp
dom/media/ipc/VideoDecoderChild.h
dom/media/ipc/VideoDecoderManagerChild.cpp
dom/media/ipc/VideoDecoderManagerChild.h
dom/media/ipc/VideoDecoderManagerParent.cpp
dom/media/ipc/VideoDecoderManagerParent.h
dom/media/ipc/VideoDecoderParent.cpp
dom/media/ipc/VideoDecoderParent.h
dom/media/platforms/PDMFactory.cpp
dom/media/platforms/PDMFactory.h
dom/media/platforms/wrappers/H264Converter.cpp
dom/media/platforms/wrappers/H264Converter.h
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -209,29 +209,25 @@ BenchmarkPlayback::DemuxNextSample()
 }
 
 void
 BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo)
 {
   MOZ_ASSERT(OnThread());
 
   RefPtr<PDMFactory> platform = new PDMFactory();
-  mDecoder = platform->CreateDecoder({ aInfo, mDecoderTaskQueue });
-  if (!mDecoder) {
-    MainThreadShutdown();
-    return;
-  }
   RefPtr<Benchmark> ref(mMainThreadState);
-  mDecoder->Init()->Then(
-    Thread(), __func__,
-    [this, ref](TrackInfo::TrackType aTrackType) {
-      InputExhausted();
-    },
-    [this, ref](const MediaResult& aError) {
-      MainThreadShutdown();
+  platform->CreateDecoder({ aInfo, mDecoderTaskQueue })
+    ->Then(Thread(), __func__,
+      [this, ref] (RefPtr<MediaDataDecoder> aDecoder) {
+        mDecoder = aDecoder.forget();
+        InputExhausted();
+      },
+      [this, ref] () {
+        MainThreadShutdown();
     });
 }
 
 void
 BenchmarkPlayback::MainThreadShutdown()
 {
   MOZ_ASSERT(OnThread());
 
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -42,16 +42,18 @@ mozilla::LazyLogModule gMediaDemuxerLog(
 
 #define LOG(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Debug, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #define LOGV(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Verbose, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 
 #define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
 
 namespace mozilla {
 
+using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
+
 /**
  * This is a singleton which controls the number of decoders that can be
  * created concurrently. Before calling PDMFactory::CreateDecoder(), Alloc()
  * must be called to get a token object as a permission to create a decoder.
  * The token should stay alive until Shutdown() is called on the decoder.
  * The destructor of the token will restore the decoder count so it is available
  * for next calls of Alloc().
  */
@@ -477,54 +479,54 @@ public:
   // pristine state so CreateDecoder() is ready to be called again immediately.
   void ShutdownDecoder(TrackType aTrack)
   {
     MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
                || aTrack == TrackInfo::kVideoTrack);
     auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
     data.mPolicy->Cancel();
     data.mTokenRequest.DisconnectIfExists();
-    data.mInitRequest.DisconnectIfExists();
+    data.mCreateDecoderRequest.DisconnectIfExists();
     if (data.mDecoder) {
       mOwner->mShutdownPromisePool->ShutdownDecoder(data.mDecoder.forget());
     }
     data.mStage = Stage::None;
+    data.mToken = nullptr;
     MOZ_ASSERT(!data.mToken);
   }
 
 private:
   class Wrapper;
 
   enum class Stage : int8_t
   {
     None,
     WaitForToken,
     CreateDecoder,
-    WaitForInit
+    WaitForDecoder
   };
 
   struct Data
   {
     Data(DecoderData& aOwnerData, TrackType aTrack, TaskQueue* aThread)
       : mOwnerData(aOwnerData)
       , mTrack(aTrack)
       , mPolicy(new LocalAllocPolicy(aTrack, aThread)) { }
     DecoderData& mOwnerData;
     const TrackType mTrack;
     RefPtr<LocalAllocPolicy> mPolicy;
     Stage mStage = Stage::None;
     RefPtr<Token> mToken;
     RefPtr<MediaDataDecoder> mDecoder;
     MozPromiseRequestHolder<TokenPromise> mTokenRequest;
-    MozPromiseRequestHolder<InitPromise> mInitRequest;
+    MozPromiseRequestHolder<CreateDecoderPromise> mCreateDecoderRequest;
   } mAudio, mVideo;
 
   void RunStage(Data& aData);
-  MediaResult DoCreateDecoder(Data& aData);
-  void DoInitDecoder(Data& aData);
+  void DoCreateDecoder(Data& aData);
 
   // guaranteed to be valid by the owner.
   const NotNull<MediaFormatReader*> mOwner;
 };
 
 void
 MediaFormatReader::DecoderFactory::CreateDecoder(TrackType aTrack)
 {
@@ -610,78 +612,68 @@ MediaFormatReader::DecoderFactory::RunSt
       MOZ_ASSERT(!aData.mToken);
       MOZ_ASSERT(aData.mTokenRequest.Exists());
       break;
     }
 
     case Stage::CreateDecoder: {
       MOZ_ASSERT(aData.mToken);
       MOZ_ASSERT(!aData.mDecoder);
-      MOZ_ASSERT(!aData.mInitRequest.Exists());
-
-      MediaResult rv = DoCreateDecoder(aData);
-      if (NS_FAILED(rv)) {
-        NS_WARNING("Error constructing decoders");
-        aData.mToken = nullptr;
-        aData.mStage = Stage::None;
-        mOwner->NotifyError(aData.mTrack, rv);
-        return;
-      }
-
-      aData.mDecoder = new Wrapper(aData.mDecoder.forget(), aData.mToken.forget());
-      DoInitDecoder(aData);
-      aData.mStage = Stage::WaitForInit;
+      MOZ_ASSERT(!aData.mCreateDecoderRequest.Exists());
+      DoCreateDecoder(aData);
+      aData.mStage = Stage::WaitForDecoder;
       break;
     }
 
-    case Stage::WaitForInit: {
-      MOZ_ASSERT(aData.mDecoder);
-      MOZ_ASSERT(aData.mInitRequest.Exists());
+    case Stage::WaitForDecoder: {
+      MOZ_ASSERT(!aData.mDecoder);
+      MOZ_ASSERT(aData.mCreateDecoderRequest.Exists());
       break;
     }
   }
 }
 
-MediaResult
+void
 MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData)
 {
   auto& ownerData = aData.mOwnerData;
 
   auto decoderCreatingError = "error creating audio decoder";
   MediaResult result =
     MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, decoderCreatingError);
 
   if (!mOwner->mPlatform) {
     mOwner->mPlatform = new PDMFactory();
     if (mOwner->IsEncrypted()) {
       MOZ_ASSERT(mOwner->mCDMProxy);
       mOwner->mPlatform->SetCDMProxy(mOwner->mCDMProxy);
     }
   }
 
+  RefPtr<CreateDecoderPromise> createDecoderPromise;
   switch (aData.mTrack) {
     case TrackInfo::kAudioTrack: {
-      aData.mDecoder = mOwner->mPlatform->CreateDecoder({
+      createDecoderPromise = mOwner->mPlatform->CreateDecoder({
         ownerData.mInfo
         ? *ownerData.mInfo->GetAsAudioInfo()
         : *ownerData.mOriginalInfo->GetAsAudioInfo(),
         ownerData.mTaskQueue,
         mOwner->mCrashHelper,
         ownerData.mIsBlankDecode,
         &result,
         TrackInfo::kAudioTrack,
         &mOwner->OnTrackWaitingForKeyProducer()
       });
       break;
     }
 
     case TrackType::kVideoTrack: {
       // Decoders use the layers backend to decide if they can use hardware decoding,
       // so specify LAYERS_NONE if we want to forcibly disable it.
-      aData.mDecoder = mOwner->mPlatform->CreateDecoder({
+      createDecoderPromise = mOwner->mPlatform->CreateDecoder({
         ownerData.mInfo
         ? *ownerData.mInfo->GetAsVideoInfo()
         : *ownerData.mOriginalInfo->GetAsVideoInfo(),
         ownerData.mTaskQueue,
         mOwner->mKnowsCompositor,
         mOwner->GetImageContainer(),
         mOwner->mCrashHelper,
         ownerData.mIsBlankDecode,
@@ -691,49 +683,41 @@ MediaFormatReader::DecoderFactory::DoCre
       });
       break;
     }
 
     default:
       break;
   }
 
-  if (aData.mDecoder) {
-    return NS_OK;
-  }
-
-  ownerData.mDescription = decoderCreatingError;
-  return result;
-}
-
-void
-MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData)
-{
-  auto& ownerData = aData.mOwnerData;
-
-  aData.mDecoder->Init()
-    ->Then(mOwner->OwnerThread(), __func__,
-           [this, &aData, &ownerData](TrackType aTrack) {
-             aData.mInitRequest.Complete();
-             aData.mStage = Stage::None;
-             MutexAutoLock lock(ownerData.mMutex);
-             ownerData.mDecoder = aData.mDecoder.forget();
-             ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
-             mOwner->SetVideoDecodeThreshold();
-             mOwner->ScheduleUpdate(aTrack);
-           },
-           [this, &aData, &ownerData](const MediaResult& aError) {
-             aData.mInitRequest.Complete();
-             MOZ_RELEASE_ASSERT(!ownerData.mDecoder,
-                                "Can't have a decoder already set");
-             aData.mStage = Stage::None;
-             mOwner->mShutdownPromisePool->ShutdownDecoder(aData.mDecoder.forget());
-             mOwner->NotifyError(aData.mTrack, aError);
-           })
-    ->Track(aData.mInitRequest);
+  createDecoderPromise->Then(mOwner->OwnerThread(), __func__,
+    [this, &aData, &ownerData] (RefPtr<MediaDataDecoder> aDecoder) {
+      aData.mCreateDecoderRequest.Complete();
+      aData.mStage = Stage::None;
+
+      MutexAutoLock lock(ownerData.mMutex);
+      ownerData.mDecoder = new Wrapper(aDecoder.forget(), aData.mToken.forget());
+      ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
+
+      mOwner->SetVideoDecodeThreshold();
+      mOwner->ScheduleUpdate(aData.mTrack);
+    },
+    [this, &aData, &ownerData, &decoderCreatingError] () {
+      aData.mCreateDecoderRequest.Complete();
+      aData.mStage = Stage::None;
+      aData.mToken = nullptr;
+      NS_WARNING("Error constructing decoders");
+
+      MOZ_RELEASE_ASSERT(!ownerData.mDecoder,
+                         "Can't have a decoder already set");
+      MutexAutoLock lock(ownerData.mMutex);
+      ownerData.mDescription = decoderCreatingError;
+
+      mOwner->NotifyError(aData.mTrack, NS_ERROR_DOM_MEDIA_FATAL_ERR);
+  })->Track(aData.mCreateDecoderRequest);
 }
 
 // DemuxerProxy ensures that the original main demuxer is only ever accessed
 // via its own dedicated task queue.
 // This ensure that the reader's taskqueue will never blocked while a demuxer
 // is itself blocked attempting to access the MediaCache or the MediaResource.
 class MediaFormatReader::DemuxerProxy
 {
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -208,34 +208,32 @@ MP4Decoder::IsEnabled()
 // attempt to use hardware decoding for small videos.
 static const uint8_t sTestH264ExtraData[] = {
   0x01, 0x42, 0xc0, 0x1e, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x42,
   0xc0, 0x1e, 0xbb, 0x40, 0x50, 0x17, 0xfc, 0xb8, 0x08, 0x80,
   0x00, 0x00, 0x32, 0x00, 0x00, 0x0b, 0xb5, 0x07, 0x8b, 0x17,
   0x50, 0x01, 0x00, 0x04, 0x68, 0xce, 0x32, 0xc8
 };
 
-static already_AddRefed<MediaDataDecoder>
+static RefPtr<PlatformDecoderModule::CreateDecoderPromise>
 CreateTestH264Decoder(layers::KnowsCompositor* aKnowsCompositor,
                       VideoInfo& aConfig,
                       TaskQueue* aTaskQueue)
 {
   aConfig.mMimeType = "video/avc";
   aConfig.mId = 1;
   aConfig.mDuration = 40000;
   aConfig.mMediaTime = 0;
   aConfig.mImage = aConfig.mDisplay = nsIntSize(640, 360);
   aConfig.mExtraData = new MediaByteBuffer();
   aConfig.mExtraData->AppendElements(sTestH264ExtraData,
                                      MOZ_ARRAY_LENGTH(sTestH264ExtraData));
 
   RefPtr<PDMFactory> platform = new PDMFactory();
-  RefPtr<MediaDataDecoder> decoder(platform->CreateDecoder({ aConfig, aTaskQueue, aKnowsCompositor }));
-
-  return decoder.forget();
+  return platform->CreateDecoder({ aConfig, aTaskQueue, aKnowsCompositor });
 }
 
 /* static */ already_AddRefed<dom::Promise>
 MP4Decoder::IsVideoAccelerated(layers::KnowsCompositor* aKnowsCompositor, nsIGlobalObject* aParent)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   ErrorResult rv;
@@ -244,51 +242,41 @@ MP4Decoder::IsVideoAccelerated(layers::K
   if (rv.Failed()) {
     rv.SuppressException();
     return nullptr;
   }
 
   RefPtr<TaskQueue> taskQueue =
     new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
   VideoInfo config;
-  RefPtr<MediaDataDecoder> decoder(CreateTestH264Decoder(aKnowsCompositor, config, taskQueue));
-  if (!decoder) {
-    taskQueue->BeginShutdown();
-    taskQueue->AwaitShutdownAndIdle();
-    promise->MaybeResolve(NS_LITERAL_STRING("No; Failed to create H264 decoder"));
-    return promise.forget();
-  }
 
-  decoder->Init()
-    ->Then(aParent->AbstractMainThreadFor(TaskCategory::Other),
-           __func__,
-           [promise, decoder, taskQueue] (TrackInfo::TrackType aTrack) {
-             nsCString failureReason;
-             bool ok = decoder->IsHardwareAccelerated(failureReason);
-             nsAutoString result;
-             if (ok) {
-               result.AssignLiteral("Yes");
-             } else {
-               result.AssignLiteral("No");
-             }
-             if (failureReason.Length()) {
-               result.AppendLiteral("; ");
-               AppendUTF8toUTF16(failureReason, result);
-             }
-             decoder->Shutdown();
-             taskQueue->BeginShutdown();
-             taskQueue->AwaitShutdownAndIdle();
-             promise->MaybeResolve(result);
-           },
-           [promise, decoder, taskQueue] (MediaResult aError) {
-             decoder->Shutdown();
-             taskQueue->BeginShutdown();
-             taskQueue->AwaitShutdownAndIdle();
-             promise->MaybeResolve(NS_LITERAL_STRING("No; Failed to initialize H264 decoder"));
-           });
+  CreateTestH264Decoder(aKnowsCompositor, config, taskQueue)
+    ->Then(aParent->AbstractMainThreadFor(TaskCategory::Other), __func__,
+      [promise, taskQueue] (RefPtr<MediaDataDecoder> aDecoder) {
+        nsCString failureReason;
+        bool ok = aDecoder->IsHardwareAccelerated(failureReason);
+        nsAutoString result;
+        if (ok) {
+          result.AssignLiteral("Yes");
+        } else {
+          result.AssignLiteral("No");
+        }
+        if (failureReason.Length()) {
+          result.AppendLiteral("; ");
+          AppendUTF8toUTF16(failureReason, result);
+        }
+        aDecoder->Shutdown();
+        taskQueue->BeginShutdown();
+        taskQueue->AwaitShutdownAndIdle();
+        promise->MaybeResolve(result);
+      }, [promise, taskQueue] () {
+        taskQueue->BeginShutdown();
+        taskQueue->AwaitShutdownAndIdle();
+        promise->MaybeResolve(NS_LITERAL_STRING("No; Failed to create H264 decoder"));
+    });
 
   return promise.forget();
 }
 
 void
 MP4Decoder::GetMozDebugReaderData(nsACString& aString)
 {
   if (mReader) {
--- a/dom/media/ipc/PVideoDecoder.ipdl
+++ b/dom/media/ipc/PVideoDecoder.ipdl
@@ -56,16 +56,20 @@ parent:
 
   async SetSeekThreshold(int64_t time);
 
   async __delete__();
 
 child:
   async InitComplete(bool hardware, nsCString hardwareReason, uint32_t conversion);
   async InitFailed(nsresult reason);
+  async CreateDecoderCompleted(bool hardware,
+                               nsCString hardwareReason,
+                               uint32_t conversion);
+  async CreateDecoderFailed();
 
   async FlushComplete();
 
   // Each output includes a SurfaceDescriptorGPUVideo that represents the decoded
   // frame. This SurfaceDescriptor can be used on the Layers IPDL protocol, but
   // must be released explicitly using DeallocateSurfaceDescriptorGPUVideo
   // on the manager protocol.
   async Output(VideoDataIPDL data);
--- a/dom/media/ipc/PVideoDecoderManager.ipdl
+++ b/dom/media/ipc/PVideoDecoderManager.ipdl
@@ -11,17 +11,17 @@ using struct mozilla::layers::TextureFac
 
 namespace mozilla {
 namespace dom {
 
 sync protocol PVideoDecoderManager
 {
   manages PVideoDecoder;
 parent:
-  sync PVideoDecoder(VideoInfo info, TextureFactoryIdentifier identifier) returns (bool success);
+  sync PVideoDecoder(VideoInfo info, TextureFactoryIdentifier identifier);
 
   sync Readback(SurfaceDescriptorGPUVideo sd) returns (SurfaceDescriptor aResult);
 
   async DeallocateSurfaceDescriptorGPUVideo(SurfaceDescriptorGPUVideo sd);
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/ipc/RemoteVideoDecoder.cpp
+++ b/dom/media/ipc/RemoteVideoDecoder.cpp
@@ -11,16 +11,18 @@
 #include "MediaInfo.h"
 #include "MediaPrefs.h"
 #include "ImageContainer.h"
 #include "mozilla/layers/SynchronousTask.h"
 
 namespace mozilla {
 namespace dom {
 
+using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
+
 using base::Thread;
 using namespace ipc;
 using namespace layers;
 using namespace gfx;
 
 RemoteVideoDecoder::RemoteVideoDecoder()
   : mActor(new VideoDecoderChild())
 {
@@ -42,16 +44,43 @@ RemoteVideoDecoder::~RemoteVideoDecoder(
   // Drop out references to the actor so that the last ref
   // always gets released on the manager thread.
   actor = nullptr;
   mActor = nullptr;
 
   VideoDecoderManagerChild::GetManagerThread()->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
 }
 
+RefPtr<CreateDecoderPromise>
+RemoteVideoDecoder::CreateRemoteDecoder(const CreateDecoderParams& aParams)
+{
+  MOZ_ASSERT(mCreateDecoderPromise.IsEmpty());
+
+  RefPtr<CreateDecoderPromise> promise;
+  SynchronousTask task("InitIPDL");
+  VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([&]() {
+    AutoCompleteTask complete(&task);
+    promise = mActor->InitIPDL(aParams.VideoConfig(),
+                               aParams.mKnowsCompositor->GetTextureFactoryIdentifier());
+  }), NS_DISPATCH_NORMAL);
+  task.Wait();
+
+  RefPtr<RemoteVideoDecoder> self = this;
+  promise
+    ->Then(VideoDecoderManagerChild::GetManagerAbstractThread(), __func__,
+      [self] () {
+        self->mCreateDecoderPromise.Resolve(self, __func__);
+      },
+      [self] () {
+        self->mCreateDecoderPromise.Reject(false, __func__);
+    });
+
+  return mCreateDecoderPromise.Ensure(__func__);
+}
+
 RefPtr<MediaDataDecoder::InitPromise>
 RemoteVideoDecoder::Init()
 {
   RefPtr<RemoteVideoDecoder> self = this;
   return InvokeAsync(VideoDecoderManagerChild::GetManagerAbstractThread(),
                      __func__, [self, this]() { return mActor->Init(); });
 }
 
@@ -133,37 +162,29 @@ RemoteDecoderModule::SupportsMimeType(co
 
 bool
 RemoteDecoderModule::Supports(const TrackInfo& aTrackInfo,
                               DecoderDoctorDiagnostics* aDiagnostics) const
 {
   return mWrapped->Supports(aTrackInfo, aDiagnostics);
 }
 
-already_AddRefed<MediaDataDecoder>
+RefPtr<CreateDecoderPromise>
 RemoteDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
 {
   if (!MediaPrefs::PDMUseGPUDecoder() ||
       !aParams.mKnowsCompositor ||
       aParams.mKnowsCompositor->GetTextureFactoryIdentifier().mParentProcessType != GeckoProcessType_GPU) {
     return mWrapped->CreateVideoDecoder(aParams);
   }
 
-  RefPtr<RemoteVideoDecoder> object = new RemoteVideoDecoder();
+  RefPtr<RemoteVideoDecoder> remoteDecoderHolder = new RemoteVideoDecoder();
+  return remoteDecoderHolder->CreateRemoteDecoder(aParams);
+}
 
-  SynchronousTask task("InitIPDL");
-  bool success;
-  VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([&]() {
-    AutoCompleteTask complete(&task);
-    success = object->mActor->InitIPDL(aParams.VideoConfig(),
-                                       aParams.mKnowsCompositor->GetTextureFactoryIdentifier());
-  }), NS_DISPATCH_NORMAL);
-  task.Wait();
-
-  if (!success) {
-    return nullptr;
-  }
-
-  return object.forget();
+RefPtr<CreateDecoderPromise>
+RemoteDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
+{
+  return CreateDecoderPromise::CreateAndReject(false, __func__);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/ipc/RemoteVideoDecoder.h
+++ b/dom/media/ipc/RemoteVideoDecoder.h
@@ -21,16 +21,19 @@ class RemoteDecoderModule;
 // to a 'real' decoder in the GPU process.
 // All requests get forwarded to a VideoDecoderChild instance that
 // operates solely on the VideoDecoderManagerChild thread.
 class RemoteVideoDecoder : public MediaDataDecoder
 {
 public:
   friend class RemoteDecoderModule;
 
+  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+  CreateRemoteDecoder(const CreateDecoderParams& aParams);
+
   // MediaDataDecoder
   RefPtr<InitPromise> Init() override;
   RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   void SetSeekThreshold(const media::TimeUnit& aTime) override;
@@ -41,16 +44,17 @@ public:
 private:
   RemoteVideoDecoder();
   ~RemoteVideoDecoder();
 
   // Only ever written to from the reader task queue (during the constructor and
   // destructor when we can guarantee no other threads are accessing it). Only
   // read from the manager thread.
   RefPtr<VideoDecoderChild> mActor;
+  MozPromiseHolder<PlatformDecoderModule::CreateDecoderPromise> mCreateDecoderPromise;
 };
 
 // A PDM implementation that creates RemoteVideoDecoders.
 // We currently require a 'wrapped' PDM in order to be able to answer SupportsMimeType
 // and DecoderNeedsConversion. Ideally we'd check these over IPDL using the manager
 // protocol
 class RemoteDecoderModule : public PlatformDecoderModule
 {
@@ -61,24 +65,21 @@ public:
 
   nsresult Startup() override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
   bool Supports(const TrackInfo& aTrackInfo,
                 DecoderDoctorDiagnostics* aDiagnostics) const override;
 
-  already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
-    const CreateDecoderParams& aParams) override;
+  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+  CreateVideoDecoder(const CreateDecoderParams& aParams) override;
 
-  already_AddRefed<MediaDataDecoder> CreateAudioDecoder(
-    const CreateDecoderParams& aParams) override
-  {
-    return nullptr;
-  }
+  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+  CreateAudioDecoder(const CreateDecoderParams& aParams) override;
 
 private:
   RefPtr<PlatformDecoderModule> mWrapped;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/media/ipc/VideoDecoderChild.cpp
+++ b/dom/media/ipc/VideoDecoderChild.cpp
@@ -9,35 +9,39 @@
 #include "base/thread.h"
 #include "MediaInfo.h"
 #include "ImageContainer.h"
 #include "GPUVideoImage.h"
 
 namespace mozilla {
 namespace dom {
 
+using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
+
 using base::Thread;
 using namespace ipc;
 using namespace layers;
 using namespace gfx;
 
 VideoDecoderChild::VideoDecoderChild()
   : mThread(VideoDecoderManagerChild::GetManagerThread())
   , mCanSend(false)
   , mInitialized(false)
+  , mHasDecoder(false)
   , mIsHardwareAccelerated(false)
   , mConversion(MediaDataDecoder::ConversionRequired::kNeedNone)
   , mNeedNewDecoder(false)
 {
 }
 
 VideoDecoderChild::~VideoDecoderChild()
 {
   AssertOnManagerThread();
   mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
+  mCreateDecoderPromise.RejectIfExists(false, __func__);
 }
 
 mozilla::ipc::IPCResult
 VideoDecoderChild::RecvOutput(const VideoDataIPDL& aData)
 {
   AssertOnManagerThread();
   VideoInfo info(aData.display().width, aData.display().height);
 
@@ -105,73 +109,93 @@ mozilla::ipc::IPCResult
 VideoDecoderChild::RecvInitFailed(const nsresult& aReason)
 {
   AssertOnManagerThread();
   mInitPromise.RejectIfExists(aReason, __func__);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
+VideoDecoderChild::RecvCreateDecoderCompleted(const bool& aHardware,
+                                              const nsCString& aHardwareReason,
+                                              const uint32_t& aConversion)
+{
+  AssertOnManagerThread();
+  mCreateDecoderPromise.ResolveIfExists(nullptr, __func__);
+  mHasDecoder = true;
+  mIsHardwareAccelerated = aHardware;
+  mHardwareAcceleratedReason = aHardwareReason;
+  mConversion = static_cast<MediaDataDecoder::ConversionRequired>(aConversion);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+VideoDecoderChild::RecvCreateDecoderFailed()
+{
+  AssertOnManagerThread();
+  mCreateDecoderPromise.RejectIfExists(false, __func__);
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
 VideoDecoderChild::RecvFlushComplete()
 {
   AssertOnManagerThread();
   mFlushPromise.ResolveIfExists(true, __func__);
   return IPC_OK();
 }
 
 void
 VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   if (aWhy == AbnormalShutdown) {
     // Defer reporting an error until we've recreated the manager so that
     // it'll be safe for MediaFormatReader to recreate decoders
     RefPtr<VideoDecoderChild> ref = this;
     GetManager()->RunWhenRecreated(NS_NewRunnableFunction([=]() {
-      if (ref->mInitialized) {
+      if (ref->mHasDecoder) {
         mDecodedData.Clear();
         mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
                                       __func__);
         mDrainPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
                                      __func__);
         mFlushPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
                                      __func__);
         // Make sure the next request will be rejected accordingly if ever
         // called.
         mNeedNewDecoder = true;
       } else {
-        ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER,
-                                         __func__);
+        ref->mCreateDecoderPromise.RejectIfExists(false, __func__);
       }
     }));
   }
   mCanSend = false;
 }
 
-bool
+RefPtr<CreateDecoderPromise>
 VideoDecoderChild::InitIPDL(const VideoInfo& aVideoInfo,
                             const layers::TextureFactoryIdentifier& aIdentifier)
 {
   RefPtr<VideoDecoderManagerChild> manager =
     VideoDecoderManagerChild::GetSingleton();
   // If the manager isn't available, then don't initialize mIPDLSelfRef and
   // leave us in an error state. We'll then immediately reject the promise when
   // Init() is called and the caller can try again. Hopefully by then the new
   // manager is ready, or we've notified the caller of it being no longer
   // available. If not, then the cycle repeats until we're ready.
   if (!manager || !manager->CanSend()) {
-    return true;
+    // TODO : async continue to create PVideoDecoder.
+    return CreateDecoderPromise::CreateAndReject(false, __func__);
   }
 
   mIPDLSelfRef = this;
-  bool success = false;
-  if (manager->SendPVideoDecoderConstructor(this, aVideoInfo, aIdentifier,
-                                            &success)) {
+  if (manager->SendPVideoDecoderConstructor(this, aVideoInfo, aIdentifier)) {
     mCanSend = true;
   }
-  return success;
+  return mCreateDecoderPromise.Ensure(__func__);
 }
 
 void
 VideoDecoderChild::DestroyIPDL()
 {
   if (mCanSend) {
     PVideoDecoderChild::Send__delete__(this);
   }
@@ -270,20 +294,22 @@ VideoDecoderChild::Drain()
   return mDrainPromise.Ensure(__func__);
 }
 
 void
 VideoDecoderChild::Shutdown()
 {
   AssertOnManagerThread();
   mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
+  mCreateDecoderPromise.RejectIfExists(false, __func__);
   if (mCanSend) {
     SendShutdown();
   }
   mInitialized = false;
+  mHasDecoder = false;
 }
 
 bool
 VideoDecoderChild::IsHardwareAccelerated(nsACString& aFailureReason) const
 {
   aFailureReason = mHardwareAcceleratedReason;
   return mIsHardwareAccelerated;
 }
--- a/dom/media/ipc/VideoDecoderChild.h
+++ b/dom/media/ipc/VideoDecoderChild.h
@@ -28,32 +28,38 @@ public:
   mozilla::ipc::IPCResult RecvOutput(const VideoDataIPDL& aData) override;
   mozilla::ipc::IPCResult RecvInputExhausted() override;
   mozilla::ipc::IPCResult RecvDrainComplete() override;
   mozilla::ipc::IPCResult RecvError(const nsresult& aError) override;
   mozilla::ipc::IPCResult RecvInitComplete(const bool& aHardware,
                                            const nsCString& aHardwareReason,
                                            const uint32_t& aConversion) override;
   mozilla::ipc::IPCResult RecvInitFailed(const nsresult& aReason) override;
+  mozilla::ipc::IPCResult RecvCreateDecoderCompleted(const bool& aHardware,
+                                                     const nsCString& aHardwareReason,
+                                                     const uint32_t& aConversion) override;
+  mozilla::ipc::IPCResult RecvCreateDecoderFailed() override;
   mozilla::ipc::IPCResult RecvFlushComplete() override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   RefPtr<MediaDataDecoder::InitPromise> Init();
   RefPtr<MediaDataDecoder::DecodePromise> Decode(MediaRawData* aSample);
   RefPtr<MediaDataDecoder::DecodePromise> Drain();
   RefPtr<MediaDataDecoder::FlushPromise> Flush();
   void Shutdown();
   bool IsHardwareAccelerated(nsACString& aFailureReason) const;
   void SetSeekThreshold(const media::TimeUnit& aTime);
   MediaDataDecoder::ConversionRequired NeedsConversion() const;
 
   MOZ_IS_CLASS_INIT
-  bool InitIPDL(const VideoInfo& aVideoInfo,
-                const layers::TextureFactoryIdentifier& aIdentifier);
+  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+  InitIPDL(const VideoInfo& aVideoInfo,
+           const layers::TextureFactoryIdentifier& aIdentifier);
+
   void DestroyIPDL();
 
   // Called from IPDL when our actor has been destroyed
   void IPDLActorDestroyed();
 
   VideoDecoderManagerChild* GetManager();
 
 private:
@@ -63,20 +69,23 @@ private:
 
   RefPtr<VideoDecoderChild> mIPDLSelfRef;
   RefPtr<nsIThread> mThread;
 
   MozPromiseHolder<MediaDataDecoder::InitPromise> mInitPromise;
   MozPromiseHolder<MediaDataDecoder::DecodePromise> mDecodePromise;
   MozPromiseHolder<MediaDataDecoder::DecodePromise> mDrainPromise;
   MozPromiseHolder<MediaDataDecoder::FlushPromise> mFlushPromise;
+  MozPromiseHolder<PlatformDecoderModule::CreateDecoderPromise>
+    mCreateDecoderPromise;
 
   nsCString mHardwareAcceleratedReason;
   bool mCanSend;
   bool mInitialized;
+  bool mHasDecoder;
   Atomic<bool> mIsHardwareAccelerated;
   Atomic<MediaDataDecoder::ConversionRequired> mConversion;
 
   // Set to true if the actor got destroyed and we haven't yet notified the
   // caller.
   bool mNeedNewDecoder;
   MediaDataDecoder::DecodedData mDecodedData;
 };
--- a/dom/media/ipc/VideoDecoderManagerChild.cpp
+++ b/dom/media/ipc/VideoDecoderManagerChild.cpp
@@ -107,18 +107,17 @@ VideoDecoderManagerChild::GetManagerThre
 /* static */ AbstractThread*
 VideoDecoderManagerChild::GetManagerAbstractThread()
 {
   return sVideoDecoderChildAbstractThread;
 }
 
 PVideoDecoderChild*
 VideoDecoderManagerChild::AllocPVideoDecoderChild(const VideoInfo& aVideoInfo,
-                                                  const layers::TextureFactoryIdentifier& aIdentifier,
-                                                  bool* aSuccess)
+                                                  const layers::TextureFactoryIdentifier& aIdentifier)
 {
   return new VideoDecoderChild();
 }
 
 bool
 VideoDecoderManagerChild::DeallocPVideoDecoderChild(PVideoDecoderChild* actor)
 {
   VideoDecoderChild* child = static_cast<VideoDecoderChild*>(actor);
--- a/dom/media/ipc/VideoDecoderManagerChild.h
+++ b/dom/media/ipc/VideoDecoderManagerChild.h
@@ -66,18 +66,17 @@ protected:
   void InitIPDL();
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void DeallocPVideoDecoderManagerChild() override;
 
   void HandleFatalError(const char* aName, const char* aMsg) const override;
 
   PVideoDecoderChild* AllocPVideoDecoderChild(const VideoInfo& aVideoInfo,
-                                              const layers::TextureFactoryIdentifier& aIdentifier,
-                                              bool* aSuccess) override;
+                                              const layers::TextureFactoryIdentifier& aIdentifier) override;
   bool DeallocPVideoDecoderChild(PVideoDecoderChild* actor) override;
 
 private:
   // Main thread only
   static void InitializeThread();
 
   VideoDecoderManagerChild()
     : mCanSend(false)
--- a/dom/media/ipc/VideoDecoderManagerParent.cpp
+++ b/dom/media/ipc/VideoDecoderManagerParent.cpp
@@ -151,22 +151,20 @@ VideoDecoderManagerParent::VideoDecoderM
 
 VideoDecoderManagerParent::~VideoDecoderManagerParent()
 {
   MOZ_COUNT_DTOR(VideoDecoderManagerParent);
 }
 
 PVideoDecoderParent*
 VideoDecoderManagerParent::AllocPVideoDecoderParent(const VideoInfo& aVideoInfo,
-                                                    const layers::TextureFactoryIdentifier& aIdentifier,
-                                                    bool* aSuccess)
+                                                    const layers::TextureFactoryIdentifier& aIdentifier)
 {
   return new VideoDecoderParent(this, aVideoInfo, aIdentifier, sManagerTaskQueue,
-                                new TaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("VideoDecoderParent"), 4)),
-                                aSuccess);
+                                new TaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("VideoDecoderParent"), 4)));
 }
 
 bool
 VideoDecoderManagerParent::DeallocPVideoDecoderParent(PVideoDecoderParent* actor)
 {
   VideoDecoderParent* parent = static_cast<VideoDecoderParent*>(actor);
   parent->Destroy();
   return true;
--- a/dom/media/ipc/VideoDecoderManagerParent.h
+++ b/dom/media/ipc/VideoDecoderManagerParent.h
@@ -24,17 +24,17 @@ public:
   static void StartupThreads();
   static void ShutdownThreads();
 
   static void ShutdownVideoBridge();
 
   bool OnManagerThread();
 
 protected:
-  PVideoDecoderParent* AllocPVideoDecoderParent(const VideoInfo& aVideoInfo, const layers::TextureFactoryIdentifier& aIdentifier, bool* aSuccess) override;
+  PVideoDecoderParent* AllocPVideoDecoderParent(const VideoInfo& aVideoInfo, const layers::TextureFactoryIdentifier& aIdentifier) override;
   bool DeallocPVideoDecoderParent(PVideoDecoderParent* actor) override;
 
   mozilla::ipc::IPCResult RecvReadback(const SurfaceDescriptorGPUVideo& aSD, SurfaceDescriptor* aResult) override;
   mozilla::ipc::IPCResult RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) override;
 
   void ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override {}
 
   void DeallocPVideoDecoderManagerParent() override;
--- a/dom/media/ipc/VideoDecoderParent.cpp
+++ b/dom/media/ipc/VideoDecoderParent.cpp
@@ -40,18 +40,17 @@ public:
 private:
   virtual ~KnowsCompositorVideo() = default;
 };
 
 VideoDecoderParent::VideoDecoderParent(VideoDecoderManagerParent* aParent,
                                        const VideoInfo& aVideoInfo,
                                        const layers::TextureFactoryIdentifier& aIdentifier,
                                        TaskQueue* aManagerTaskQueue,
-                                       TaskQueue* aDecodeTaskQueue,
-                                       bool* aSuccess)
+                                       TaskQueue* aDecodeTaskQueue)
   : mParent(aParent)
   , mManagerTaskQueue(aManagerTaskQueue)
   , mDecodeTaskQueue(aDecodeTaskQueue)
   , mKnowsCompositor(new KnowsCompositorVideo)
   , mDestroyed(false)
 {
   MOZ_COUNT_CTOR(VideoDecoderParent);
   MOZ_ASSERT(OnManagerThread());
@@ -70,23 +69,40 @@ VideoDecoderParent::VideoDecoderParent(V
   RefPtr<WMFDecoderModule> pdm(new WMFDecoderModule());
   pdm->Startup();
 
   CreateDecoderParams params(aVideoInfo);
   params.mTaskQueue = mDecodeTaskQueue;
   params.mKnowsCompositor = mKnowsCompositor;
   params.mImageContainer = new layers::ImageContainer();
 
-  mDecoder = pdm->CreateVideoDecoder(params);
+  RefPtr<VideoDecoderParent> self = this;
+  pdm->CreateVideoDecoder(params)->Then(mManagerTaskQueue, __func__,
+    [self] (RefPtr<MediaDataDecoder> aDecoder) {
+      self->mDecoder = aDecoder.forget();
+      MOZ_ASSERT(self->mDecoder);
+
+      nsCString hardwareReason;
+      bool hardwareAccelerated =
+        self->mDecoder->IsHardwareAccelerated(hardwareReason);
+      uint32_t conversion =
+        static_cast<uint32_t>(self->mDecoder->NeedsConversion());
+      Unused << self->SendCreateDecoderCompleted(hardwareAccelerated,
+                                                 hardwareReason,
+                                                 conversion);
+    },
+    [self] () {
+      if (!self->mDestroyed) {
+        Unused << self->SendCreateDecoderFailed();
+      }
+  });
 #else
   MOZ_ASSERT(false,
              "Can't use RemoteVideoDecoder on non-Windows platforms yet");
 #endif
-
-  *aSuccess = !!mDecoder;
 }
 
 VideoDecoderParent::~VideoDecoderParent()
 {
   MOZ_COUNT_DTOR(VideoDecoderParent);
 }
 
 void
--- a/dom/media/ipc/VideoDecoderParent.h
+++ b/dom/media/ipc/VideoDecoderParent.h
@@ -25,18 +25,17 @@ public:
   // We refcount this class since the task queue can have runnables
   // that reference us.
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderParent)
 
   VideoDecoderParent(VideoDecoderManagerParent* aParent,
                      const VideoInfo& aVideoInfo,
                      const layers::TextureFactoryIdentifier& aIdentifier,
                      TaskQueue* aManagerTaskQueue,
-                     TaskQueue* aDecodeTaskQueue,
-                     bool* aSuccess);
+                     TaskQueue* aDecodeTaskQueue);
 
   void Destroy();
 
   // PVideoDecoderParent
   mozilla::ipc::IPCResult RecvInit() override;
   mozilla::ipc::IPCResult RecvInput(const MediaRawDataIPDL& aData) override;
   mozilla::ipc::IPCResult RecvFlush() override;
   mozilla::ipc::IPCResult RecvDrain() override;
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -46,16 +46,18 @@
 #include "mozilla/dom/RemoteVideoDecoder.h"
 
 #include "mp4_demuxer/H264.h"
 
 #include <functional>
 
 namespace mozilla {
 
+using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
+
 extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
 extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
 
 class PDMFactoryImpl final
 {
 public:
   PDMFactoryImpl()
   {
@@ -195,17 +197,17 @@ PDMFactory::EnsureInit() const
       if (!sInstance) {
         sInstance = new PDMFactoryImpl();
         ClearOnShutdown(&sInstance);
       }
     });
   SyncRunnable::DispatchToThread(mainThread, runnable);
 }
 
-already_AddRefed<MediaDataDecoder>
+RefPtr<CreateDecoderPromise>
 PDMFactory::CreateDecoder(const CreateDecoderParams& aParams)
 {
   if (aParams.mUseBlankDecoder) {
     MOZ_ASSERT(mBlankPDM);
     return CreateDecoderWithPDM(mBlankPDM, aParams);
   }
 
   const TrackInfo& config = aParams.mConfig;
@@ -226,37 +228,55 @@ PDMFactory::CreateDecoder(const CreateDe
       diagnostics->SetFFmpegFailedToLoad();
     }
     if (mGMPPDMFailedToStartup) {
       diagnostics->SetGMPPDMFailedToStartup();
     }
   }
 
   for (auto& current : mCurrentPDMs) {
-    if (!current->SupportsMimeType(config.mMimeType, diagnostics)) {
+    if (!current->SupportsMimeType(config.mMimeType, diagnostics) ||
+        !CheckMediaFormat(aParams)) {
       continue;
     }
-    RefPtr<MediaDataDecoder> m = CreateDecoderWithPDM(current, aParams);
-    if (m) {
-      return m.forget();
-    }
+    return CreateDecoderWithPDM(current, aParams);
   }
   NS_WARNING("Unable to create a decoder, no platform found.");
-  return nullptr;
+
+  return CreateDecoderPromise::CreateAndReject(false, __func__);
 }
 
-already_AddRefed<MediaDataDecoder>
+RefPtr<CreateDecoderPromise>
 PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                                  const CreateDecoderParams& aParams)
 {
   MOZ_ASSERT(aPDM);
-  RefPtr<MediaDataDecoder> m;
+
+  if (aParams.mConfig.IsAudio()) {
+    return aPDM->CreateAudioDecoder(aParams);
+  } else if (aParams.mConfig.IsVideo()) {
+    if (MP4Decoder::IsH264(aParams.mConfig.mMimeType) &&
+        !aParams.mUseBlankDecoder) {
+      RefPtr<H264Converter> h = new H264Converter(aPDM, aParams);
+      return h->CreateVideoDecoder();
+    }
+    return aPDM->CreateVideoDecoder(aParams);
+  }
+
+  *aParams.mError = MediaResult(
+    NS_ERROR_DOM_MEDIA_FATAL_ERR,
+    RESULT_DETAIL("Decoder configuration error, expected audio or video."));
+  return CreateDecoderPromise::CreateAndReject(false, __func__);
+}
+
+bool
+PDMFactory::CheckMediaFormat(const CreateDecoderParams& aParams) const
+{
+  SupportChecker supportChecker;
   MediaResult* result = aParams.mError;
-
-  SupportChecker supportChecker;
   const TrackInfo& config = aParams.mConfig;
   supportChecker.AddMediaFormatChecker(config);
 
   auto checkResult = supportChecker.Check();
   if (checkResult.mReason != SupportChecker::Reason::kSupported) {
     DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
     if (checkResult.mReason
         == SupportChecker::Reason::kVideoFormatNotSupported) {
@@ -270,45 +290,19 @@ PDMFactory::CreateDecoderWithPDM(Platfor
                == SupportChecker::Reason::kAudioFormatNotSupported) {
       if (diagnostics) {
         diagnostics->SetAudioNotSupported();
       }
       if (result) {
         *result = checkResult.mMediaResult;
       }
     }
-    return nullptr;
-  }
-
-  if (config.IsAudio()) {
-    m = aPDM->CreateAudioDecoder(aParams);
-    return m.forget();
-  }
-
-  if (!config.IsVideo()) {
-    *result = MediaResult(
-      NS_ERROR_DOM_MEDIA_FATAL_ERR,
-      RESULT_DETAIL("Decoder configuration error, expected audio or video."));
-    return nullptr;
+    return false;
   }
-
-  if (MP4Decoder::IsH264(config.mMimeType) && !aParams.mUseBlankDecoder) {
-    RefPtr<H264Converter> h = new H264Converter(aPDM, aParams);
-    const nsresult rv = h->GetLastError();
-    if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) {
-      // The H264Converter either successfully created the wrapped decoder,
-      // or there wasn't enough AVCC data to do so. Otherwise, there was some
-      // problem, for example WMF DLLs were missing.
-      m = h.forget();
-    }
-  } else {
-    m = aPDM->CreateVideoDecoder(aParams);
-  }
-
-  return m.forget();
+  return true;
 }
 
 bool
 PDMFactory::SupportsMimeType(const nsACString& aMimeType,
                              DecoderDoctorDiagnostics* aDiagnostics) const
 {
   UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
   if (!trackInfo) {
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -25,17 +25,17 @@ public:
 
   PDMFactory();
 
   // Factory method that creates the appropriate PlatformDecoderModule for
   // the platform we're running on. Caller is responsible for deleting this
   // instance. It's expected that there will be multiple
   // PlatformDecoderModules alive at the same time.
   // This is called on the decode task queue.
-  already_AddRefed<MediaDataDecoder>
+  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
   CreateDecoder(const CreateDecoderParams& aParams);
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const;
   bool Supports(const TrackInfo& aTrackInfo,
                 DecoderDoctorDiagnostics* aDiagnostics) const;
 
   // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
@@ -56,20 +56,22 @@ private:
   void CreateBlankPDM();
   // Startup the provided PDM and add it to our list if successful.
   bool StartupPDM(PlatformDecoderModule* aPDM);
   // Returns the first PDM in our list supporting the mimetype.
   already_AddRefed<PlatformDecoderModule>
   GetDecoder(const TrackInfo& aTrackInfo,
              DecoderDoctorDiagnostics* aDiagnostics) const;
 
-  already_AddRefed<MediaDataDecoder>
+  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
   CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
                        const CreateDecoderParams& aParams);
 
+  bool CheckMediaFormat(const CreateDecoderParams& aParams) const;
+
   nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs;
   RefPtr<PlatformDecoderModule> mEMEPDM;
   RefPtr<PlatformDecoderModule> mBlankPDM;
 
   bool mWMFFailedToLoad = false;
   bool mFFmpegFailedToLoad = false;
   bool mGMPPDMFailedToStartup = false;
 
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -6,96 +6,118 @@
 
 #include "mozilla/TaskQueue.h"
 
 #include "H264Converter.h"
 #include "ImageContainer.h"
 #include "MediaInfo.h"
 #include "MediaPrefs.h"
 #include "mp4_demuxer/AnnexB.h"
-#include "mp4_demuxer/H264.h"
 
 namespace mozilla
 {
 
+using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
+
 H264Converter::H264Converter(PlatformDecoderModule* aPDM,
                              const CreateDecoderParams& aParams)
   : mPDM(aPDM)
   , mOriginalConfig(aParams.VideoConfig())
   , mCurrentConfig(aParams.VideoConfig())
   , mKnowsCompositor(aParams.mKnowsCompositor)
   , mImageContainer(aParams.mImageContainer)
   , mTaskQueue(aParams.mTaskQueue)
   , mDecoder(nullptr)
   , mGMPCrashHelper(aParams.mCrashHelper)
-  , mLastError(NS_OK)
   , mType(aParams.mType)
   , mOnWaitingForKeyEvent(aParams.mOnWaitingForKeyEvent)
   , mDecoderOptions(aParams.mOptions)
-{
-  CreateDecoder(aParams.mDiagnostics);
-}
+  , mDiagnostics(aParams.mDiagnostics)
+{}
 
 H264Converter::~H264Converter()
 {
 }
 
+RefPtr<CreateDecoderPromise>
+H264Converter::CreateVideoDecoder()
+{
+  RefPtr<CreateDecoderPromise> promise;
+  if (!CanCreateDecoder(mCurrentConfig.mExtraData)) {
+    promise = CreateDecoderPromise::CreateAndReject(false, __func__);
+    return promise.forget();
+  }
+
+  PromiseHolder* rawHolder = new PromiseHolder();
+  promise = rawHolder->Ensure(__func__);
+
+  RefPtr<H264Converter> self = this;
+  mPDM->CreateVideoDecoder({
+    mUseOriginalConfig ? mOriginalConfig : mCurrentConfig,
+    mTaskQueue,
+    mDiagnostics,
+    mImageContainer,
+    mKnowsCompositor,
+    mGMPCrashHelper,
+    mType,
+    mOnWaitingForKeyEvent,
+    mDecoderOptions
+  })->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
+    [self, rawHolder] (RefPtr<MediaDataDecoder> aDecoder) {
+      self->mUseOriginalConfig = false;
+      self->mNeedKeyframe = true;
+      UniquePtr<PromiseHolder> holder(rawHolder);
+      holder->Resolve(aDecoder, __func__);
+    },
+    [rawHolder] () {
+      UniquePtr<PromiseHolder> holder(rawHolder);
+      holder->Reject(false, __func__);
+  });
+
+  return promise.forget();
+}
+
 RefPtr<MediaDataDecoder::InitPromise>
 H264Converter::Init()
 {
   if (mDecoder) {
     return mDecoder->Init();
   }
 
   // We haven't been able to initialize a decoder due to a missing SPS/PPS.
   return MediaDataDecoder::InitPromise::CreateAndResolve(
            TrackType::kVideoTrack, __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 H264Converter::Decode(MediaRawData* aSample)
 {
-  MOZ_RELEASE_ASSERT(!mDecodePromiseRequest.Exists()
-                     && !mInitPromiseRequest.Exists(),
+  MOZ_RELEASE_ASSERT(!mDecodePromiseRequest.Exists() &&
+                     !mCreateDecoderRequest.Exists(),
                      "Can't request a new decode until previous one completed");
 
   if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
     // We need AVCC content to be able to later parse the SPS.
     // This is a no-op if the data is already AVCC.
     return DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_OUT_OF_MEMORY, RESULT_DETAIL("ConvertSampleToAVCC")),
       __func__);
   }
 
-  nsresult rv;
   if (!mDecoder) {
     // It is not possible to create an AVCC H264 decoder without SPS.
     // As such, creation will fail if the extra_data just extracted doesn't
     // contain a SPS.
-    rv = CreateDecoderAndInit(aSample);
-    if (rv == NS_ERROR_NOT_INITIALIZED) {
-      // We are missing the required SPS to create the decoder.
-      // Ignore for the time being, the MediaRawData will be dropped.
-      return DecodePromise::CreateAndResolve(DecodedData(), __func__);
-    }
-  } else {
-    rv = CheckForSPSChange(aSample);
-  }
-
-  if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
-    // The decoder is pending initialization.
     RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__);
+    CreateDecoderAndDecodeFirstSample(aSample);
     return p;
   }
 
-  if (NS_FAILED(rv)) {
-    return DecodePromise::CreateAndReject(
-      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
-                  RESULT_DETAIL("Unable to create H264 decoder")),
-      __func__);
+  if (IsSPSChanged(aSample)) {
+    return RecycleOrRecreateDecoder(aSample);
   }
 
   if (mNeedKeyframe && !aSample->mKeyframe) {
     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
   }
 
   if (!mNeedAVCC) {
     mNeedAVCC =
@@ -135,21 +157,20 @@ H264Converter::Drain()
     return mDecoder->Drain();
   }
   return DecodePromise::CreateAndResolve(DecodedData(), __func__);
 }
 
 RefPtr<ShutdownPromise>
 H264Converter::Shutdown()
 {
-  mInitPromiseRequest.DisconnectIfExists();
+  mCreateDecoderRequest.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) {
     RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
     return decoder->Shutdown();
@@ -171,108 +192,54 @@ H264Converter::SetSeekThreshold(const me
 {
   if (mDecoder) {
     mDecoder->SetSeekThreshold(aTime);
   } else {
     MediaDataDecoder::SetSeekThreshold(aTime);
   }
 }
 
-nsresult
-H264Converter::CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics)
+bool
+H264Converter::CanCreateDecoder(MediaByteBuffer* aExtraData)
 {
-  if (!mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.mExtraData)) {
+  if (!mp4_demuxer::AnnexB::HasSPS(aExtraData)) {
     // nothing found yet, will try again later
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  UpdateConfigFromExtraData(mCurrentConfig.mExtraData);
-
-  mp4_demuxer::SPSData spsdata;
-  if (mp4_demuxer::H264::DecodeSPSFromExtraData(mCurrentConfig.mExtraData, spsdata)) {
-    // Do some format check here.
-    // WMF H.264 Video Decoder and Apple ATDecoder do not support YUV444 format.
-    if (spsdata.profile_idc == 244 /* Hi444PP */
-        || spsdata.chroma_format_idc == PDMFactory::kYUV444) {
-      mLastError = NS_ERROR_FAILURE;
-      if (aDiagnostics) {
-        aDiagnostics->SetVideoNotSupported();
-      }
-      return NS_ERROR_FAILURE;
-    }
-  } else {
-    // SPS was invalid.
-    mLastError = NS_ERROR_FAILURE;
-    return NS_ERROR_FAILURE;
+    return true;
   }
 
-  mDecoder = mPDM->CreateVideoDecoder({
-    mUseOriginalConfig ? mOriginalConfig : mCurrentConfig,
-    mTaskQueue,
-    aDiagnostics,
-    mImageContainer,
-    mKnowsCompositor,
-    mGMPCrashHelper,
-    mType,
-    mOnWaitingForKeyEvent,
-    mDecoderOptions
-  });
-
-  if (!mDecoder) {
-    mLastError = NS_ERROR_FAILURE;
-    return NS_ERROR_FAILURE;
+  mp4_demuxer::SPSData spsdata;
+  if (!mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata)) {
+    // SPS was invalid.
+    return false;
   }
 
-  mUseOriginalConfig = false;
-  mNeedKeyframe = true;
-
-  return NS_OK;
-}
-
-nsresult
-H264Converter::CreateDecoderAndInit(MediaRawData* aSample)
-{
-  RefPtr<MediaByteBuffer> extra_data =
-    mp4_demuxer::AnnexB::ExtractExtraData(aSample);
-  if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
-    return NS_ERROR_NOT_INITIALIZED;
-  }
-  UpdateConfigFromExtraData(extra_data);
-
-  nsresult rv = CreateDecoder(/* DecoderDoctorDiagnostics* */ nullptr);
-
-  if (NS_SUCCEEDED(rv)) {
-    // Queue the incoming sample.
-    mPendingSample = aSample;
-
-    mDecoder->Init()
-      ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__, this,
-             &H264Converter::OnDecoderInitDone,
-             &H264Converter::OnDecoderInitFailed)
-      ->Track(mInitPromiseRequest);
-    return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER;
-  }
-  return rv;
+  return UpdateConfigFromExtraData(aExtraData);
 }
 
 void
-H264Converter::OnDecoderInitDone(const TrackType aTrackType)
+H264Converter::CreateDecoderAndDecodeFirstSample(MediaRawData* aSample)
 {
-  mInitPromiseRequest.Complete();
-  RefPtr<MediaRawData> sample = mPendingSample.forget();
-  DecodeFirstSample(sample);
-}
+  MOZ_ASSERT(!mDecodePromise.IsEmpty());
 
-void
-H264Converter::OnDecoderInitFailed(const MediaResult& aError)
-{
-  mInitPromiseRequest.Complete();
-  mDecodePromise.Reject(
-    MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
-                RESULT_DETAIL("Unable to initialize H264 decoder")),
-    __func__);
+  RefPtr<H264Converter> self = this;
+  RefPtr<MediaRawData> sample = aSample;
+  CreateVideoDecoder()
+    ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
+      [self, sample] (RefPtr<MediaDataDecoder> aDecoder) {
+        self->mDecoder = aDecoder;
+        self->mCreateDecoderRequest.Complete();
+        self->DecodeFirstSample(sample);
+      }, [self] () {
+        self->mCreateDecoderRequest.Complete();
+        self->mDecodePromise.Reject(
+          MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                      RESULT_DETAIL("Unable to create H264 decoder")),
+          __func__);
+      })
+    ->Track(mCreateDecoderRequest);
 }
 
 void
 H264Converter::DecodeFirstSample(MediaRawData* aSample)
 {
   if (mNeedKeyframe && !aSample->mKeyframe) {
     mDecodePromise.Resolve(DecodedData(), __func__);
     return;
@@ -302,102 +269,101 @@ H264Converter::DecodeFirstSample(MediaRa
            },
            [self, this](const MediaResult& aError) {
              mDecodePromiseRequest.Complete();
              mDecodePromise.Reject(aError, __func__);
            })
     ->Track(mDecodePromiseRequest);
 }
 
-nsresult
-H264Converter::CheckForSPSChange(MediaRawData* aSample)
+
+bool
+H264Converter::IsSPSChanged(MediaRawData* aSample) const
 {
   RefPtr<MediaByteBuffer> extra_data =
     mp4_demuxer::AnnexB::ExtractExtraData(aSample);
-  if (!mp4_demuxer::AnnexB::HasSPS(extra_data)
-      || mp4_demuxer::AnnexB::CompareExtraData(extra_data,
-                                               mCurrentConfig.mExtraData)) {
-        return NS_OK;
-      }
-
-  RefPtr<MediaRawData> sample = aSample;
+  return (mp4_demuxer::AnnexB::HasSPS(extra_data) &&
+          !mp4_demuxer::AnnexB::CompareExtraData(extra_data,
+                                                 mCurrentConfig.mExtraData));
+}
 
-  if (CanRecycleDecoder()) {
-    // Do not recreate the decoder, reuse it.
-    UpdateConfigFromExtraData(extra_data);
-    // Ideally we would want to drain the decoder instead of flushing it.
-    // However the draining operation requires calling Drain and looping several
-    // times which isn't possible from within the H264Converter. So instead we
-    // flush the decoder. In practice, this is a no-op as SPS change will only
-    // be used with MSE. And with MSE, the MediaFormatReader would have drained
-    // the decoder already.
-    RefPtr<H264Converter> self = this;
-    mDecoder->Flush()
-      ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
-             __func__,
-             [self, sample, this]() {
-               mFlushRequest.Complete();
-               DecodeFirstSample(sample);
-             },
-             [self, this](const MediaResult& aError) {
-               mFlushRequest.Complete();
-               mDecodePromise.Reject(aError, __func__);
-             })
-      ->Track(mFlushRequest);
-    mNeedKeyframe = true;
-    // This is not really initializing the decoder, but it will do as it
-    // indicates an operation is pending.
-    return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER;
+RefPtr<MediaDataDecoder::DecodePromise>
+H264Converter::RecycleOrRecreateDecoder(MediaRawData* aSample)
+{
+  RefPtr<MediaRawData> sample = aSample;
+  RefPtr<MediaDataDecoder::DecodePromise> promise =
+    mDecodePromise.Ensure(__func__);
+
+  RefPtr<MediaByteBuffer> extra_data =
+    mp4_demuxer::AnnexB::ExtractExtraData(aSample);
+
+  // Check whether the decoder supports new sps.
+  if (!UpdateConfigFromExtraData(extra_data)) {
+    return DecodePromise::CreateAndReject(
+      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                  RESULT_DETAIL("Unable to create or recycle H264 decoder")),
+      __func__);
   }
 
-  // The SPS has changed, signal to flush the current decoder and create a
-  // new one.
+  // The SPS has changed, signal to flush the current decoder and then create a
+  // new one or recycle the old decoder.
   RefPtr<H264Converter> self = this;
   mDecoder->Flush()
-    ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
-           __func__,
-           [self, sample, this]() {
-             mFlushRequest.Complete();
-             mShutdownPromise = Shutdown();
-             mShutdownPromise
-               ->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
-                      __func__,
-                      [self, sample, this]() {
-                        mShutdownRequest.Complete();
-                        mShutdownPromise = nullptr;
-                        mNeedAVCC.reset();
-                        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;
+  ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
+    [self, sample, this]() {
+      mFlushRequest.Complete();
+      if (CanRecycleDecoder()) {
+        DecodeFirstSample(sample);
+      } else {
+        mShutdownPromise = Shutdown();
+        mShutdownPromise
+        ->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
+          [self, sample, this]() {
+            mShutdownRequest.Complete();
+            mShutdownPromise = nullptr;
+            mNeedAVCC.reset();
+            CreateDecoderAndDecodeFirstSample(sample);
+          },
+          [] { MOZ_CRASH("Can't reach here'"); })
+        ->Track(mShutdownRequest);
+      }
+    },
+    [self, this](const MediaResult& aError) {
+      mFlushRequest.Complete();
+      mDecodePromise.Reject(aError, __func__);
+    })
+  ->Track(mFlushRequest);
+
+  return promise.forget();
 }
 
-void
+bool
+H264Converter::IsUnSupportedSPSFormat(mp4_demuxer::SPSData aSPS) const
+{
+  // WMF H.264 Video Decoder and Apple ATDecoder do not support YUV444 format.
+  return (aSPS.profile_idc == 244 /* Hi444PP */ ||
+          aSPS.chroma_format_idc == PDMFactory::kYUV444);
+}
+
+bool
 H264Converter::UpdateConfigFromExtraData(MediaByteBuffer* aExtraData)
 {
   mp4_demuxer::SPSData spsdata;
   if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata)
       && spsdata.pic_width > 0
       && spsdata.pic_height > 0) {
     mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
+    if (IsUnSupportedSPSFormat(spsdata)) {
+      if (mDiagnostics) {
+        mDiagnostics->SetVideoNotSupported();
+      }
+      return false;
+    }
     mCurrentConfig.mImage.width = spsdata.pic_width;
     mCurrentConfig.mImage.height = spsdata.pic_height;
     mCurrentConfig.mDisplay.width = spsdata.display_width;
     mCurrentConfig.mDisplay.height = spsdata.display_height;
   }
   mCurrentConfig.mExtraData = aExtraData;
+  return true;
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_H264Converter_h
 #define mozilla_H264Converter_h
 
 #include "PlatformDecoderModule.h"
 #include "mozilla/Maybe.h"
+#include "mp4_demuxer/H264.h"
 
 namespace mozilla {
 
 // H264Converter is a MediaDataDecoder wrapper used to ensure that
 // only AVCC or AnnexB is fed to the underlying MediaDataDecoder.
 // The H264Converter allows playback of content where the SPS NAL may not be
 // provided in the init segment (e.g. AVC3 or Annex B)
 // H264Converter will monitor the input data, and will delay creation of the
@@ -22,16 +23,19 @@ namespace mozilla {
 class H264Converter : public MediaDataDecoder
 {
 public:
 
   H264Converter(PlatformDecoderModule* aPDM,
                 const CreateDecoderParams& aParams);
   virtual ~H264Converter();
 
+  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+  CreateVideoDecoder();
+
   RefPtr<InitPromise> Init() override;
   RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
   const char* GetDescriptionName() const override
   {
@@ -57,60 +61,56 @@ public:
   ConversionRequired NeedsConversion() const override
   {
     if (mDecoder) {
       return mDecoder->NeedsConversion();
     }
     // Default so no conversion is performed.
     return ConversionRequired::kNeedAVCC;
   }
-  nsresult GetLastError() const { return mLastError; }
 
 private:
-  // Will create the required MediaDataDecoder if need AVCC and we have a SPS NAL.
-  // Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
-  // will set mError accordingly.
-  nsresult CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics);
-  nsresult CreateDecoderAndInit(MediaRawData* aSample);
-  nsresult CheckForSPSChange(MediaRawData* aSample);
-  void UpdateConfigFromExtraData(MediaByteBuffer* aExtraData);
+  bool CanCreateDecoder(mozilla::MediaByteBuffer* aExtraData);
+  void CreateDecoderAndDecodeFirstSample(MediaRawData* aSample);
+  RefPtr<DecodePromise> RecycleOrRecreateDecoder(MediaRawData* aSample);
+  void DecodeFirstSample(MediaRawData* aSample);
 
-  void OnDecoderInitDone(const TrackType aTrackType);
-  void OnDecoderInitFailed(const MediaResult& aError);
+  bool UpdateConfigFromExtraData(mozilla::MediaByteBuffer* aExtraData);
 
   bool CanRecycleDecoder() const
   {
     MOZ_ASSERT(mDecoder);
     return MediaPrefs::MediaDecoderCheckRecycling()
            && mDecoder->SupportDecoderRecycling();
   }
 
-  void DecodeFirstSample(MediaRawData* aSample);
+  bool IsSPSChanged(MediaRawData* aSample) const;
+  bool IsUnSupportedSPSFormat(mp4_demuxer::SPSData aSPS) const;
 
   RefPtr<PlatformDecoderModule> mPDM;
   const VideoInfo mOriginalConfig;
   VideoInfo mCurrentConfig;
   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;
 
+  MozPromiseRequestHolder<PlatformDecoderModule::CreateDecoderPromise> mCreateDecoderRequest;
+
   RefPtr<GMPCrashHelper> mGMPCrashHelper;
   Maybe<bool> mNeedAVCC;
-  nsresult mLastError;
   bool mNeedKeyframe = true;
   // Set to true once a decoder has been created.
   bool mUseOriginalConfig = true;
   const TrackInfo::TrackType mType;
   MediaEventProducer<TrackInfo::TrackType>* const mOnWaitingForKeyEvent;
   const CreateDecoderParams::OptionSet mDecoderOptions;
+  DecoderDoctorDiagnostics* mDiagnostics;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_H264Converter_h