Backed out 13 changesets (bug 1672072) for short.mp4.firstframe.html failures CLOSED TREE
authorBogdan Tara <btara@mozilla.com>
Fri, 13 Nov 2020 06:13:22 +0200
changeset 557068 23b8e2facfb9860427b51b8fbad686def2d2ac29
parent 557067 d70bf7b7cef939d678ab162b5ae2725cee322f78
child 557069 67f5a42ed17014389c80fb6ebf415b707dc39753
push id37946
push userdluca@mozilla.com
push dateFri, 13 Nov 2020 09:59:41 +0000
treeherdermozilla-central@7bc610418605 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1672072
milestone84.0a1
backs outf093b7969e8b823a98edd7564f5458d61dafb137
28db8276ec2b737102f8c5796d1c52adc59d5274
ff8fe1b856b353d722ccc554b6585cf70ead4e51
091b9449c7867ddef4ca1b1ca1bd3013dc7080eb
89d9a12c073704033395a23be8ecd74352d44b90
9cb71fd4b43b47ffaf516a605a170b78b14111f0
09adad7416e19b7fb06f95b26b23818f3b71fc87
9905650335efebb95edc63af1e76d28b934000a5
6f1d99e9c3a1c49f11c1f868ccd8650b17391a08
b59655b7a59599068cc36187574600727aa04848
1ef9d6d105080ec0b6dfb4ce73fac9ba53ec9c29
fbf0b51176552b077a35b38bf735a08ad9983832
65cd3b9de5c62074365502372b5b17deafe38088
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
Backed out 13 changesets (bug 1672072) for short.mp4.firstframe.html failures CLOSED TREE Backed out changeset f093b7969e8b (bug 1672072) Backed out changeset 28db8276ec2b (bug 1672072) Backed out changeset ff8fe1b856b3 (bug 1672072) Backed out changeset 091b9449c786 (bug 1672072) Backed out changeset 89d9a12c0737 (bug 1672072) Backed out changeset 9cb71fd4b43b (bug 1672072) Backed out changeset 09adad7416e1 (bug 1672072) Backed out changeset 9905650335ef (bug 1672072) Backed out changeset 6f1d99e9c3a1 (bug 1672072) Backed out changeset b59655b7a595 (bug 1672072) Backed out changeset 1ef9d6d10508 (bug 1672072) Backed out changeset fbf0b5117655 (bug 1672072) Backed out changeset 65cd3b9de5c6 (bug 1672072)
dom/media/Benchmark.cpp
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
dom/media/ipc/IRemoteDecoderChild.h
dom/media/ipc/PRemoteDecoder.ipdl
dom/media/ipc/PRemoteDecoderManager.ipdl
dom/media/ipc/RDDProcessManager.cpp
dom/media/ipc/RDDProcessManager.h
dom/media/ipc/RemoteAudioDecoder.cpp
dom/media/ipc/RemoteAudioDecoder.h
dom/media/ipc/RemoteDecoderChild.cpp
dom/media/ipc/RemoteDecoderChild.h
dom/media/ipc/RemoteDecoderManagerChild.cpp
dom/media/ipc/RemoteDecoderManagerChild.h
dom/media/ipc/RemoteDecoderManagerParent.cpp
dom/media/ipc/RemoteDecoderManagerParent.h
dom/media/ipc/RemoteDecoderModule.cpp
dom/media/ipc/RemoteDecoderModule.h
dom/media/ipc/RemoteDecoderParent.cpp
dom/media/ipc/RemoteDecoderParent.h
dom/media/ipc/RemoteMediaDataDecoder.cpp
dom/media/ipc/RemoteMediaDataDecoder.h
dom/media/ipc/RemoteVideoDecoder.cpp
dom/media/ipc/RemoteVideoDecoder.h
dom/media/ipc/moz.build
dom/media/platforms/AllocationPolicy.cpp
dom/media/platforms/PDMFactory.cpp
dom/media/platforms/PDMFactory.h
dom/media/platforms/PlatformDecoderModule.cpp
dom/media/platforms/PlatformDecoderModule.h
dom/media/platforms/agnostic/AOMDecoder.h
dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
dom/media/platforms/agnostic/DAV1DDecoder.h
dom/media/platforms/agnostic/OpusDecoder.cpp
dom/media/platforms/agnostic/OpusDecoder.h
dom/media/platforms/agnostic/TheoraDecoder.h
dom/media/platforms/agnostic/VPXDecoder.h
dom/media/platforms/agnostic/VorbisDecoder.cpp
dom/media/platforms/agnostic/VorbisDecoder.h
dom/media/platforms/agnostic/WAVDecoder.cpp
dom/media/platforms/agnostic/WAVDecoder.h
dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
dom/media/platforms/agnostic/eme/EMEDecoderModule.h
dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp
dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h
dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
dom/media/platforms/android/AndroidDecoderModule.cpp
dom/media/platforms/android/RemoteDataDecoder.h
dom/media/platforms/apple/AppleATDecoder.cpp
dom/media/platforms/apple/AppleATDecoder.h
dom/media/platforms/apple/AppleDecoderModule.cpp
dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
dom/media/platforms/moz.build
dom/media/platforms/omx/OmxDataDecoder.cpp
dom/media/platforms/wrappers/AudioTrimmer.cpp
dom/media/platforms/wrappers/MediaChangeMonitor.cpp
dom/media/platforms/wrappers/MediaChangeMonitor.h
dom/media/webaudio/MediaBufferDecoder.cpp
dom/media/webrtc/libwebrtcglue/MediaDataCodec.cpp
dom/media/webrtc/libwebrtcglue/WebrtcMediaDataDecoderCodec.cpp
dom/media/webrtc/libwebrtcglue/WebrtcMediaDataDecoderCodec.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
ipc/ipdl/sync-messages.ini
mfbt/WeakPtr.h
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -242,31 +242,30 @@ void BenchmarkPlayback::InitDecoder(Uniq
 
   if (!aInfo) {
     Error(MediaResult(NS_ERROR_FAILURE, "Invalid TrackInfo"));
     return;
   }
 
   RefPtr<PDMFactory> platform = new PDMFactory();
   mInfo = std::move(aInfo);
+  RefPtr<MediaDataDecoder> decoder =
+      platform->CreateDecoder(CreateDecoderParams{*mInfo});
+
+  if (!decoder) {
+    Error(MediaResult(NS_ERROR_FAILURE, "Failed to create decoder"));
+    return;
+  }
+  mDecoder = new MediaDataDecoderProxy(decoder.forget(),
+                                       do_AddRef(mDecoderTaskQueue.get()));
   RefPtr<Benchmark> ref(mGlobalState);
-  platform->CreateDecoder(CreateDecoderParams{*mInfo})
-      ->Then(
-          Thread(), __func__,
-          [this, ref](RefPtr<MediaDataDecoder>&& aDecoder) {
-            mDecoder = new MediaDataDecoderProxy(
-                aDecoder.forget(), do_AddRef(mDecoderTaskQueue.get()));
-            mDecoder->Init()->Then(
-                Thread(), __func__,
-                [this, ref](TrackInfo::TrackType aTrackType) {
-                  InputExhausted();
-                },
-                [this, ref](const MediaResult& aError) { Error(aError); });
-          },
-          [this, ref](const MediaResult& aError) { Error(aError); });
+  mDecoder->Init()->Then(
+      Thread(), __func__,
+      [this, ref](TrackInfo::TrackType aTrackType) { InputExhausted(); },
+      [this, ref](const MediaResult& aError) { Error(aError); });
 }
 
 void BenchmarkPlayback::FinalizeShutdown() {
   MOZ_ASSERT(OnThread());
 
   MOZ_ASSERT(mFinished, "GlobalShutdown must have been run");
   MOZ_ASSERT(!mDecoder, "mDecoder must have been shutdown already");
   MOZ_ASSERT(!mDemuxer, "mDemuxer must have been shutdown already");
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -204,17 +204,16 @@ void MediaFormatReader::DecoderData::Flu
   }
   mFlushed = true;
 }
 
 class MediaFormatReader::DecoderFactory {
   using InitPromise = MediaDataDecoder::InitPromise;
   using TokenPromise = AllocPolicy::Promise;
   using Token = AllocPolicy::Token;
-  using CreateDecoderPromise = PlatformDecoderModule::CreateDecoderPromise;
 
  public:
   explicit DecoderFactory(MediaFormatReader* aOwner)
       : mAudio(aOwner->mAudio, TrackInfo::kAudioTrack, aOwner->OwnerThread()),
         mVideo(aOwner->mVideo, TrackInfo::kVideoTrack, aOwner->OwnerThread()),
         mOwner(WrapNotNull(aOwner)) {
     DecoderDoctorLogger::LogConstruction("MediaFormatReader::DecoderFactory",
                                          this);
@@ -232,33 +231,16 @@ class MediaFormatReader::DecoderFactory 
   // Shutdown any decoder pending initialization and reset mAudio/mVideo to its
   // 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();
-    if (data.mLiveToken) {
-      // We haven't completed creation of the decoder, and it hasn't been
-      // initialised yet.
-      data.mLiveToken = nullptr;
-      // The decoder will be shutdown as soon as it's available and tracked by
-      // the ShutdownPromisePool.
-      mOwner->mShutdownPromisePool->Track(data.mCreateDecoderPromise->Then(
-          mOwner->mTaskQueue, __func__,
-          [](CreateDecoderPromise::ResolveOrRejectValue&& aResult) {
-            if (aResult.IsReject()) {
-              return ShutdownPromise::CreateAndResolve(true, __func__);
-            }
-            return aResult.ResolveValue()->Shutdown();
-          }));
-      // Free the token to leave room for a new decoder.
-      data.mToken = nullptr;
-    }
     data.mInitRequest.DisconnectIfExists();
     if (data.mDecoder) {
       mOwner->mShutdownPromisePool->ShutdownDecoder(data.mDecoder.forget());
     }
     data.mStage = Stage::None;
     MOZ_ASSERT(!data.mToken);
   }
 
@@ -272,31 +254,21 @@ class MediaFormatReader::DecoderFactory 
           mPolicy(new SingleAllocPolicy(aTrack, aThread)) {}
     DecoderData& mOwnerData;
     const TrackType mTrack;
     RefPtr<SingleAllocPolicy> mPolicy;
     Stage mStage = Stage::None;
     RefPtr<Token> mToken;
     RefPtr<MediaDataDecoder> mDecoder;
     MozPromiseRequestHolder<TokenPromise> mTokenRequest;
-    struct DecoderCancelled : public SupportsWeakPtr {
-      NS_INLINE_DECL_REFCOUNTING_ONEVENTTARGET(DecoderCancelled)
-     private:
-      ~DecoderCancelled() = default;
-    };
-    // Set when decoder is about to be created. If cleared before the decoder
-    // creation promise is resolved; it indicates that Shutdown() was called and
-    // further processing such as initialization should stop.
-    RefPtr<DecoderCancelled> mLiveToken;
-    RefPtr<CreateDecoderPromise> mCreateDecoderPromise;
     MozPromiseRequestHolder<InitPromise> mInitRequest;
   } mAudio, mVideo;
 
   void RunStage(Data& aData);
-  void DoCreateDecoder(Data& aData);
+  MediaResult DoCreateDecoder(Data& aData);
   void DoInitDecoder(Data& aData);
 
   // guaranteed to be valid by the owner.
   const NotNull<MediaFormatReader*> mOwner;
 };
 
 void MediaFormatReader::DecoderFactory::CreateDecoder(TrackType aTrack) {
   MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
@@ -332,126 +304,122 @@ void MediaFormatReader::DecoderFactory::
       break;
     }
 
     case Stage::CreateDecoder: {
       MOZ_ASSERT(aData.mToken);
       MOZ_ASSERT(!aData.mDecoder);
       MOZ_ASSERT(!aData.mInitRequest.Exists());
 
-      DoCreateDecoder(aData);
+      MediaResult rv = DoCreateDecoder(aData);
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Error constructing decoders");
+        aData.mToken = nullptr;
+        aData.mStage = Stage::None;
+        aData.mOwnerData.mDescription = rv.Description();
+        DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
+                 "create_decoder_error", rv);
+        mOwner->NotifyError(aData.mTrack, rv);
+        return;
+      }
+
+      aData.mDecoder =
+          new AllocationWrapper(aData.mDecoder.forget(), aData.mToken.forget());
+      DecoderDoctorLogger::LinkParentAndChild(
+          aData.mDecoder.get(), "decoder", "MediaFormatReader::DecoderFactory",
+          this);
+
+      DoInitDecoder(aData);
       aData.mStage = Stage::WaitForInit;
       break;
     }
 
     case Stage::WaitForInit: {
-      MOZ_ASSERT((aData.mDecoder && aData.mInitRequest.Exists()) ||
-                 aData.mLiveToken);
+      MOZ_ASSERT(aData.mDecoder);
+      MOZ_ASSERT(aData.mInitRequest.Exists());
       break;
     }
   }
 }
 
-void MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData) {
+MediaResult MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData) {
   AUTO_PROFILER_LABEL("DecoderFactory::DoCreateDecoder", MEDIA_PLAYBACK);
   auto& ownerData = aData.mOwnerData;
   auto& decoder = mOwner->GetDecoderData(aData.mTrack);
   auto& platform =
       decoder.IsEncrypted() ? mOwner->mEncryptedPlatform : mOwner->mPlatform;
 
   if (!platform) {
     platform = new PDMFactory();
     if (decoder.IsEncrypted()) {
       MOZ_ASSERT(mOwner->mCDMProxy);
       platform->SetCDMProxy(mOwner->mCDMProxy);
     }
   }
 
-  RefPtr<PlatformDecoderModule::CreateDecoderPromise> p;
-  MediaFormatReader* owner = mOwner;
-  auto onWaitingForKeyEvent =
-      [owner = ThreadSafeWeakPtr<MediaFormatReader>(owner)]() {
-        RefPtr<MediaFormatReader> mfr(owner);
-        MOZ_DIAGNOSTIC_ASSERT(mfr, "The MediaFormatReader didn't wait for us");
-        return mfr ? &mfr->OnTrackWaitingForKeyProducer() : nullptr;
-      };
+  // result may not be updated by PDMFactory::CreateDecoder, as such it must be
+  // initialized to a fatal error by default.
+  MediaResult result =
+      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                  nsPrintfCString("error creating %s decoder",
+                                  TrackTypeToStr(aData.mTrack)));
 
   switch (aData.mTrack) {
     case TrackInfo::kAudioTrack: {
-      p = platform->CreateDecoder(
+      RefPtr<MediaDataDecoder> decoder = platform->CreateDecoder(
           {*ownerData.GetCurrentInfo()->GetAsAudioInfo(), mOwner->mCrashHelper,
            CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
-           TrackInfo::kAudioTrack, std::move(onWaitingForKeyEvent)});
+           &result, TrackInfo::kAudioTrack,
+           &mOwner->OnTrackWaitingForKeyProducer()});
+      if (!decoder) {
+        aData.mDecoder = nullptr;
+        break;
+      }
+      aData.mDecoder = new MediaDataDecoderProxy(
+          decoder.forget(), do_AddRef(ownerData.mTaskQueue.get()));
       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.
       using Option = CreateDecoderParams::Option;
       using OptionSet = CreateDecoderParams::OptionSet;
 
-      p = platform->CreateDecoder(
+      RefPtr<MediaDataDecoder> decoder = platform->CreateDecoder(
           {*ownerData.GetCurrentInfo()->GetAsVideoInfo(),
            mOwner->mKnowsCompositor, mOwner->GetImageContainer(),
            mOwner->mCrashHelper,
            CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
-           TrackType::kVideoTrack, std::move(onWaitingForKeyEvent),
+           &result, TrackType::kVideoTrack,
+           &mOwner->OnTrackWaitingForKeyProducer(),
            CreateDecoderParams::VideoFrameRate(ownerData.mMeanRate.Mean()),
            OptionSet(ownerData.mHardwareDecodingDisabled
                          ? Option::HardwareDecoderNotAllowed
                          : Option::Default)});
+      if (!decoder) {
+        aData.mDecoder = nullptr;
+        break;
+      }
+      aData.mDecoder = new MediaDataDecoderProxy(
+          decoder.forget(), do_AddRef(ownerData.mTaskQueue.get()));
       break;
     }
 
     default:
-      p = PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-          NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
+      break;
   }
 
-  aData.mLiveToken = MakeRefPtr<Data::DecoderCancelled>();
-
-  aData.mCreateDecoderPromise = p->Then(
-      mOwner->OwnerThread(), __func__,
-      [this, &aData, &ownerData, live = WeakPtr{aData.mLiveToken},
-       owner = ThreadSafeWeakPtr<MediaFormatReader>(owner)](
-          RefPtr<MediaDataDecoder>&& aDecoder) {
-        if (!live) {
-          return CreateDecoderPromise::CreateAndResolve(std::move(aDecoder),
-                                                        __func__);
-        }
-        aData.mLiveToken = nullptr;
-        aData.mDecoder = new MediaDataDecoderProxy(
-            aDecoder.forget(), do_AddRef(ownerData.mTaskQueue.get()));
-        aData.mDecoder = new AllocationWrapper(aData.mDecoder.forget(),
-                                               aData.mToken.forget());
-        DecoderDoctorLogger::LinkParentAndChild(
-            aData.mDecoder.get(), "decoder",
-            "MediaFormatReader::DecoderFactory", this);
-
-        DoInitDecoder(aData);
-
-        return CreateDecoderPromise::CreateAndResolve(aData.mDecoder, __func__);
-      },
-      [this, &aData,
-       live = WeakPtr{aData.mLiveToken}](const MediaResult& aError) {
-        NS_WARNING("Error constructing decoders");
-        if (!live) {
-          return CreateDecoderPromise::CreateAndReject(aError, __func__);
-        }
-        aData.mLiveToken = nullptr;
-        aData.mToken = nullptr;
-        aData.mStage = Stage::None;
-        aData.mOwnerData.mDescription = aError.Description();
-        DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
-                 "create_decoder_error", aError);
-        mOwner->NotifyError(aData.mTrack, aError);
-
-        return CreateDecoderPromise::CreateAndReject(aError, __func__);
-      });
+  if (aData.mDecoder) {
+    return NS_OK;
+  }
+
+  MOZ_RELEASE_ASSERT(NS_FAILED(result), "PDM returned an invalid error code");
+
+  return result;
 }
 
 void MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData) {
   AUTO_PROFILER_LABEL("DecoderFactory::DoInitDecoder", MEDIA_PLAYBACK);
   auto& ownerData = aData.mOwnerData;
 
   DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
            "initialize_decoder", DDNoValue{});
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -2,32 +2,32 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #if !defined(MediaFormatReader_h_)
 #  define MediaFormatReader_h_
 
-#  include "FrameStatistics.h"
-#  include "MediaDataDemuxer.h"
-#  include "MediaEventSource.h"
-#  include "MediaMetadataManager.h"
-#  include "MediaPromiseDefs.h"
-#  include "PDMFactory.h"
-#  include "SeekTarget.h"
 #  include "mozilla/Atomics.h"
 #  include "mozilla/Maybe.h"
 #  include "mozilla/Mutex.h"
 #  include "mozilla/StateMirroring.h"
 #  include "mozilla/StaticPrefs_media.h"
 #  include "mozilla/TaskQueue.h"
-#  include "mozilla/ThreadSafeWeakPtr.h"
 #  include "mozilla/dom/MediaDebugInfoBinding.h"
 
+#  include "FrameStatistics.h"
+#  include "MediaEventSource.h"
+#  include "MediaDataDemuxer.h"
+#  include "MediaMetadataManager.h"
+#  include "MediaPromiseDefs.h"
+#  include "PDMFactory.h"
+#  include "SeekTarget.h"
+
 namespace mozilla {
 
 class CDMProxy;
 class GMPCrashHelper;
 class MediaResource;
 class VideoFrameContainer;
 
 struct WaitForDataRejectValue {
@@ -65,26 +65,23 @@ struct MOZ_STACK_CLASS MediaFormatReader
   already_AddRefed<GMPCrashHelper> mCrashHelper;
   // Used in bug 1393399 for temporary telemetry.
   MediaDecoderOwnerID mMediaDecoderOwnerID = nullptr;
 };
 
 DDLoggedTypeDeclName(MediaFormatReader);
 
 class MediaFormatReader final
-    : public SupportsThreadSafeWeakPtr<MediaFormatReader>,
-      public DecoderDoctorLifeLogger<MediaFormatReader> {
+    : public DecoderDoctorLifeLogger<MediaFormatReader> {
   static const bool IsExclusive = true;
   typedef TrackInfo::TrackType TrackType;
   typedef MozPromise<bool, MediaResult, IsExclusive> NotifyDataArrivedPromise;
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaFormatReader)
 
  public:
-  MOZ_DECLARE_THREADSAFEWEAKREFERENCE_TYPENAME(MediaFormatReader)
-  MOZ_DECLARE_REFCOUNTED_TYPENAME(MediaFormatReader)
-
   using TrackSet = EnumSet<TrackInfo::TrackType>;
   using MetadataPromise = MozPromise<MetadataHolder, MediaResult, IsExclusive>;
 
   template <typename Type>
   using DataPromise = MozPromise<RefPtr<Type>, MediaResult, IsExclusive>;
   using AudioDataPromise = DataPromise<AudioData>;
   using VideoDataPromise = DataPromise<VideoData>;
 
@@ -93,17 +90,16 @@ class MediaFormatReader final
   // Note that, conceptually, WaitForData makes sense in a non-exclusive sense.
   // But in the current architecture it's only ever used exclusively (by MDSM),
   // so we mark it that way to verify our assumptions. If you have a use-case
   // for multiple WaitForData consumers, feel free to flip the exclusivity here.
   using WaitForDataPromise =
       MozPromise<MediaData::Type, WaitForDataRejectValue, IsExclusive>;
 
   MediaFormatReader(MediaFormatReaderInit& aInit, MediaDataDemuxer* aDemuxer);
-  virtual ~MediaFormatReader();
 
   // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
   // on failure.
   nsresult Init();
 
   size_t SizeOfVideoQueueInFrames();
   size_t SizeOfAudioQueueInFrames();
 
@@ -235,16 +231,18 @@ class MediaFormatReader final
 
   MediaEventSource<MediaResult>& OnDecodeWarning() { return mOnDecodeWarning; }
 
   MediaEventSource<VideoInfo>& OnStoreDecoderBenchmark() {
     return mOnStoreDecoderBenchmark;
   }
 
  private:
+  ~MediaFormatReader();
+
   bool HasVideo() const { return mVideo.mTrackDemuxer; }
   bool HasAudio() const { return mAudio.mTrackDemuxer; }
 
   bool IsWaitingOnCDMResource();
 
   bool InitDemuxer();
   // Notify the track demuxers that new data has been received.
   void NotifyTrackDemuxers();
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/IRemoteDecoderChild.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 include_dom_media_ipc_IRemoteDecoderChild_h
+#define include_dom_media_ipc_IRemoteDecoderChild_h
+
+#include "PlatformDecoderModule.h"
+#include "mozilla/TaskQueue.h"
+
+namespace mozilla {
+
+// This interface mirrors the MediaDataDecoder plus a bit (DestroyIPDL)
+// to allow proxying to a remote decoder in RemoteDecoderModule or
+// GpuDecoderModule. RemoteAudioDecoderChild, RemoteVideoDecoderChild,
+// and VideoDecoderChild (for GPU) implement this interface.
+class IRemoteDecoderChild {
+ public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IRemoteDecoderChild);
+
+  virtual RefPtr<MediaDataDecoder::InitPromise> Init() = 0;
+  virtual RefPtr<MediaDataDecoder::DecodePromise> Decode(
+      const nsTArray<RefPtr<MediaRawData>>& aSamples) = 0;
+  virtual RefPtr<MediaDataDecoder::DecodePromise> Drain() = 0;
+  virtual RefPtr<MediaDataDecoder::FlushPromise> Flush() = 0;
+  virtual RefPtr<ShutdownPromise> Shutdown() = 0;
+  virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const {
+    return false;
+  }
+  virtual nsCString GetDescriptionName() const = 0;
+  virtual void SetSeekThreshold(const media::TimeUnit& aTime) {}
+  virtual MediaDataDecoder::ConversionRequired NeedsConversion() const {
+    return MediaDataDecoder::ConversionRequired::kNeedNone;
+  }
+
+  virtual void DestroyIPDL() = 0;
+
+ protected:
+  virtual ~IRemoteDecoderChild() = default;
+};
+
+}  // namespace mozilla
+
+#endif  // include_dom_media_ipc_IRemoteDecoderChild_h
--- a/dom/media/ipc/PRemoteDecoder.ipdl
+++ b/dom/media/ipc/PRemoteDecoder.ipdl
@@ -51,18 +51,16 @@ union DecodeResultIPDL
 // RemoteDecoderModule or WindowsMediaFoundation.
 // The child side runs in the content process, and the parent side runs
 // in the RDD process or the GPU process. We run a separate IPDL thread
 // for both sides.
 async protocol PRemoteDecoder
 {
   manager PRemoteDecoderManager;
 parent:
-  async Construct() returns (MediaResult result);
-
   async Init() returns (InitResultIPDL result);
 
   // Each output may include 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 Decode(ArrayOfRemoteMediaRawData data) returns (DecodeResultIPDL result);
   async Flush() returns (MediaResult error);
--- a/dom/media/ipc/PRemoteDecoderManager.ipdl
+++ b/dom/media/ipc/PRemoteDecoderManager.ipdl
@@ -28,18 +28,20 @@ union RemoteDecoderInfoIPDL
   VideoDecoderInfoIPDL;
 };
 
 sync protocol PRemoteDecoderManager
 {
   manages PRemoteDecoder;
 
 parent:
-  async PRemoteDecoder(RemoteDecoderInfoIPDL info,
-                       OptionSet options,
-                       TextureFactoryIdentifier? identifier);
+  sync PRemoteDecoder(RemoteDecoderInfoIPDL info,
+                      OptionSet options,
+                      TextureFactoryIdentifier? identifier)
+         returns (bool success,
+                  nsCString aErrorDescription);
 
   sync Readback(SurfaceDescriptorGPUVideo sd) returns (SurfaceDescriptor aResult);
 
   async DeallocateSurfaceDescriptorGPUVideo(SurfaceDescriptorGPUVideo sd);
 };
 
 } // namespace mozilla
--- a/dom/media/ipc/RDDProcessManager.cpp
+++ b/dom/media/ipc/RDDProcessManager.cpp
@@ -94,59 +94,54 @@ void RDDProcessManager::OnPreferenceChan
   if (!!mRDDChild) {
     MOZ_ASSERT(mQueuedPrefs.IsEmpty());
     mRDDChild->SendPreferenceUpdate(pref);
   } else if (IsRDDProcessLaunching()) {
     mQueuedPrefs.AppendElement(pref);
   }
 }
 
-auto RDDProcessManager::EnsureRDDProcessAndCreateBridge(
-    base::ProcessId aOtherProcess) -> RefPtr<EnsureRDDPromise> {
-  return InvokeAsync(GetMainThreadSerialEventTarget(), __func__,
-                     [aOtherProcess, this]() -> RefPtr<EnsureRDDPromise> {
-                       if (!Get()) {
-                         // Shutdown?
-                         return EnsureRDDPromise::CreateAndReject(
-                             NS_ERROR_NOT_AVAILABLE, __func__);
-                       }
-                       if (mProcess) {
-                         ipc::Endpoint<PRemoteDecoderManagerChild> endpoint;
-                         if (!CreateContentBridge(aOtherProcess, &endpoint)) {
-                           return EnsureRDDPromise::CreateAndReject(
-                               NS_ERROR_NOT_AVAILABLE, __func__);
-                         }
-                         return EnsureRDDPromise::CreateAndResolve(
-                             std::move(endpoint), __func__);
-                       }
+bool RDDProcessManager::EnsureRDDProcessAndCreateBridge(
+    base::ProcessId aOtherProcess,
+    mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>*
+        aOutRemoteDecoderManager) {
+  bool success = false;
 
-                       mNumProcessAttempts++;
+  RefPtr<Runnable> task =
+      NS_NewRunnableFunction("RDDProcessManager::RDDProcessManager", [&]() {
+        if (mProcess) {
+          success =
+              CreateContentBridge(aOtherProcess, aOutRemoteDecoderManager);
+          return;
+        }
+
+        mNumProcessAttempts++;
 
-                       std::vector<std::string> extraArgs;
-                       nsCString parentBuildID(mozilla::PlatformBuildID());
-                       extraArgs.push_back("-parentBuildID");
-                       extraArgs.push_back(parentBuildID.get());
+        std::vector<std::string> extraArgs;
+        nsCString parentBuildID(mozilla::PlatformBuildID());
+        extraArgs.push_back("-parentBuildID");
+        extraArgs.push_back(parentBuildID.get());
 
-                       // The subprocess is launched asynchronously, so we wait
-                       // for a callback to acquire the IPDL actor.
-                       mProcess = new RDDProcessHost(this);
-                       if (!mProcess->Launch(extraArgs)) {
-                         DestroyProcess();
-                         return EnsureRDDPromise::CreateAndReject(
-                             NS_ERROR_NOT_AVAILABLE, __func__);
-                       }
-                       ipc::Endpoint<PRemoteDecoderManagerChild> endpoint;
-                       if (!EnsureRDDReady() || !CreateVideoBridge() ||
-                           !CreateContentBridge(aOtherProcess, &endpoint)) {
-                         return EnsureRDDPromise::CreateAndReject(
-                             NS_ERROR_NOT_AVAILABLE, __func__);
-                       }
-                       return EnsureRDDPromise::CreateAndResolve(
-                           std::move(endpoint), __func__);
-                     });
+        // The subprocess is launched asynchronously, so we wait for a callback
+        // to acquire the IPDL actor.
+        mProcess = new RDDProcessHost(this);
+        if (!mProcess->Launch(extraArgs)) {
+          DestroyProcess();
+          return;
+        }
+        if (!EnsureRDDReady()) {
+          return;
+        }
+
+        success = CreateVideoBridge() &&
+                  CreateContentBridge(aOtherProcess, aOutRemoteDecoderManager);
+      });
+  SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), task);
+
+  return success;
 }
 
 bool RDDProcessManager::IsRDDProcessLaunching() {
   MOZ_ASSERT(NS_IsMainThread());
   return !!mProcess && !mRDDChild;
 }
 
 bool RDDProcessManager::EnsureRDDReady() {
@@ -237,33 +232,37 @@ void RDDProcessManager::DestroyProcess()
 
   CrashReporter::AnnotateCrashReport(
       CrashReporter::Annotation::RDDProcessStatus, "Destroyed"_ns);
 }
 
 bool RDDProcessManager::CreateContentBridge(
     base::ProcessId aOtherProcess,
     ipc::Endpoint<PRemoteDecoderManagerChild>* aOutRemoteDecoderManager) {
-  MOZ_ASSERT(NS_IsMainThread());
-
-  ipc::Endpoint<PRemoteDecoderManagerParent> parentPipe;
-  ipc::Endpoint<PRemoteDecoderManagerChild> childPipe;
+  bool success = false;
+  RefPtr<Runnable> task =
+      NS_NewRunnableFunction("RDDProcessManager::RDDProcessManager", [&]() {
+        ipc::Endpoint<PRemoteDecoderManagerParent> parentPipe;
+        ipc::Endpoint<PRemoteDecoderManagerChild> childPipe;
 
-  nsresult rv = PRemoteDecoderManager::CreateEndpoints(
-      mRDDChild->OtherPid(), aOtherProcess, &parentPipe, &childPipe);
-  if (NS_FAILED(rv)) {
-    MOZ_LOG(sPDMLog, LogLevel::Debug,
-            ("Could not create content remote decoder: %d", int(rv)));
-    return false;
-  }
+        nsresult rv = PRemoteDecoderManager::CreateEndpoints(
+            mRDDChild->OtherPid(), aOtherProcess, &parentPipe, &childPipe);
+        if (NS_FAILED(rv)) {
+          MOZ_LOG(sPDMLog, LogLevel::Debug,
+                  ("Could not create content remote decoder: %d", int(rv)));
+          return;
+        }
 
-  mRDDChild->SendNewContentRemoteDecoderManager(std::move(parentPipe));
+        mRDDChild->SendNewContentRemoteDecoderManager(std::move(parentPipe));
 
-  *aOutRemoteDecoderManager = std::move(childPipe);
-  return true;
+        *aOutRemoteDecoderManager = std::move(childPipe);
+        success = true;
+      });
+  SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), task);
+  return success;
 }
 
 bool RDDProcessManager::CreateVideoBridge() {
   MOZ_ASSERT(NS_IsMainThread());
   ipc::Endpoint<PVideoBridgeParent> parentPipe;
   ipc::Endpoint<PVideoBridgeChild> childPipe;
 
   GPUProcessManager* gpuManager = GPUProcessManager::Get();
--- a/dom/media/ipc/RDDProcessManager.h
+++ b/dom/media/ipc/RDDProcessManager.h
@@ -1,44 +1,49 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 _include_dom_media_ipc_RDDProcessManager_h_
 #define _include_dom_media_ipc_RDDProcessManager_h_
-#include "mozilla/MozPromise.h"
-#include "mozilla/PRemoteDecoderManagerChild.h"
 #include "mozilla/RDDProcessHost.h"
 #include "mozilla/ipc/TaskFactory.h"
 
 namespace mozilla {
 
 class MemoryReportingProcess;
+class PRemoteDecoderManagerChild;
 class RDDChild;
 
 // The RDDProcessManager is a singleton responsible for creating RDD-bound
 // objects that may live in another process. Currently, it provides access
 // to the RDD process via ContentParent.
 class RDDProcessManager final : public RDDProcessHost::Listener {
   friend class RDDChild;
 
  public:
   static void Initialize();
   static void Shutdown();
   static RDDProcessManager* Get();
 
   ~RDDProcessManager();
 
-  using EnsureRDDPromise =
-      MozPromise<ipc::Endpoint<PRemoteDecoderManagerChild>, nsresult, true>;
   // If not using a RDD process, launch a new RDD process asynchronously and
   // create a RemoteDecoderManager bridge
-  RefPtr<EnsureRDDPromise> EnsureRDDProcessAndCreateBridge(
-      base::ProcessId aOtherProcess);
+  bool EnsureRDDProcessAndCreateBridge(
+      base::ProcessId aOtherProcess,
+      mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>*
+          aOutRemoteDecoderManager);
+  bool IsRDDProcessLaunching();
+
+  // Ensure that RDD-bound methods can be used. If no RDD process is being
+  // used, or one is launched and ready, this function returns immediately.
+  // Otherwise it blocks until the RDD process has finished launching.
+  bool EnsureRDDReady();
 
   void OnProcessLaunchComplete(RDDProcessHost* aHost) override;
   void OnProcessUnexpectedShutdown(RDDProcessHost* aHost) override;
 
   // Notify the RDDProcessManager that a top-level PRDD protocol has been
   // terminated. This may be called from any thread.
   void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken);
 
@@ -57,21 +62,16 @@ class RDDProcessManager final : public R
 
   // Returns whether or not a RDD process was ever launched.
   bool AttemptedRDDProcess() const { return mNumProcessAttempts > 0; }
 
   // Returns the RDD Process
   RDDProcessHost* Process() { return mProcess; }
 
  private:
-  bool IsRDDProcessLaunching();
-  // Ensure that RDD-bound methods can be used. If no RDD process is being
-  // used, or one is launched and ready, this function returns immediately.
-  // Otherwise it blocks until the RDD process has finished launching.
-  bool EnsureRDDReady();
   bool CreateVideoBridge();
 
   // Called from our xpcom-shutdown observer.
   void OnXPCOMShutdown();
   void OnPreferenceChange(const char16_t* aData);
 
   RDDProcessManager();
 
@@ -89,29 +89,30 @@ class RDDProcessManager final : public R
 
    protected:
     ~Observer() = default;
 
     RDDProcessManager* mManager;
   };
   friend class Observer;
 
-  bool CreateContentBridge(
-      base::ProcessId aOtherProcess,
-      ipc::Endpoint<PRemoteDecoderManagerChild>* aOutRemoteDecoderManager);
+ private:
+  bool CreateContentBridge(base::ProcessId aOtherProcess,
+                           mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>*
+                               aOutRemoteDecoderManager);
 
   const RefPtr<Observer> mObserver;
-  ipc::TaskFactory<RDDProcessManager> mTaskFactory;
+  mozilla::ipc::TaskFactory<RDDProcessManager> mTaskFactory;
   uint32_t mNumProcessAttempts = 0;
 
   // Fields that are associated with the current RDD process.
   RDDProcessHost* mProcess = nullptr;
   uint64_t mProcessToken = 0;
   RDDChild* mRDDChild = nullptr;
   // Collects any pref changes that occur during process launch (after
   // the initial map is passed in command-line arguments) to be sent
   // when the process can receive IPC messages.
-  nsTArray<dom::Pref> mQueuedPrefs;
+  nsTArray<mozilla::dom::Pref> mQueuedPrefs;
 };
 
 }  // namespace mozilla
 
 #endif  // _include_dom_media_ipc_RDDProcessManager_h_
--- a/dom/media/ipc/RemoteAudioDecoder.cpp
+++ b/dom/media/ipc/RemoteAudioDecoder.cpp
@@ -49,50 +49,49 @@ MediaResult RemoteAudioDecoderChild::Ini
   }
 
   if (!manager->CanSend()) {
     return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                        RESULT_DETAIL("RemoteDecoderManager unable to send."));
   }
 
   mIPDLSelfRef = this;
-  Unused << manager->SendPRemoteDecoderConstructor(this, aAudioInfo, aOptions,
-                                                   Nothing());
-  return NS_OK;
+  bool success = false;
+  nsCString errorDescription;
+  Unused << manager->SendPRemoteDecoderConstructor(
+      this, aAudioInfo, aOptions, Nothing(), &success, &errorDescription);
+  return success ? MediaResult(NS_OK)
+                 : MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, errorDescription);
 }
 
 RemoteAudioDecoderParent::RemoteAudioDecoderParent(
     RemoteDecoderManagerParent* aParent, const AudioInfo& aAudioInfo,
     const CreateDecoderParams::OptionSet& aOptions,
-    nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue)
-    : RemoteDecoderParent(aParent, aOptions, aManagerThread, aDecodeTaskQueue),
-      mAudioInfo(aAudioInfo) {}
+    nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue,
+    bool* aSuccess, nsCString* aErrorDescription)
+    : RemoteDecoderParent(aParent, aManagerThread, aDecodeTaskQueue),
+      mAudioInfo(aAudioInfo) {
+  MediaResult error(NS_OK);
+  auto params = CreateDecoderParams{
+      mAudioInfo, aOptions, CreateDecoderParams::NoWrapper(true), &error};
 
-IPCResult RemoteAudioDecoderParent::RecvConstruct(
-    ConstructResolver&& aResolver) {
-  auto params = CreateDecoderParams{mAudioInfo, mOptions,
-                                    CreateDecoderParams::NoWrapper(true)};
+  auto& factory = aParent->EnsurePDMFactory();
+  RefPtr<MediaDataDecoder> decoder = factory.CreateDecoder(params);
 
-  mParent->EnsurePDMFactory().CreateDecoder(params)->Then(
-      GetCurrentSerialEventTarget(), __func__,
-      [resolver = std::move(aResolver), self = RefPtr{this}](
-          PlatformDecoderModule::CreateDecoderPromise::ResolveOrRejectValue&&
-              aValue) {
-        if (aValue.IsReject()) {
-          resolver(aValue.RejectValue());
-          return;
-        }
-        MOZ_ASSERT(aValue.ResolveValue());
-        self->mDecoder =
-            new MediaDataDecoderProxy(aValue.ResolveValue().forget(),
-                                      do_AddRef(self->mDecodeTaskQueue.get()));
-        resolver(NS_OK);
-      });
+  if (NS_FAILED(error)) {
+    MOZ_ASSERT(aErrorDescription);
+    *aErrorDescription = error.Description();
+  }
 
-  return IPC_OK();
+  if (decoder) {
+    mDecoder = new MediaDataDecoderProxy(decoder.forget(),
+                                         do_AddRef(mDecodeTaskQueue.get()));
+  }
+
+  *aSuccess = !!mDecoder;
 }
 
 MediaResult RemoteAudioDecoderParent::ProcessDecodedData(
     MediaDataDecoder::DecodedData&& aData, DecodedOutputIPDL& aDecodedData) {
   MOZ_ASSERT(OnManagerThread());
 
   // Converted array to array of RefPtr<AudioData>
   nsTArray<RefPtr<AudioData>> data(aData.Length());
--- a/dom/media/ipc/RemoteAudioDecoder.h
+++ b/dom/media/ipc/RemoteAudioDecoder.h
@@ -24,28 +24,27 @@ class RemoteAudioDecoderChild final : pu
 };
 
 class RemoteAudioDecoderParent final : public RemoteDecoderParent {
  public:
   RemoteAudioDecoderParent(RemoteDecoderManagerParent* aParent,
                            const AudioInfo& aAudioInfo,
                            const CreateDecoderParams::OptionSet& aOptions,
                            nsISerialEventTarget* aManagerThread,
-                           TaskQueue* aDecodeTaskQueue);
+                           TaskQueue* aDecodeTaskQueue, bool* aSuccess,
+                           nsCString* aErrorDescription);
 
  protected:
-  IPCResult RecvConstruct(ConstructResolver&& aResolver) override;
   MediaResult ProcessDecodedData(MediaDataDecoder::DecodedData&& aData,
                                  DecodedOutputIPDL& aDecodedData) override;
 
  private:
   // Can only be accessed from the manager thread
   // Note: we can't keep a reference to the original AudioInfo here
   // because unlike in typical MediaDataDecoder situations, we're being
   // passed a deserialized AudioInfo from RecvPRemoteDecoderConstructor
   // which is destroyed when RecvPRemoteDecoderConstructor returns.
   const AudioInfo mAudioInfo;
-  const CreateDecoderParams::OptionSet mOptions;
 };
 
 }  // namespace mozilla
 
 #endif  // include_dom_media_ipc_RemoteAudioDecoderChild_h
--- a/dom/media/ipc/RemoteDecoderChild.cpp
+++ b/dom/media/ipc/RemoteDecoderChild.cpp
@@ -14,18 +14,16 @@ RemoteDecoderChild::RemoteDecoderChild(b
       mThread(GetCurrentSerialEventTarget()),
       mRecreatedOnCrash(aRecreatedOnCrash) {
   MOZ_DIAGNOSTIC_ASSERT(
       RemoteDecoderManagerChild::GetManagerThread() &&
           RemoteDecoderManagerChild::GetManagerThread()->IsOnCurrentThread(),
       "Must be created on the manager thread");
 }
 
-RemoteDecoderChild::~RemoteDecoderChild() = default;
-
 void RemoteDecoderChild::HandleRejectionError(
     const ipc::ResponseRejectReason& aReason,
     std::function<void(const MediaResult&)>&& aCallback) {
   // If the channel goes down and CanSend() returns false, the IPDL promise will
   // be rejected with SendError rather than ActorDestroyed. Both means the same
   // thing and we can consider that the parent has crashed. The child can no
   // longer be used.
 
--- a/dom/media/ipc/RemoteDecoderChild.h
+++ b/dom/media/ipc/RemoteDecoderChild.h
@@ -3,57 +3,56 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 include_dom_media_ipc_RemoteDecoderChild_h
 #define include_dom_media_ipc_RemoteDecoderChild_h
 
 #include <functional>
 
+#include "IRemoteDecoderChild.h"
 #include "mozilla/PRemoteDecoderChild.h"
 #include "mozilla/ShmemRecycleAllocator.h"
 
 namespace mozilla {
 
 class RemoteDecoderManagerChild;
 using mozilla::MediaDataDecoder;
 using mozilla::ipc::IPCResult;
 
 class RemoteDecoderChild : public ShmemRecycleAllocator<RemoteDecoderChild>,
-                           public PRemoteDecoderChild {
+                           public PRemoteDecoderChild,
+                           public IRemoteDecoderChild {
   friend class PRemoteDecoderChild;
 
  public:
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteDecoderChild);
-
   explicit RemoteDecoderChild(bool aRecreatedOnCrash = false);
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
-  // This interface closely mirrors the MediaDataDecoder plus a bit
-  // (DestroyIPDL) to allow proxying to a remote decoder in RemoteDecoderModule.
-  RefPtr<MediaDataDecoder::InitPromise> Init();
+  // IRemoteDecoderChild
+  RefPtr<MediaDataDecoder::InitPromise> Init() override;
   RefPtr<MediaDataDecoder::DecodePromise> Decode(
-      const nsTArray<RefPtr<MediaRawData>>& aSamples);
-  RefPtr<MediaDataDecoder::DecodePromise> Drain();
-  RefPtr<MediaDataDecoder::FlushPromise> Flush();
-  RefPtr<mozilla::ShutdownPromise> Shutdown();
-  bool IsHardwareAccelerated(nsACString& aFailureReason) const;
-  nsCString GetDescriptionName() const;
-  void SetSeekThreshold(const media::TimeUnit& aTime);
-  MediaDataDecoder::ConversionRequired NeedsConversion() const;
-  void DestroyIPDL();
+      const nsTArray<RefPtr<MediaRawData>>& aSamples) override;
+  RefPtr<MediaDataDecoder::DecodePromise> Drain() override;
+  RefPtr<MediaDataDecoder::FlushPromise> Flush() override;
+  RefPtr<mozilla::ShutdownPromise> Shutdown() override;
+  bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
+  nsCString GetDescriptionName() const override;
+  void SetSeekThreshold(const media::TimeUnit& aTime) override;
+  MediaDataDecoder::ConversionRequired NeedsConversion() const override;
+  void DestroyIPDL() override;
 
   // Called from IPDL when our actor has been destroyed
   void IPDLActorDestroyed();
 
   RemoteDecoderManagerChild* GetManager();
 
  protected:
-  virtual ~RemoteDecoderChild();
+  virtual ~RemoteDecoderChild() = default;
   void AssertOnManagerThread() const;
 
   virtual MediaResult ProcessOutput(DecodedOutputIPDL&& aDecodedData) = 0;
   virtual void RecordShutdownTelemetry(bool aForAbnormalShutdown) {}
 
   RefPtr<RemoteDecoderChild> mIPDLSelfRef;
   MediaDataDecoder::DecodedData mDecodedData;
 
--- a/dom/media/ipc/RemoteDecoderManagerChild.cpp
+++ b/dom/media/ipc/RemoteDecoderManagerChild.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 #include "RemoteDecoderManagerChild.h"
 
 #include "RemoteAudioDecoder.h"
+#include "RemoteDecoderChild.h"
 #include "RemoteMediaDataDecoder.h"
 #include "RemoteVideoDecoder.h"
 #include "VideoUtils.h"
 #include "mozilla/DataMutex.h"
 #include "mozilla/SyncRunnable.h"
 #include "mozilla/dom/ContentChild.h"  // for launching RDD w/ ContentChild
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
@@ -21,19 +22,18 @@
 #include "nsIObserver.h"
 
 namespace mozilla {
 
 using namespace layers;
 using namespace gfx;
 
 // Used so that we only ever attempt to check if the RDD process should be
-// launched serially. Protects sLaunchPromise
+// launched serially.
 StaticMutex sLaunchMutex;
-static StaticRefPtr<GenericNonExclusivePromise> sLaunchRDDPromise;
 
 // Only modified on the main-thread, read on any thread. While it could be read
 // on the main thread directly, for clarity we force access via the DataMutex
 // wrapper.
 static StaticDataMutex<StaticRefPtr<nsIThread>>
     sRemoteDecoderManagerChildThread("sRemoteDecoderManagerChildThread");
 
 // Only accessed from sRemoteDecoderManagerChildThread
@@ -65,20 +65,20 @@ ShutdownObserver::Observe(nsISupports* a
 StaticRefPtr<ShutdownObserver> sObserver;
 
 /* static */
 void RemoteDecoderManagerChild::Init() {
   MOZ_ASSERT(NS_IsMainThread());
 
   auto remoteDecoderManagerThread = sRemoteDecoderManagerChildThread.Lock();
   if (!*remoteDecoderManagerThread) {
-    // We can't use a MediaThreadType::SUPERVISOR as the RemoteDecoderModule
-    // runs on it and dispatch synchronous tasks to the manager thread, should
-    // more than 4 concurrent videos being instantiated at the same time, we
-    // could end up in a deadlock.
+    // We can't use a MediaThreadType::CONTROLLER as the GpuDecoderModule and
+    // RemoteDecoderModule runs on it and dispatch synchronous tasks to the
+    // manager thread, should more than 4 concurrent videos being instantiated
+    // at the same time, we could end up in a deadlock.
     RefPtr<nsIThread> childThread;
     nsresult rv = NS_NewNamedThread(
         "RemVidChild", getter_AddRefs(childThread),
         NS_NewRunnableFunction(
             "RemoteDecoderManagerChild::InitPBackground", []() {
               ipc::PBackgroundChild* bgActor =
                   ipc::BackgroundChild::GetOrCreateForCurrentThread();
               NS_ASSERTION(bgActor, "Failed to start Background channel");
@@ -189,206 +189,175 @@ bool RemoteDecoderManagerChild::Supports
       break;
     default:
       return false;
   }
   return pdm->Supports(aParams, aDiagnostics);
 }
 
 /* static */
-RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+already_AddRefed<MediaDataDecoder>
 RemoteDecoderManagerChild::CreateAudioDecoder(
     const CreateDecoderParams& aParams) {
   nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   if (!managerThread) {
     // We got shutdown.
-    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-        NS_ERROR_DOM_MEDIA_CANCELED, __func__);
+    return nullptr;
   }
-  return LaunchRDDProcessIfNeeded()->Then(
-      managerThread, __func__,
-      [params = CreateDecoderParamsForAsync(aParams)](bool) {
-        auto child = MakeRefPtr<RemoteAudioDecoderChild>();
-        MediaResult result =
-            child->InitIPDL(params.AudioConfig(), params.mOptions);
+
+  RefPtr<RemoteAudioDecoderChild> child;
+  MediaResult result(NS_ERROR_DOM_MEDIA_CANCELED);
+
+  // We can use child as a ref here because this is a sync dispatch. In
+  // the error case for InitIPDL, we can't just let the RefPtr go out of
+  // scope at the end of the method because it will release the
+  // RemoteAudioDecoderChild on the wrong thread.  This will assert in
+  // RemoteDecoderChild's destructor.  Passing the RefPtr by reference
+  // allows us to release the RemoteAudioDecoderChild on the manager
+  // thread during this single dispatch.
+  RefPtr<Runnable> task =
+      NS_NewRunnableFunction("RemoteDecoderModule::CreateAudioDecoder", [&]() {
+        child = new RemoteAudioDecoderChild();
+        result = child->InitIPDL(aParams.AudioConfig(), aParams.mOptions);
         if (NS_FAILED(result)) {
-          return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-              result, __func__);
+          // Release RemoteAudioDecoderChild here, while we're on
+          // manager thread.  Don't just let the RefPtr go out of scope.
+          child = nullptr;
         }
-        return Construct(std::move(child));
-      },
-      [](nsresult aResult) {
-        return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-            MediaResult(aResult, "Couldn't start RDD process"), __func__);
       });
+  SyncRunnable::DispatchToThread(managerThread, task);
+
+  if (NS_FAILED(result)) {
+    if (aParams.mError) {
+      *aParams.mError = result;
+    }
+    return nullptr;
+  }
+
+  RefPtr<RemoteMediaDataDecoder> object = new RemoteMediaDataDecoder(child);
+
+  return object.forget();
 }
 
 /* static */
-RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+already_AddRefed<MediaDataDecoder>
 RemoteDecoderManagerChild::CreateVideoDecoder(
     const CreateDecoderParams& aParams, RemoteDecodeIn aLocation) {
   nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   if (!managerThread) {
     // We got shutdown.
-    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-        NS_ERROR_DOM_MEDIA_CANCELED, __func__);
-  }
-
-  if (!aParams.mKnowsCompositor && aLocation == RemoteDecodeIn::GpuProcess) {
-    // We don't have an image bridge; don't attempt to decode in the GPU
-    // process.
-    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-        NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR, __func__);
+    return nullptr;
   }
 
   MOZ_ASSERT(aLocation != RemoteDecodeIn::Unspecified);
-
-  RefPtr<GenericNonExclusivePromise> p =
-      aLocation == RemoteDecodeIn::GpuProcess
-          ? GenericNonExclusivePromise::CreateAndResolve(true, __func__)
-          : LaunchRDDProcessIfNeeded();
+  RefPtr<RemoteVideoDecoderChild> child;
+  MediaResult result(NS_ERROR_DOM_MEDIA_CANCELED);
 
-  return p->Then(
-      managerThread, __func__,
-      [aLocation, params = CreateDecoderParamsForAsync(aParams)](bool) {
-        auto child = MakeRefPtr<RemoteVideoDecoderChild>(aLocation);
-        MediaResult result = child->InitIPDL(
-            params.VideoConfig(), params.mRate.mValue, params.mOptions,
-            params.mKnowsCompositor
-                ? &params.mKnowsCompositor->GetTextureFactoryIdentifier()
+  // We can use child as a ref here because this is a sync dispatch. In
+  // the error case for InitIPDL, we can't just let the RefPtr go out of
+  // scope at the end of the method because it will release the
+  // RemoteVideoDecoderChild on the wrong thread.  This will assert in
+  // RemoteDecoderChild's destructor.  Passing the RefPtr by reference
+  // allows us to release the RemoteVideoDecoderChild on the manager
+  // thread during this single dispatch.
+  RefPtr<Runnable> task = NS_NewRunnableFunction(
+      "RemoteDecoderManagerChild::CreateVideoDecoder", [&]() {
+        child = new RemoteVideoDecoderChild(aLocation);
+        result = child->InitIPDL(
+            aParams.VideoConfig(), aParams.mRate.mValue, aParams.mOptions,
+            aParams.mKnowsCompositor
+                ? &aParams.mKnowsCompositor->GetTextureFactoryIdentifier()
                 : nullptr);
         if (NS_FAILED(result)) {
-          return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-              result, __func__);
+          // Release RemoteVideoDecoderChild here, while we're on
+          // manager thread.  Don't just let the RefPtr go out of scope.
+          child = nullptr;
         }
-        return Construct(std::move(child));
-      },
-      [](nsresult aResult) {
-        return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-            MediaResult(aResult, "Couldn't start RDD process"), __func__);
       });
+  SyncRunnable::DispatchToThread(managerThread, task);
+
+  if (NS_FAILED(result)) {
+    if (aParams.mError) {
+      *aParams.mError = result;
+    }
+    return nullptr;
+  }
+
+  RefPtr<RemoteMediaDataDecoder> object = new RemoteMediaDataDecoder(child);
+
+  return object.forget();
 }
 
 /* static */
-RefPtr<PlatformDecoderModule::CreateDecoderPromise>
-RemoteDecoderManagerChild::Construct(RefPtr<RemoteDecoderChild>&& aChild) {
-  nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
-  if (!managerThread) {
-    // We got shutdown.
-    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-        NS_ERROR_DOM_MEDIA_CANCELED, __func__);
-  }
-  MOZ_ASSERT(managerThread->IsOnCurrentThread());
-
-  RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
-      aChild->SendConstruct()->Then(
-          managerThread, __func__,
-          [child = std::move(aChild)](MediaResult aResult) {
-            if (NS_FAILED(aResult)) {
-              // We will never get to use this remote decoder, tear it down.
-              child->DestroyIPDL();
-              return PlatformDecoderModule::CreateDecoderPromise::
-                  CreateAndReject(aResult, __func__);
-            }
-            return PlatformDecoderModule::CreateDecoderPromise::
-                CreateAndResolve(MakeRefPtr<RemoteMediaDataDecoder>(child),
-                                 __func__);
-          },
-          [](const mozilla::ipc::ResponseRejectReason& aReason) {
-            // The parent has died.
-            return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-                NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER, __func__);
-          });
-  return p;
-}
-
-/* static */
-RefPtr<GenericNonExclusivePromise>
-RemoteDecoderManagerChild::LaunchRDDProcessIfNeeded() {
+void RemoteDecoderManagerChild::LaunchRDDProcessIfNeeded(
+    RemoteDecodeIn aLocation) {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess(),
                         "Only supported from a content process.");
 
+  if (aLocation != RemoteDecodeIn::RddProcess) {
+    // Not targeting RDD process? No need to launch RDD.
+    return;
+  }
+
   nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
   if (!managerThread) {
     // We got shutdown.
-    return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
-                                                       __func__);
+    return;
   }
 
   StaticMutexAutoLock lock(sLaunchMutex);
 
-  if (sLaunchRDDPromise) {
-    return sLaunchRDDPromise;
-  }
-
   // We have a couple possible states here.  We are in a content process
   // and:
   // 1) the RDD process has never been launched.  RDD should be launched
   //    and the IPC connections setup.
   // 2) the RDD process has been launched, but this particular content
   //    process has not setup (or has lost) its IPC connection.
   // In the code below, we assume we need to launch the RDD process and
   // setup the IPC connections.  However, if the manager thread for
   // RemoteDecoderManagerChild is available we do a quick check to see
   // if we can send (meaning the IPC channel is open).  If we can send,
   // then no work is necessary.  If we can't send, then we call
   // LaunchRDDProcess which will launch RDD if necessary, and setup the
   // IPC connections between *this* content process and the RDD process.
 
-  RefPtr<GenericNonExclusivePromise> p = InvokeAsync(
-      managerThread, __func__, []() -> RefPtr<GenericNonExclusivePromise> {
+  bool needsLaunch = true;
+  RefPtr<Runnable> task = NS_NewRunnableFunction(
+      "RemoteDecoderManagerChild::LaunchRDDProcessIfNeeded-CheckSend", [&]() {
         auto* rps = GetSingleton(RemoteDecodeIn::RddProcess);
-        if (rps && rps->CanSend()) {
-          return GenericNonExclusivePromise::CreateAndResolve(true, __func__);
-        }
-        nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
-        ipc::PBackgroundChild* bgActor =
-            ipc::BackgroundChild::GetForCurrentThread();
-        if (!managerThread || NS_WARN_IF(!bgActor)) {
-          return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_FAILURE,
-                                                             __func__);
-        }
+        needsLaunch = rps ? !rps->CanSend() : true;
+      });
+  if (NS_FAILED(SyncRunnable::DispatchToThread(managerThread, task))) {
+    return;
+  };
 
-        return bgActor->SendEnsureRDDProcessAndCreateBridge()->Then(
-            managerThread, __func__,
-            [](ipc::PBackgroundChild::EnsureRDDProcessAndCreateBridgePromise::
-                   ResolveOrRejectValue&& aResult) {
-              nsCOMPtr<nsISerialEventTarget> managerThread = GetManagerThread();
-              if (!managerThread || aResult.IsReject()) {
-                // The parent process died or we got shutdown
-                return GenericNonExclusivePromise::CreateAndReject(
-                    NS_ERROR_FAILURE, __func__);
-              }
-              nsresult rv = Get<0>(aResult.ResolveValue());
-              if (NS_FAILED(rv)) {
-                return GenericNonExclusivePromise::CreateAndReject(rv,
-                                                                   __func__);
-              }
-              OpenForRDDProcess(Get<1>(std::move(aResult.ResolveValue())));
-              return GenericNonExclusivePromise::CreateAndResolve(true,
-                                                                  __func__);
-            });
-      });
-
-  p = p->Then(
-      GetCurrentSerialEventTarget(), __func__,
-      [](const GenericNonExclusivePromise::ResolveOrRejectValue& aResult) {
-        StaticMutexAutoLock lock(sLaunchMutex);
-        sLaunchRDDPromise = nullptr;
-        return GenericNonExclusivePromise::CreateAndResolveOrReject(aResult,
-                                                                    __func__);
-      });
-  sLaunchRDDPromise = p;
-  return sLaunchRDDPromise;
+  if (needsLaunch) {
+    managerThread->Dispatch(NS_NewRunnableFunction(
+        "RemoteDecoderManagerChild::EnsureRDDProcessAndCreateBridge", [&]() {
+          ipc::PBackgroundChild* bgActor =
+              ipc::BackgroundChild::GetForCurrentThread();
+          if (NS_WARN_IF(!bgActor)) {
+            return;
+          }
+          nsresult rv;
+          Endpoint<PRemoteDecoderManagerChild> endpoint;
+          Unused << bgActor->SendEnsureRDDProcessAndCreateBridge(&rv,
+                                                                 &endpoint);
+          if (NS_SUCCEEDED(rv)) {
+            OpenForRDDProcess(std::move(endpoint));
+          }
+        }));
+  }
 }
 
 PRemoteDecoderChild* RemoteDecoderManagerChild::AllocPRemoteDecoderChild(
     const RemoteDecoderInfoIPDL& /* not used */,
     const CreateDecoderParams::OptionSet& aOptions,
-    const Maybe<layers::TextureFactoryIdentifier>& aIdentifier) {
+    const Maybe<layers::TextureFactoryIdentifier>& aIdentifier, bool* aSuccess,
+    nsCString* /* not used */) {
   // RemoteDecoderModule is responsible for creating RemoteDecoderChild
   // classes.
   MOZ_ASSERT(false,
              "RemoteDecoderManagerChild cannot create "
              "RemoteDecoderChild classes");
   return nullptr;
 }
 
--- a/dom/media/ipc/RemoteDecoderManagerChild.h
+++ b/dom/media/ipc/RemoteDecoderManagerChild.h
@@ -6,18 +6,16 @@
 #ifndef include_dom_media_ipc_RemoteDecoderManagerChild_h
 #define include_dom_media_ipc_RemoteDecoderManagerChild_h
 #include "GPUVideoImage.h"
 #include "mozilla/PRemoteDecoderManagerChild.h"
 #include "mozilla/layers/VideoBridgeUtils.h"
 
 namespace mozilla {
 
-class RemoteDecoderChild;
-
 enum class RemoteDecodeIn {
   Unspecified,
   RddProcess,
   GpuProcess,
 };
 
 class RemoteDecoderManagerChild final
     : public PRemoteDecoderManagerChild,
@@ -32,23 +30,24 @@ class RemoteDecoderManagerChild final
   static RemoteDecoderManagerChild* GetSingleton(RemoteDecodeIn aLocation);
 
   static void Init();
 
   // Can be called from any thread.
   static bool Supports(RemoteDecodeIn aLocation,
                        const SupportDecoderParams& aParams,
                        DecoderDoctorDiagnostics* aDiagnostics);
-  static RefPtr<PlatformDecoderModule::CreateDecoderPromise> CreateAudioDecoder(
+  static already_AddRefed<MediaDataDecoder> CreateAudioDecoder(
       const CreateDecoderParams& aParams);
-  static RefPtr<PlatformDecoderModule::CreateDecoderPromise> CreateVideoDecoder(
+  static already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
       const CreateDecoderParams& aParams, RemoteDecodeIn aLocation);
 
   // Can be called from any thread.
   static nsISerialEventTarget* GetManagerThread();
+  static void LaunchRDDProcessIfNeeded(RemoteDecodeIn aLocation);
 
   // Can be called from any thread, dispatches the request to the IPDL thread
   // internally and will be ignored if the IPDL actor has been destroyed.
   already_AddRefed<gfx::SourceSurface> Readback(
       const SurfaceDescriptorGPUVideo& aSD) override;
   void DeallocateSurfaceDescriptor(
       const SurfaceDescriptorGPUVideo& aSD) override;
 
@@ -87,30 +86,28 @@ class RemoteDecoderManagerChild final
 
   void ActorDealloc() override;
 
   void HandleFatalError(const char* aMsg) const override;
 
   PRemoteDecoderChild* AllocPRemoteDecoderChild(
       const RemoteDecoderInfoIPDL& aRemoteDecoderInfo,
       const CreateDecoderParams::OptionSet& aOptions,
-      const Maybe<layers::TextureFactoryIdentifier>& aIdentifier);
+      const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
+      bool* aSuccess, nsCString* aErrorDescription);
   bool DeallocPRemoteDecoderChild(PRemoteDecoderChild* actor);
 
  private:
   explicit RemoteDecoderManagerChild(RemoteDecodeIn aLocation);
   ~RemoteDecoderManagerChild() = default;
-  static RefPtr<PlatformDecoderModule::CreateDecoderPromise> Construct(
-      RefPtr<RemoteDecoderChild>&& aChild);
 
   static void OpenForRDDProcess(
       Endpoint<PRemoteDecoderManagerChild>&& aEndpoint);
   static void OpenForGPUProcess(
       Endpoint<PRemoteDecoderManagerChild>&& aEndpoint);
-  static RefPtr<GenericNonExclusivePromise> LaunchRDDProcessIfNeeded();
 
   RefPtr<RemoteDecoderManagerChild> mIPDLSelfRef;
   // The location for decoding, Rdd or Gpu process.
   const RemoteDecodeIn mLocation;
 };
 
 }  // namespace mozilla
 
--- a/dom/media/ipc/RemoteDecoderManagerParent.cpp
+++ b/dom/media/ipc/RemoteDecoderManagerParent.cpp
@@ -9,21 +9,21 @@
 #  include <objbase.h>
 #endif
 
 #include "ImageContainer.h"
 #include "PDMFactory.h"
 #include "RemoteAudioDecoder.h"
 #include "RemoteVideoDecoder.h"
 #include "VideoUtils.h"  // for MediaThreadType
-#include "mozilla/RDDParent.h"
 #include "mozilla/SyncRunnable.h"
-#include "mozilla/gfx/GPUParent.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/VideoBridgeChild.h"
+#include "mozilla/gfx/GPUParent.h"
+#include "mozilla/RDDParent.h"
 
 namespace mozilla {
 
 #ifdef XP_WIN
 extern const nsCString GetFoundD3D11BlacklistedDLL();
 extern const nsCString GetFoundD3D9BlacklistedDLL();
 #endif  // XP_WIN
 
@@ -177,34 +177,37 @@ RemoteDecoderManagerParent::~RemoteDecod
 void RemoteDecoderManagerParent::ActorDestroy(
     mozilla::ipc::IProtocol::ActorDestroyReason) {
   mThread = nullptr;
 }
 
 PRemoteDecoderParent* RemoteDecoderManagerParent::AllocPRemoteDecoderParent(
     const RemoteDecoderInfoIPDL& aRemoteDecoderInfo,
     const CreateDecoderParams::OptionSet& aOptions,
-    const Maybe<layers::TextureFactoryIdentifier>& aIdentifier) {
+    const Maybe<layers::TextureFactoryIdentifier>& aIdentifier, bool* aSuccess,
+    nsCString* aErrorDescription) {
   RefPtr<TaskQueue> decodeTaskQueue =
       new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
                     "RemoteVideoDecoderParent::mDecodeTaskQueue");
 
   if (aRemoteDecoderInfo.type() ==
       RemoteDecoderInfoIPDL::TVideoDecoderInfoIPDL) {
     const VideoDecoderInfoIPDL& decoderInfo =
         aRemoteDecoderInfo.get_VideoDecoderInfoIPDL();
     return new RemoteVideoDecoderParent(
         this, decoderInfo.videoInfo(), decoderInfo.framerate(), aOptions,
-        aIdentifier, sRemoteDecoderManagerParentThread, decodeTaskQueue);
+        aIdentifier, sRemoteDecoderManagerParentThread, decodeTaskQueue,
+        aSuccess, aErrorDescription);
   }
 
   if (aRemoteDecoderInfo.type() == RemoteDecoderInfoIPDL::TAudioInfo) {
     return new RemoteAudioDecoderParent(
         this, aRemoteDecoderInfo.get_AudioInfo(), aOptions,
-        sRemoteDecoderManagerParentThread, decodeTaskQueue);
+        sRemoteDecoderManagerParentThread, decodeTaskQueue, aSuccess,
+        aErrorDescription);
   }
 
   MOZ_CRASH("unrecognized type of RemoteDecoderInfoIPDL union");
   return nullptr;
 }
 
 bool RemoteDecoderManagerParent::DeallocPRemoteDecoderParent(
     PRemoteDecoderParent* actor) {
--- a/dom/media/ipc/RemoteDecoderManagerParent.h
+++ b/dom/media/ipc/RemoteDecoderManagerParent.h
@@ -52,19 +52,25 @@ class RemoteDecoderManagerParent final
 
   // Can be called from manager thread only
   PDMFactory& EnsurePDMFactory();
 
  protected:
   PRemoteDecoderParent* AllocPRemoteDecoderParent(
       const RemoteDecoderInfoIPDL& aRemoteDecoderInfo,
       const CreateDecoderParams::OptionSet& aOptions,
-      const Maybe<layers::TextureFactoryIdentifier>& aIdentifier);
+      const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
+      bool* aSuccess, nsCString* aErrorDescription);
   bool DeallocPRemoteDecoderParent(PRemoteDecoderParent* actor);
 
+  mozilla::ipc::IPCResult RecvSupports(
+      const RemoteDecoderInfoIPDL& aInfo,
+      const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
+      bool* aSuccess, DecoderDoctorDiagnostics* aDiagnostics);
+
   mozilla::ipc::IPCResult RecvReadback(const SurfaceDescriptorGPUVideo& aSD,
                                        SurfaceDescriptor* aResult);
   mozilla::ipc::IPCResult RecvDeallocateSurfaceDescriptorGPUVideo(
       const SurfaceDescriptorGPUVideo& aSD);
 
   void ActorDestroy(mozilla::ipc::IProtocol::ActorDestroyReason) override;
   void ActorDealloc() override;
 
--- a/dom/media/ipc/RemoteDecoderModule.cpp
+++ b/dom/media/ipc/RemoteDecoderModule.cpp
@@ -1,15 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 #include "RemoteDecoderModule.h"
 
+#include "mozilla/StaticPrefs_media.h"
+#include "mozilla/SyncRunnable.h"
+#include "mozilla/dom/ContentChild.h"  // for launching RDD w/ ContentChild
+#include "mozilla/layers/SynchronousTask.h"
+
 #ifdef MOZ_AV1
 #  include "AOMDecoder.h"
 #endif
 #include "OpusDecoder.h"
 #include "RemoteAudioDecoder.h"
 #include "RemoteDecoderManagerChild.h"
 #include "RemoteMediaDataDecoder.h"
 #include "RemoteVideoDecoder.h"
@@ -51,27 +56,33 @@ bool RemoteDecoderModule::Supports(
       RemoteDecoderManagerChild::Supports(mLocation, aParams, aDiagnostics);
   MOZ_LOG(sPDMLog, LogLevel::Debug,
           ("Sandbox %s decoder %s requested type",
            mLocation == RemoteDecodeIn::GpuProcess ? "GPU" : "RDD",
            supports ? "supports" : "rejects"));
   return supports;
 }
 
-RefPtr<RemoteDecoderModule::CreateDecoderPromise>
-RemoteDecoderModule::AsyncCreateDecoder(const CreateDecoderParams& aParams) {
-  if (aParams.mConfig.IsAudio()) {
-    // OpusDataDecoder will check this option to provide the same info
-    // that IsDefaultPlaybackDeviceMono provides.  We want to avoid calls
-    // to IsDefaultPlaybackDeviceMono on RDD because initializing audio
-    // backends on RDD will be blocked by the sandbox.
-    if (OpusDataDecoder::IsOpus(aParams.mConfig.mMimeType) &&
-        IsDefaultPlaybackDeviceMono()) {
-      CreateDecoderParams params = aParams;
-      params.mOptions += CreateDecoderParams::Option::DefaultPlaybackDeviceMono;
-      return RemoteDecoderManagerChild::CreateAudioDecoder(params);
-    }
-    return RemoteDecoderManagerChild::CreateAudioDecoder(aParams);
+already_AddRefed<MediaDataDecoder> RemoteDecoderModule::CreateAudioDecoder(
+    const CreateDecoderParams& aParams) {
+  RemoteDecoderManagerChild::LaunchRDDProcessIfNeeded(mLocation);
+
+  // OpusDataDecoder will check this option to provide the same info
+  // that IsDefaultPlaybackDeviceMono provides.  We want to avoid calls
+  // to IsDefaultPlaybackDeviceMono on RDD because initializing audio
+  // backends on RDD will be blocked by the sandbox.
+  if (OpusDataDecoder::IsOpus(aParams.mConfig.mMimeType) &&
+      IsDefaultPlaybackDeviceMono()) {
+    CreateDecoderParams params = aParams;
+    params.mOptions += CreateDecoderParams::Option::DefaultPlaybackDeviceMono;
+    return RemoteDecoderManagerChild::CreateAudioDecoder(params);
   }
+
+  return RemoteDecoderManagerChild::CreateAudioDecoder(aParams);
+}
+
+already_AddRefed<MediaDataDecoder> RemoteDecoderModule::CreateVideoDecoder(
+    const CreateDecoderParams& aParams) {
+  RemoteDecoderManagerChild::LaunchRDDProcessIfNeeded(mLocation);
   return RemoteDecoderManagerChild::CreateVideoDecoder(aParams, mLocation);
 }
 
 }  // namespace mozilla
--- a/dom/media/ipc/RemoteDecoderModule.h
+++ b/dom/media/ipc/RemoteDecoderModule.h
@@ -21,28 +21,21 @@ class RemoteDecoderModule : public Platf
       RemoteDecodeIn aLocation);
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
 
   bool Supports(const SupportDecoderParams& aParams,
                 DecoderDoctorDiagnostics* aDiagnostics) const override;
 
-  RefPtr<CreateDecoderPromise> AsyncCreateDecoder(
+  already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
       const CreateDecoderParams& aParams) override;
 
-  already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
-      const CreateDecoderParams& aParams) override {
-    MOZ_CRASH("Not available");
-  }
-
   already_AddRefed<MediaDataDecoder> CreateAudioDecoder(
-      const CreateDecoderParams& aParams) override {
-    MOZ_CRASH("Not available");
-  }
+      const CreateDecoderParams& aParams) override;
 
  private:
   explicit RemoteDecoderModule(RemoteDecodeIn aLocation);
 
   const RemoteDecodeIn mLocation;
 };
 
 }  // namespace mozilla
--- a/dom/media/ipc/RemoteDecoderParent.cpp
+++ b/dom/media/ipc/RemoteDecoderParent.cpp
@@ -5,23 +5,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "RemoteDecoderParent.h"
 
 #include "RemoteDecoderManagerParent.h"
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 
-RemoteDecoderParent::RemoteDecoderParent(
-    RemoteDecoderManagerParent* aParent,
-    const CreateDecoderParams::OptionSet& aOptions,
-    nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue)
+RemoteDecoderParent::RemoteDecoderParent(RemoteDecoderManagerParent* aParent,
+                                         nsISerialEventTarget* aManagerThread,
+                                         TaskQueue* aDecodeTaskQueue)
     : ShmemRecycleAllocator(this),
       mParent(aParent),
-      mOptions(aOptions),
       mDecodeTaskQueue(aDecodeTaskQueue),
       mManagerThread(aManagerThread) {
   MOZ_COUNT_CTOR(RemoteDecoderParent);
   MOZ_ASSERT(OnManagerThread());
   // We hold a reference to ourselves to keep us alive until IPDL
   // explictly destroys us. There may still be refs held by
   // tasks, but no new ones should be added after we're
   // destroyed.
--- a/dom/media/ipc/RemoteDecoderParent.h
+++ b/dom/media/ipc/RemoteDecoderParent.h
@@ -19,24 +19,22 @@ class RemoteDecoderParent : public Shmem
   friend class PRemoteDecoderParent;
 
  public:
   // We refcount this class since the task queue can have runnables
   // that reference us.
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteDecoderParent)
 
   RemoteDecoderParent(RemoteDecoderManagerParent* aParent,
-                      const CreateDecoderParams::OptionSet& aOptions,
                       nsISerialEventTarget* aManagerThread,
                       TaskQueue* aDecodeTaskQueue);
 
   void Destroy();
 
   // PRemoteDecoderParent
-  virtual IPCResult RecvConstruct(ConstructResolver&& aResolver) = 0;
   IPCResult RecvInit(InitResolver&& aResolver);
   IPCResult RecvDecode(ArrayOfRemoteMediaRawData* aData,
                        DecodeResolver&& aResolver);
   IPCResult RecvFlush(FlushResolver&& aResolver);
   IPCResult RecvDrain(DrainResolver&& aResolver);
   IPCResult RecvShutdown(ShutdownResolver&& aResolver);
   IPCResult RecvSetSeekThreshold(const media::TimeUnit& aTime);
 
@@ -46,17 +44,16 @@ class RemoteDecoderParent : public Shmem
   virtual ~RemoteDecoderParent();
 
   bool OnManagerThread();
 
   virtual MediaResult ProcessDecodedData(MediaDataDecoder::DecodedData&& aData,
                                          DecodedOutputIPDL& aDecodedData) = 0;
 
   const RefPtr<RemoteDecoderManagerParent> mParent;
-  const CreateDecoderParams::OptionSet mOptions;
   const RefPtr<TaskQueue> mDecodeTaskQueue;
   RefPtr<MediaDataDecoder> mDecoder;
 
  private:
   void DecodeNextSample(const RefPtr<ArrayOfRemoteMediaRawData>& aData,
                         size_t aIndex, MediaDataDecoder::DecodedData&& aOutput,
                         DecodeResolver&& aResolver);
   RefPtr<RemoteDecoderParent> mIPDLSelfRef;
--- a/dom/media/ipc/RemoteMediaDataDecoder.cpp
+++ b/dom/media/ipc/RemoteMediaDataDecoder.cpp
@@ -1,39 +1,28 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 #include "RemoteMediaDataDecoder.h"
 
-#include "RemoteDecoderChild.h"
+#include "base/thread.h"
+
+#include "IRemoteDecoderChild.h"
 #include "RemoteDecoderManagerChild.h"
 
 namespace mozilla {
 
-RemoteMediaDataDecoder::RemoteMediaDataDecoder(RemoteDecoderChild* aChild)
+RemoteMediaDataDecoder::RemoteMediaDataDecoder(IRemoteDecoderChild* aChild)
     : mChild(aChild) {}
 
 RemoteMediaDataDecoder::~RemoteMediaDataDecoder() {
-  if (mChild) {
-    // Shutdown didn't get called. This can happen if the creation of the
-    // decoder got interrupted while pending.
-    nsCOMPtr<nsISerialEventTarget> thread =
-        RemoteDecoderManagerChild::GetManagerThread();
-    MOZ_ASSERT(thread);
-    thread->Dispatch(NS_NewRunnableFunction(
-        "RemoteMediaDataDecoderShutdown", [child = std::move(mChild), thread] {
-          child->Shutdown()->Then(
-              thread, __func__,
-              [child](const ShutdownPromise::ResolveOrRejectValue& aValue) {
-                child->DestroyIPDL();
-              });
-        }));
-  }
+  /* Shutdown method should have been called. */
+  MOZ_ASSERT(!mChild);
 }
 
 RefPtr<MediaDataDecoder::InitPromise> RemoteMediaDataDecoder::Init() {
   RefPtr<RemoteMediaDataDecoder> self = this;
   return InvokeAsync(RemoteDecoderManagerChild::GetManagerThread(), __func__,
                      [self]() { return self->mChild->Init(); })
       ->Then(
           RemoteDecoderManagerChild::GetManagerThread(), __func__,
--- a/dom/media/ipc/RemoteMediaDataDecoder.h
+++ b/dom/media/ipc/RemoteMediaDataDecoder.h
@@ -6,54 +6,57 @@
 #ifndef include_dom_media_ipc_RemoteMediaDataDecoder_h
 #define include_dom_media_ipc_RemoteMediaDataDecoder_h
 #include "PlatformDecoderModule.h"
 
 #include "MediaData.h"
 
 namespace mozilla {
 
-class RemoteDecoderChild;
+class GpuDecoderModule;
+class IRemoteDecoderChild;
 class RemoteDecoderManagerChild;
 class RemoteMediaDataDecoder;
 
 DDLoggedTypeCustomNameAndBase(RemoteMediaDataDecoder, RemoteMediaDataDecoder,
                               MediaDataDecoder);
 
 // A MediaDataDecoder implementation that proxies through IPDL
 // to a 'real' decoder in the GPU or RDD process.
 // All requests get forwarded to a *DecoderChild instance that
 // operates solely on the provided manager and abstract manager threads.
 class RemoteMediaDataDecoder
     : public MediaDataDecoder,
       public DecoderDoctorLifeLogger<RemoteMediaDataDecoder> {
  public:
-  explicit RemoteMediaDataDecoder(RemoteDecoderChild* aChild);
+  friend class GpuDecoderModule;
+  friend class RemoteDecoderManagerChild;
 
   // MediaDataDecoder
   RefPtr<InitPromise> Init() override;
   RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
   bool CanDecodeBatch() const override { return true; }
   RefPtr<DecodePromise> DecodeBatch(
       nsTArray<RefPtr<MediaRawData>>&& aSamples) 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;
   nsCString GetDescriptionName() const override;
   ConversionRequired NeedsConversion() const override;
 
  private:
+  explicit RemoteMediaDataDecoder(IRemoteDecoderChild* aChild);
   ~RemoteMediaDataDecoder();
 
   // 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<RemoteDecoderChild> mChild;
+  RefPtr<IRemoteDecoderChild> mChild;
   // Only ever written/modified during decoder initialisation.
   // As such can be accessed from any threads after that.
   nsCString mDescription = "RemoteMediaDataDecoder"_ns;
   bool mIsHardwareAccelerated = false;
   nsCString mHardwareAcceleratedReason;
   ConversionRequired mConversion = ConversionRequired::kNeedNone;
 };
 
--- a/dom/media/ipc/RemoteVideoDecoder.cpp
+++ b/dom/media/ipc/RemoteVideoDecoder.cpp
@@ -118,70 +118,71 @@ MediaResult RemoteVideoDecoderChild::Ini
       return NS_OK;
     }
 
     return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                        RESULT_DETAIL("RemoteDecoderManager unable to send."));
   }
 
   mIPDLSelfRef = this;
+  bool success = false;
+  nsCString errorDescription;
   VideoDecoderInfoIPDL decoderInfo(aVideoInfo, aFramerate);
   Unused << manager->SendPRemoteDecoderConstructor(this, decoderInfo, aOptions,
-                                                   ToMaybe(aIdentifier));
+                                                   ToMaybe(aIdentifier),
+                                                   &success, &errorDescription);
 
-  return NS_OK;
+  return success ? MediaResult(NS_OK)
+                 : MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, errorDescription);
 }
 
 RemoteVideoDecoderParent::RemoteVideoDecoderParent(
     RemoteDecoderManagerParent* aParent, const VideoInfo& aVideoInfo,
     float aFramerate, const CreateDecoderParams::OptionSet& aOptions,
     const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
-    nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue)
-    : RemoteDecoderParent(aParent, aOptions, aManagerThread, aDecodeTaskQueue),
-      mVideoInfo(aVideoInfo),
-      mFramerate(aFramerate) {
+    nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue,
+    bool* aSuccess, nsCString* aErrorDescription)
+    : RemoteDecoderParent(aParent, aManagerThread, aDecodeTaskQueue),
+      mVideoInfo(aVideoInfo) {
   if (aIdentifier) {
     // Check to see if we have a direct PVideoBridge connection to the
     // destination process specified in aIdentifier, and create a
     // KnowsCompositor representing that connection if so. If this fails, then
     // we fall back to returning the decoded frames directly via Output().
     mKnowsCompositor =
         KnowsCompositorVideo::TryCreateForIdentifier(*aIdentifier);
   }
-}
 
-IPCResult RemoteVideoDecoderParent::RecvConstruct(
-    ConstructResolver&& aResolver) {
+  // It is possible for CreateDecoder() below to fail. In that case, we need to
+  // free the ImageContainer to avoid it leaking.
   auto imageContainer = MakeRefPtr<layers::ImageContainer>();
   if (mKnowsCompositor && XRE_IsRDDProcess()) {
     // Ensure to allocate recycle allocator
     imageContainer->EnsureRecycleAllocatorForRDD(mKnowsCompositor);
   }
+  MediaResult error(NS_OK);
   auto params = CreateDecoderParams{
       mVideoInfo,     mKnowsCompositor,
-      imageContainer, CreateDecoderParams::VideoFrameRate(mFramerate),
-      mOptions,       CreateDecoderParams::NoWrapper(true),
-  };
+      imageContainer, CreateDecoderParams::VideoFrameRate(aFramerate),
+      aOptions,       CreateDecoderParams::NoWrapper(true),
+      &error};
+
+  auto& factory = aParent->EnsurePDMFactory();
+  RefPtr<MediaDataDecoder> decoder = factory.CreateDecoder(params);
 
-  mParent->EnsurePDMFactory().CreateDecoder(params)->Then(
-      GetCurrentSerialEventTarget(), __func__,
-      [resolver = std::move(aResolver), self = RefPtr{this}](
-          PlatformDecoderModule::CreateDecoderPromise::ResolveOrRejectValue&&
-              aValue) {
-        if (aValue.IsReject()) {
-          resolver(aValue.RejectValue());
-          return;
-        }
-        MOZ_ASSERT(aValue.ResolveValue());
-        self->mDecoder =
-            new MediaDataDecoderProxy(aValue.ResolveValue().forget(),
-                                      do_AddRef(self->mDecodeTaskQueue.get()));
-        resolver(NS_OK);
-      });
-  return IPC_OK();
+  if (NS_FAILED(error)) {
+    MOZ_ASSERT(aErrorDescription);
+    *aErrorDescription = error.Description();
+  }
+
+  if (decoder) {
+    mDecoder = new MediaDataDecoderProxy(decoder.forget(),
+                                         do_AddRef(mDecodeTaskQueue.get()));
+  }
+  *aSuccess = !!mDecoder;
 }
 
 MediaResult RemoteVideoDecoderParent::ProcessDecodedData(
     MediaDataDecoder::DecodedData&& aData, DecodedOutputIPDL& aDecodedData) {
   MOZ_ASSERT(OnManagerThread());
 
   // If the video decoder bridge has shut down, stop.
   if (mKnowsCompositor && !mKnowsCompositor->GetTextureForwarder()) {
--- a/dom/media/ipc/RemoteVideoDecoder.h
+++ b/dom/media/ipc/RemoteVideoDecoder.h
@@ -53,30 +53,29 @@ class RemoteVideoDecoderChild : public R
 };
 
 class RemoteVideoDecoderParent final : public RemoteDecoderParent {
  public:
   RemoteVideoDecoderParent(
       RemoteDecoderManagerParent* aParent, const VideoInfo& aVideoInfo,
       float aFramerate, const CreateDecoderParams::OptionSet& aOptions,
       const Maybe<layers::TextureFactoryIdentifier>& aIdentifier,
-      nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue);
+      nsISerialEventTarget* aManagerThread, TaskQueue* aDecodeTaskQueue,
+      bool* aSuccess, nsCString* aErrorDescription);
 
  protected:
-  IPCResult RecvConstruct(ConstructResolver&& aResolver) override;
-
   MediaResult ProcessDecodedData(MediaDataDecoder::DecodedData&& aData,
                                  DecodedOutputIPDL& aDecodedData) override;
 
  private:
   // Can only be accessed from the manager thread
   // Note: we can't keep a reference to the original VideoInfo here
   // because unlike in typical MediaDataDecoder situations, we're being
   // passed a deserialized VideoInfo from RecvPRemoteDecoderConstructor
   // which is destroyed when RecvPRemoteDecoderConstructor returns.
   const VideoInfo mVideoInfo;
-  const float mFramerate;
+
   RefPtr<KnowsCompositorVideo> mKnowsCompositor;
 };
 
 }  // namespace mozilla
 
 #endif  // include_dom_media_ipc_RemoteVideoDecoderChild_h
--- a/dom/media/ipc/moz.build
+++ b/dom/media/ipc/moz.build
@@ -8,16 +8,17 @@
 IPDL_SOURCES += [
     "PMediaDecoderParams.ipdlh",
     "PRDD.ipdl",
     "PRemoteDecoder.ipdl",
     "PRemoteDecoderManager.ipdl",
 ]
 
 EXPORTS.mozilla += [
+    "IRemoteDecoderChild.h",
     "RDDChild.h",
     "RDDParent.h",
     "RDDProcessHost.h",
     "RDDProcessImpl.h",
     "RDDProcessManager.h",
     "RemoteDecoderChild.h",
     "RemoteDecoderManagerChild.h",
     "RemoteDecoderManagerParent.h",
--- a/dom/media/platforms/AllocationPolicy.cpp
+++ b/dom/media/platforms/AllocationPolicy.cpp
@@ -190,47 +190,67 @@ RefPtr<ShutdownPromise> AllocationWrappe
   RefPtr<Token> token = std::move(mToken);
   return decoder->Shutdown()->Then(
       GetCurrentSerialEventTarget(), __func__,
       [token]() { return ShutdownPromise::CreateAndResolve(true, __func__); });
 }
 /* static */ RefPtr<AllocationWrapper::AllocateDecoderPromise>
 AllocationWrapper::CreateDecoder(const CreateDecoderParams& aParams,
                                  AllocPolicy* aPolicy) {
+  // aParams.mConfig is guaranteed to stay alive during the lifetime of the
+  // MediaDataDecoder, so keeping a pointer to the object is safe.
+  const TrackInfo* config = &aParams.mConfig;
+  DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
+  RefPtr<layers::ImageContainer> imageContainer = aParams.mImageContainer;
+  RefPtr<layers::KnowsCompositor> knowsCompositor = aParams.mKnowsCompositor;
+  RefPtr<GMPCrashHelper> crashHelper = aParams.mCrashHelper;
+  CreateDecoderParams::UseNullDecoder useNullDecoder = aParams.mUseNullDecoder;
+  CreateDecoderParams::NoWrapper noWrapper = aParams.mNoWrapper;
+  TrackInfo::TrackType type = aParams.mType;
+  MediaEventProducer<TrackInfo::TrackType>* onWaitingForKeyEvent =
+      aParams.mOnWaitingForKeyEvent;
+  CreateDecoderParams::OptionSet options = aParams.mOptions;
+  CreateDecoderParams::VideoFrameRate rate = aParams.mRate;
+
   RefPtr<AllocateDecoderPromise> p =
       (aPolicy ? aPolicy : GlobalAllocPolicy::Instance(aParams.mType))
           ->Alloc()
           ->Then(
               GetCurrentSerialEventTarget(), __func__,
-              [params =
-                   CreateDecoderParamsForAsync(aParams)](RefPtr<Token> aToken) {
+              [=](RefPtr<Token> aToken) {
                 // result may not always be updated by
                 // PDMFactory::CreateDecoder either when the creation
                 // succeeded or failed, as such it must be initialized to a
                 // fatal error by default.
                 MediaResult result =
                     MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                                 nsPrintfCString("error creating %s decoder",
-                                                TrackTypeToStr(params.mType)));
+                                                TrackTypeToStr(type)));
                 RefPtr<PDMFactory> pdm = new PDMFactory();
-                RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
-                    pdm->CreateDecoder(params)->Then(
-                        GetCurrentSerialEventTarget(), __func__,
-                        [aToken](RefPtr<MediaDataDecoder>&& aDecoder) mutable {
-                          RefPtr<AllocationWrapper> wrapper =
-                              new AllocationWrapper(aDecoder.forget(),
-                                                    aToken.forget());
-                          return AllocateDecoderPromise::CreateAndResolve(
-                              wrapper, __func__);
-                        },
-                        [](const MediaResult& aError) {
-                          return AllocateDecoderPromise::CreateAndReject(
-                              aError, __func__);
-                        });
-                return p;
+                CreateDecoderParams params{*config,
+                                           diagnostics,
+                                           imageContainer,
+                                           &result,
+                                           knowsCompositor,
+                                           crashHelper,
+                                           useNullDecoder,
+                                           noWrapper,
+                                           type,
+                                           onWaitingForKeyEvent,
+                                           options,
+                                           rate};
+                RefPtr<MediaDataDecoder> decoder = pdm->CreateDecoder(params);
+                if (decoder) {
+                  RefPtr<AllocationWrapper> wrapper =
+                      new AllocationWrapper(decoder.forget(), aToken.forget());
+                  return AllocateDecoderPromise::CreateAndResolve(wrapper,
+                                                                  __func__);
+                }
+                return AllocateDecoderPromise::CreateAndReject(result,
+                                                               __func__);
               },
               []() {
                 return AllocateDecoderPromise::CreateAndReject(
                     MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                                 "Allocation policy expired"),
                     __func__);
               });
   return p;
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -23,17 +23,16 @@
 #include "mozilla/RemoteDecoderModule.h"
 #include "mozilla/SharedThreadPool.h"
 #include "mozilla/StaticPrefs_media.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/SyncRunnable.h"
 #include "mozilla/TaskQueue.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "nsIXULRuntime.h"  // for BrowserTabsRemoteAutostart
-#include "nsPrintfCString.h"
 
 #ifdef XP_WIN
 #  include "WMFDecoderModule.h"
 #  include "mozilla/WindowsVersion.h"
 #endif
 #ifdef MOZ_FFVPX
 #  include "FFVPXRuntimeLinker.h"
 #endif
@@ -284,123 +283,121 @@ void PDMFactory::EnsureInit() {
 
   // Not on the main thread -> Sync-dispatch creation to main thread.
   nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadEventTarget();
   nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
       "PDMFactory::EnsureInit", std::move(initalization));
   SyncRunnable::DispatchToThread(mainTarget, runnable);
 }
 
-RefPtr<PlatformDecoderModule::CreateDecoderPromise> PDMFactory::CreateDecoder(
+already_AddRefed<MediaDataDecoder> PDMFactory::CreateDecoder(
     const CreateDecoderParams& aParams) {
+  RefPtr<MediaDataDecoder> decoder;
+  const TrackInfo& config = aParams.mConfig;
   if (aParams.mUseNullDecoder.mUse) {
     MOZ_ASSERT(mNullPDM);
-    return CreateDecoderWithPDM(mNullPDM, aParams);
-  }
-  bool isEncrypted = mEMEPDM && aParams.mConfig.mCrypto.IsEncrypted();
+    decoder = CreateDecoderWithPDM(mNullPDM, aParams);
+  } else {
+    bool isEncrypted = mEMEPDM && config.mCrypto.IsEncrypted();
+
+    if (isEncrypted) {
+      decoder = CreateDecoderWithPDM(mEMEPDM, aParams);
+    } else {
+      DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
+      if (diagnostics) {
+        // If libraries failed to load, the following loop over mCurrentPDMs
+        // will not even try to use them. So we record failures now.
+        diagnostics->SetFailureFlags(mFailureFlags);
+      }
 
-  if (isEncrypted) {
-    return CreateDecoderWithPDM(mEMEPDM, aParams);
+      for (auto& current : mCurrentPDMs) {
+        if (!current->Supports(SupportDecoderParams(aParams), diagnostics)) {
+          continue;
+        }
+        decoder = CreateDecoderWithPDM(current, aParams);
+        if (decoder) {
+          break;
+        }
+      }
+    }
   }
-
-  return CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync(aParams), 0);
+  if (!decoder) {
+    NS_WARNING("Unable to create a decoder, no platform found.");
+    return nullptr;
+  }
+  return decoder.forget();
 }
 
-RefPtr<PlatformDecoderModule::CreateDecoderPromise>
-PDMFactory::CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync&& aParams,
-                                       uint32_t aIndex) {
-  uint32_t i = aIndex;
-  auto params = SupportDecoderParams(aParams);
-  for (; i < mCurrentPDMs.Length(); i++) {
-    if (!mCurrentPDMs[i]->Supports(params, nullptr /* diagnostic */)) {
-      continue;
-    }
-    RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
-        CreateDecoderWithPDM(mCurrentPDMs[i], aParams)
-            ->Then(
-                GetCurrentSerialEventTarget(), __func__,
-                [](RefPtr<MediaDataDecoder>&& aDecoder) {
-                  return PlatformDecoderModule::CreateDecoderPromise::
-                      CreateAndResolve(std::move(aDecoder), __func__);
-                },
-                [self = RefPtr{this}, i, params = std::move(aParams)](
-                    const MediaResult& aError) mutable {
-                  // Try the next PDM.
-                  return self->CheckAndMaybeCreateDecoder(std::move(params),
-                                                          i + 1);
-                });
-    return p;
-  }
-  return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
-                  nsPrintfCString("Error no decoder found for %s",
-                                  aParams.mConfig->mMimeType.get())
-                      .get()),
-      __func__);
-}
-
-RefPtr<PlatformDecoderModule::CreateDecoderPromise>
-PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
-                                 const CreateDecoderParams& aParams) {
+already_AddRefed<MediaDataDecoder> PDMFactory::CreateDecoderWithPDM(
+    PlatformDecoderModule* aPDM, const CreateDecoderParams& aParams) {
   MOZ_ASSERT(aPDM);
-  MediaResult result = NS_OK;
+  RefPtr<MediaDataDecoder> m;
+  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) {
-      result = checkResult.mMediaResult;
+      if (diagnostics) {
+        diagnostics->SetVideoNotSupported();
+      }
+      if (result) {
+        *result = checkResult.mMediaResult;
+      }
     } else if (checkResult.mReason ==
                SupportChecker::Reason::kAudioFormatNotSupported) {
-      result = checkResult.mMediaResult;
+      if (diagnostics) {
+        diagnostics->SetAudioNotSupported();
+      }
+      if (result) {
+        *result = checkResult.mMediaResult;
+      }
     }
-    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-        result, __func__);
+    return nullptr;
   }
 
   if (config.IsAudio()) {
-    RefPtr<PlatformDecoderModule::CreateDecoderPromise> p;
-    p = aPDM->AsyncCreateDecoder(aParams)->Then(
-        GetCurrentSerialEventTarget(), __func__,
-        [params = CreateDecoderParamsForAsync(aParams)](
-            RefPtr<MediaDataDecoder>&& aDecoder) {
-          RefPtr<MediaDataDecoder> decoder = std::move(aDecoder);
-          if (!params.mNoWrapper.mDontUseWrapper) {
-            decoder =
-                new AudioTrimmer(decoder.forget(), CreateDecoderParams(params));
-          }
-          return PlatformDecoderModule::CreateDecoderPromise::CreateAndResolve(
-              decoder, __func__);
-        },
-        [](const MediaResult& aError) {
-          return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-              aError, __func__);
-        });
-    return p;
+    m = aPDM->CreateAudioDecoder(aParams);
+    if (m && !aParams.mNoWrapper.mDontUseWrapper) {
+      m = new AudioTrimmer(m.forget(), aParams);
+    }
+    return m.forget();
   }
 
   if (!config.IsVideo()) {
-    return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-        MediaResult(
-            NS_ERROR_DOM_MEDIA_FATAL_ERR,
-            RESULT_DETAIL(
-                "Decoder configuration error, expected audio or video.")),
-        __func__);
+    *result = MediaResult(
+        NS_ERROR_DOM_MEDIA_FATAL_ERR,
+        RESULT_DETAIL("Decoder configuration error, expected audio or video."));
+    return nullptr;
   }
 
   if ((MP4Decoder::IsH264(config.mMimeType) ||
        VPXDecoder::IsVPX(config.mMimeType)) &&
       !aParams.mUseNullDecoder.mUse && !aParams.mNoWrapper.mDontUseWrapper) {
-    return MediaChangeMonitor::Create(aPDM, aParams);
+    RefPtr<MediaChangeMonitor> h = new MediaChangeMonitor(aPDM, aParams);
+    const MediaResult result = h->GetLastError();
+    if (NS_SUCCEEDED(result) || result == NS_ERROR_NOT_INITIALIZED) {
+      // The MediaChangeMonitor either successfully created the wrapped decoder,
+      // or there wasn't enough initialization data to do so (such as what can
+      // happen with AVC3). Otherwise, there was some problem, for example WMF
+      // DLLs were missing.
+      m = std::move(h);
+    } else if (aParams.mError) {
+      *aParams.mError = result;
+    }
+  } else {
+    m = aPDM->CreateVideoDecoder(aParams);
   }
-  return aPDM->AsyncCreateDecoder(aParams);
+
+  return m.forget();
 }
 
 bool PDMFactory::SupportsMimeType(
     const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const {
   UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
   if (!trackInfo) {
     return false;
   }
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -27,18 +27,21 @@ class PDMFactory final {
   PDMFactory();
 
   // To be called in the content process only, used to determine which PDMs are
   // usable in their respective process.
   static already_AddRefed<PDMFactory> PDMFactoryForRdd();
   static already_AddRefed<PDMFactory> PDMFactoryForGpu();
 
   // Factory method that creates the appropriate PlatformDecoderModule for
-  // the platform we're running on.
-  RefPtr<PlatformDecoderModule::CreateDecoderPromise> CreateDecoder(
+  // 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> CreateDecoder(
       const CreateDecoderParams& aParams);
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const;
   bool Supports(const SupportDecoderParams& aParams,
                 DecoderDoctorDiagnostics* aDiagnostics) const;
 
   // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or
@@ -99,21 +102,18 @@ class PDMFactory final {
   // Startup the provided PDM and add it to our list if successful.
   bool StartupPDM(already_AddRefed<PlatformDecoderModule> aPDM,
                   bool aInsertAtBeginning = false);
   // Returns the first PDM in our list supporting the mimetype.
   already_AddRefed<PlatformDecoderModule> GetDecoderModule(
       const SupportDecoderParams& aParams,
       DecoderDoctorDiagnostics* aDiagnostics) const;
 
-  RefPtr<PlatformDecoderModule::CreateDecoderPromise> CreateDecoderWithPDM(
+  already_AddRefed<MediaDataDecoder> CreateDecoderWithPDM(
       PlatformDecoderModule* aPDM, const CreateDecoderParams& aParams);
-  RefPtr<PlatformDecoderModule::CreateDecoderPromise>
-  CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync&& aParams,
-                             uint32_t aIndex);
 
   nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs;
   RefPtr<PlatformDecoderModule> mEMEPDM;
   RefPtr<PlatformDecoderModule> mNullPDM;
 
   DecoderDoctorDiagnostics::FlagsSet mFailureFlags;
 
   friend class RemoteVideoDecoderParent;
deleted file mode 100644
--- a/dom/media/platforms/PlatformDecoderModule.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * 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/. */
-
-#include "PlatformDecoderModule.h"
-
-#include "ImageContainer.h"
-#include "nsPrintfCString.h"
-
-namespace mozilla {
-
-CreateDecoderParamsForAsync::CreateDecoderParamsForAsync(
-    const CreateDecoderParams& aParams)
-    : mConfig(aParams.mConfig.Clone()),
-      mImageContainer(aParams.mImageContainer),
-      mKnowsCompositor(aParams.mKnowsCompositor),
-      mCrashHelper(aParams.mCrashHelper),
-      mUseNullDecoder(aParams.mUseNullDecoder),
-      mNoWrapper(aParams.mNoWrapper),
-      mType(aParams.mType),
-      mOnWaitingForKeyEvent(aParams.mOnWaitingForKeyEvent),
-      mOptions(aParams.mOptions),
-      mRate(aParams.mRate) {}
-
-CreateDecoderParamsForAsync::CreateDecoderParamsForAsync(
-    CreateDecoderParamsForAsync&& aParams) = default;
-
-RefPtr<PlatformDecoderModule::CreateDecoderPromise>
-PlatformDecoderModule::AsyncCreateDecoder(const CreateDecoderParams& aParams) {
-  RefPtr<MediaDataDecoder> decoder;
-  MediaResult result = NS_OK;
-  if (aParams.mConfig.IsAudio()) {
-    decoder = CreateAudioDecoder(CreateDecoderParams{aParams, &result});
-  } else if (aParams.mConfig.IsVideo()) {
-    decoder = CreateVideoDecoder(CreateDecoderParams{aParams, &result});
-  }
-  if (!decoder) {
-    if (NS_FAILED(result)) {
-      return CreateDecoderPromise::CreateAndReject(result, __func__);
-    }
-    return CreateDecoderPromise::CreateAndReject(
-        MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
-                    nsPrintfCString("Error creating decoder for %s",
-                                    aParams.mConfig.mMimeType.get())
-                        .get()),
-        __func__);
-  }
-  return CreateDecoderPromise::CreateAndResolve(decoder, __func__);
-}
-
-}  // namespace mozilla
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -29,16 +29,17 @@ class AudioInfo;
 class VideoInfo;
 class MediaRawData;
 class DecoderDoctorDiagnostics;
 
 namespace layers {
 class ImageContainer;
 }  // namespace layers
 
+class GpuDecoderModule;
 class MediaDataDecoder;
 class RemoteDecoderModule;
 class CDMProxy;
 
 static LazyLogModule sPDMLog("PlatformDecoderModule");
 
 namespace media {
 
@@ -74,67 +75,24 @@ struct NoWrapper {
 struct VideoFrameRate {
   VideoFrameRate() = default;
   explicit VideoFrameRate(float aFramerate) : mValue(aFramerate) {}
   float mValue = 0.0f;
 };
 
 }  // namespace media
 
-struct CreateDecoderParams;
-struct CreateDecoderParamsForAsync {
-  using Option = media::Option;
-  using OptionSet = media::OptionSet;
-  explicit CreateDecoderParamsForAsync(const CreateDecoderParams& aParams);
-  CreateDecoderParamsForAsync(CreateDecoderParamsForAsync&& aParams);
-
-  const VideoInfo& VideoConfig() const {
-    MOZ_ASSERT(mConfig->IsVideo());
-    return *mConfig->GetAsVideoInfo();
-  }
-
-  const AudioInfo& AudioConfig() const {
-    MOZ_ASSERT(mConfig->IsAudio());
-    return *mConfig->GetAsAudioInfo();
-  }
-
-  UniquePtr<TrackInfo> mConfig;
-  const RefPtr<layers::ImageContainer> mImageContainer;
-  const RefPtr<layers::KnowsCompositor> mKnowsCompositor;
-  const RefPtr<GMPCrashHelper> mCrashHelper;
-  const media::UseNullDecoder mUseNullDecoder;
-  const media::NoWrapper mNoWrapper;
-  const TrackInfo::TrackType mType = TrackInfo::kUndefinedTrack;
-  std::function<MediaEventProducer<TrackInfo::TrackType>*()>
-      mOnWaitingForKeyEvent;
-  const OptionSet mOptions = OptionSet(Option::Default);
-  const media::VideoFrameRate mRate;
-};
-
 struct MOZ_STACK_CLASS CreateDecoderParams final {
   using Option = media::Option;
   using OptionSet = media::OptionSet;
   using UseNullDecoder = media::UseNullDecoder;
   using NoWrapper = media::NoWrapper;
   using VideoFrameRate = media::VideoFrameRate;
 
   explicit CreateDecoderParams(const TrackInfo& aConfig) : mConfig(aConfig) {}
-  CreateDecoderParams(const CreateDecoderParams& aParams) = default;
-
-  MOZ_IMPLICIT CreateDecoderParams(const CreateDecoderParamsForAsync& aParams)
-      : mConfig(*aParams.mConfig.get()),
-        mImageContainer(aParams.mImageContainer),
-        mKnowsCompositor(aParams.mKnowsCompositor),
-        mCrashHelper(aParams.mCrashHelper),
-        mUseNullDecoder(aParams.mUseNullDecoder),
-        mNoWrapper(aParams.mNoWrapper),
-        mType(aParams.mType),
-        mOnWaitingForKeyEvent(aParams.mOnWaitingForKeyEvent),
-        mOptions(aParams.mOptions),
-        mRate(aParams.mRate) {}
 
   template <typename T1, typename... Ts>
   CreateDecoderParams(const TrackInfo& aConfig, T1&& a1, Ts&&... args)
       : mConfig(aConfig) {
     Set(std::forward<T1>(a1), std::forward<Ts>(args)...);
   }
 
   template <typename T1, typename... Ts>
@@ -155,33 +113,33 @@ struct MOZ_STACK_CLASS CreateDecoderPara
 
   layers::LayersBackend GetLayersBackend() const {
     if (mKnowsCompositor) {
       return mKnowsCompositor->GetCompositorBackendType();
     }
     return layers::LayersBackend::LAYERS_NONE;
   }
 
-  // CreateDecoderParams is a MOZ_STACK_CLASS, it is only used to
-  // simplify the passing of arguments to Create*Decoder.
-  // It is safe to use references and raw pointers.
   const TrackInfo& mConfig;
+  DecoderDoctorDiagnostics* mDiagnostics = nullptr;
   layers::ImageContainer* mImageContainer = nullptr;
   MediaResult* mError = nullptr;
-  layers::KnowsCompositor* mKnowsCompositor = nullptr;
-  GMPCrashHelper* mCrashHelper = nullptr;
+  RefPtr<layers::KnowsCompositor> mKnowsCompositor;
+  RefPtr<GMPCrashHelper> mCrashHelper;
   media::UseNullDecoder mUseNullDecoder;
   media::NoWrapper mNoWrapper;
   TrackInfo::TrackType mType = TrackInfo::kUndefinedTrack;
-  std::function<MediaEventProducer<TrackInfo::TrackType>*()>
-      mOnWaitingForKeyEvent;
+  MediaEventProducer<TrackInfo::TrackType>* mOnWaitingForKeyEvent = nullptr;
   OptionSet mOptions = OptionSet(Option::Default);
   media::VideoFrameRate mRate;
 
  private:
+  void Set(DecoderDoctorDiagnostics* aDiagnostics) {
+    mDiagnostics = aDiagnostics;
+  }
   void Set(layers::ImageContainer* aImageContainer) {
     mImageContainer = aImageContainer;
   }
   void Set(MediaResult* aError) { mError = aError; }
   void Set(GMPCrashHelper* aCrashHelper) { mCrashHelper = aCrashHelper; }
   void Set(UseNullDecoder aUseNullDecoder) {
     mUseNullDecoder = aUseNullDecoder;
   }
@@ -190,37 +148,19 @@ struct MOZ_STACK_CLASS CreateDecoderPara
   void Set(VideoFrameRate aRate) { mRate = aRate; }
   void Set(layers::KnowsCompositor* aKnowsCompositor) {
     if (aKnowsCompositor) {
       mKnowsCompositor = aKnowsCompositor;
       MOZ_ASSERT(aKnowsCompositor->IsThreadSafe());
     }
   }
   void Set(TrackInfo::TrackType aType) { mType = aType; }
-  void Set(std::function<MediaEventProducer<TrackInfo::TrackType>*()>&&
-               aOnWaitingForKey) {
-    mOnWaitingForKeyEvent = std::move(aOnWaitingForKey);
-  }
-  void Set(const std::function<MediaEventProducer<TrackInfo::TrackType>*()>&
-               aOnWaitingForKey) {
+  void Set(MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey) {
     mOnWaitingForKeyEvent = aOnWaitingForKey;
   }
-  void Set(const CreateDecoderParams& aParams) {
-    // Set all but mTrackInfo;
-    mImageContainer = aParams.mImageContainer;
-    mError = aParams.mError;
-    mKnowsCompositor = aParams.mKnowsCompositor;
-    mCrashHelper = aParams.mCrashHelper;
-    mUseNullDecoder = aParams.mUseNullDecoder;
-    mNoWrapper = aParams.mNoWrapper;
-    mType = aParams.mType;
-    mOnWaitingForKeyEvent = aParams.mOnWaitingForKeyEvent;
-    mOptions = aParams.mOptions;
-    mRate = aParams.mRate;
-  }
   template <typename T1, typename T2, typename... Ts>
   void Set(T1&& a1, T2&& a2, Ts&&... args) {
     Set(std::forward<T1>(a1));
     Set(std::forward<T2>(a2), std::forward<Ts>(args)...);
   }
 };
 
 struct MOZ_STACK_CLASS SupportDecoderParams final {
@@ -229,16 +169,17 @@ struct MOZ_STACK_CLASS SupportDecoderPar
   using UseNullDecoder = media::UseNullDecoder;
   using NoWrapper = media::NoWrapper;
   using VideoFrameRate = media::VideoFrameRate;
 
   explicit SupportDecoderParams(const TrackInfo& aConfig) : mConfig(aConfig) {}
 
   explicit SupportDecoderParams(const CreateDecoderParams& aParams)
       : mConfig(aParams.mConfig),
+        mDiagnostics(aParams.mDiagnostics),
         mError(aParams.mError),
         mKnowsCompositor(aParams.mKnowsCompositor),
         mUseNullDecoder(aParams.mUseNullDecoder),
         mNoWrapper(aParams.mNoWrapper),
         mOptions(aParams.mOptions),
         mRate(aParams.mRate) {}
 
   template <typename T1, typename... Ts>
@@ -324,65 +265,64 @@ class PlatformDecoderModule {
     if (!SupportsMimeType(trackInfo.mMimeType, aDiagnostics)) {
       return false;
     }
     const auto* videoInfo = trackInfo.GetAsVideoInfo();
     return !videoInfo ||
            SupportsColorDepth(videoInfo->mColorDepth, aDiagnostics);
   }
 
-  typedef MozPromise<RefPtr<MediaDataDecoder>, MediaResult,
-                     /* IsExclusive = */ true>
-      CreateDecoderPromise;
-
  protected:
   PlatformDecoderModule() = default;
   virtual ~PlatformDecoderModule() = default;
 
   friend class MediaChangeMonitor;
   friend class PDMFactory;
+  friend class GpuDecoderModule;
   friend class EMEDecoderModule;
   friend class RemoteDecoderModule;
 
   // Indicates if the PlatformDecoderModule supports decoding of aColorDepth.
   // Should override this method when the platform can support color depth != 8.
   virtual bool SupportsColorDepth(
       gfx::ColorDepth aColorDepth,
       DecoderDoctorDiagnostics* aDiagnostics) const {
     return aColorDepth == gfx::ColorDepth::COLOR_8;
   }
 
   // Creates a Video decoder. The layers backend is passed in so that
   // decoders can determine whether hardware accelerated decoding can be used.
+  // Asynchronous decoding of video should be done in runnables dispatched
+  // to aVideoTaskQueue. If the task queue isn't needed, the decoder should
+  // not hold a reference to it.
   // On Windows the task queue's threads in have MSCOM initialized with
   // COINIT_MULTITHREADED.
   // Returns nullptr if the decoder can't be created.
-  // It is not safe to store a reference to aParams or aParams.mConfig as the
-  // object isn't guaranteed to live after the call.
+  // It is safe to store a reference to aConfig.
+  // This is called on the decode task queue.
   // CreateVideoDecoder may need to make additional checks if the
   // CreateDecoderParams argument is actually supported and return nullptr if
   // not to allow for fallback PDMs to be tried.
   virtual already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
       const CreateDecoderParams& aParams) = 0;
 
   // Creates an Audio decoder with the specified properties.
+  // Asynchronous decoding of audio should be done in runnables dispatched to
+  // aAudioTaskQueue. If the task queue isn't needed, the decoder should
+  // not hold a reference to it.
   // Returns nullptr if the decoder can't be created.
   // On Windows the task queue's threads in have MSCOM initialized with
   // COINIT_MULTITHREADED.
-  // It is not safe to store a reference to aParams or aParams.mConfig as the
-  // object isn't guaranteed to live after the call.
+  // It is safe to store a reference to aConfig.
+  // This is called on the decode task queue.
   // CreateAudioDecoder may need to make additional checks if the
   // CreateDecoderParams argument is actually supported and return nullptr if
   // not to allow for fallback PDMs to be tried.
   virtual already_AddRefed<MediaDataDecoder> CreateAudioDecoder(
       const CreateDecoderParams& aParams) = 0;
-
-  // Asychronously create a decoder.
-  virtual RefPtr<CreateDecoderPromise> AsyncCreateDecoder(
-      const CreateDecoderParams& aParams);
 };
 
 DDLoggedTypeDeclName(MediaDataDecoder);
 
 // MediaDataDecoder is the interface exposed by decoders created by the
 // PlatformDecoderModule's Create*Decoder() functions. The type of
 // media data that the decoder accepts as valid input and produces as
 // output is determined when the MediaDataDecoder is created.
@@ -390,34 +330,37 @@ DDLoggedTypeDeclName(MediaDataDecoder);
 // Unless otherwise noted, all functions are only called on the decode task
 // queue.  An exception is the MediaDataDecoder in
 // MediaFormatReader::IsVideoAccelerated() for which all calls (Init(),
 // IsHardwareAccelerated(), and Shutdown()) are from the main thread.
 //
 // Don't block inside these functions, unless it's explicitly noted that you
 // should (like in Flush()).
 //
-// Decoding is done asynchronously.
+// Decoding is done asynchronously. Any async work can be done on the
+// TaskQueue passed into the PlatformDecoderModules's Create*Decoder()
+// function. This may not be necessary for platforms with async APIs
+// for decoding.
 class MediaDataDecoder : public DecoderDoctorLifeLogger<MediaDataDecoder> {
  protected:
   virtual ~MediaDataDecoder() = default;
 
  public:
   typedef TrackInfo::TrackType TrackType;
   typedef nsTArray<RefPtr<MediaData>> DecodedData;
   typedef MozPromise<TrackType, MediaResult, /* IsExclusive = */ true>
       InitPromise;
   typedef MozPromise<DecodedData, MediaResult, /* IsExclusive = */ true>
       DecodePromise;
   typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> FlushPromise;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDataDecoder)
 
   // Initialize the decoder. The decoder should be ready to decode once
-  // the promise resolves. The decoder should do any initialization here, rather
+  // promise resolves. The decoder should do any initialization here, rather
   // than in its constructor or PlatformDecoderModule::Create*Decoder(),
   // so that if the MediaFormatReader needs to shutdown during initialization,
   // it can call Shutdown() to cancel this operation. Any initialization
   // that requires blocking the calling thread in this function *must*
   // be done here so that it can be canceled by calling Shutdown()!
   // Methods Decode, DecodeBatch, Drain, Flush, Shutdown are guaranteed to be
   // called on the thread where Init() first ran.
   virtual RefPtr<InitPromise> Init() = 0;
@@ -465,19 +408,16 @@ class MediaDataDecoder : public DecoderD
   virtual RefPtr<FlushPromise> Flush() = 0;
 
   // Cancels all init/decode/drain operations, and shuts down the decoder. The
   // platform decoder should clean up any resources it's using and release
   // memory etc. The shutdown promise will be resolved once the decoder has
   // completed shutdown. The reader calls Flush() before calling Shutdown(). The
   // reader will delete the decoder once the promise is resolved.
   // The ShutdownPromise must only ever be resolved.
-  // Shutdown() may not be called if init hasn't been called first. It is
-  // possible under some circumstances for the decoder to be deleted without
-  // Init having been called first.
   virtual RefPtr<ShutdownPromise> Shutdown() = 0;
 
   // Called from the state machine task queue or main thread. Decoder needs to
   // decide whether or not hardware acceleration is supported after creating.
   // It doesn't need to call Init() before calling this function.
   virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const {
     return false;
   }
--- a/dom/media/platforms/agnostic/AOMDecoder.h
+++ b/dom/media/platforms/agnostic/AOMDecoder.h
@@ -45,14 +45,14 @@ class AOMDecoder : public MediaDataDecod
   RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample);
 
   const RefPtr<layers::ImageContainer> mImageContainer;
   const RefPtr<TaskQueue> mTaskQueue;
 
   // AOM decoder state
   aom_codec_ctx_t mCodec;
 
-  const VideoInfo mInfo;
+  const VideoInfo& mInfo;
 };
 
 }  // namespace mozilla
 
 #endif  // AOMDecoder_h_
--- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp
@@ -119,17 +119,17 @@ bool AgnosticDecoderModule::Supports(
   MOZ_LOG(sPDMLog, LogLevel::Debug,
           ("Agnostic decoder %s requested type",
            supports ? "supports" : "rejects"));
   return supports;
 }
 
 already_AddRefed<MediaDataDecoder> AgnosticDecoderModule::CreateVideoDecoder(
     const CreateDecoderParams& aParams) {
-  if (!Supports(SupportDecoderParams(aParams), nullptr /* diagnostic */)) {
+  if (!Supports(SupportDecoderParams(aParams), aParams.mDiagnostics)) {
     return nullptr;
   }
   RefPtr<MediaDataDecoder> m;
 
   if (VPXDecoder::IsVPX(aParams.mConfig.mMimeType)) {
     m = new VPXDecoder(aParams);
   }
 #ifdef MOZ_AV1
@@ -150,17 +150,17 @@ already_AddRefed<MediaDataDecoder> Agnos
     m = new TheoraDecoder(aParams);
   }
 
   return m.forget();
 }
 
 already_AddRefed<MediaDataDecoder> AgnosticDecoderModule::CreateAudioDecoder(
     const CreateDecoderParams& aParams) {
-  if (!Supports(SupportDecoderParams(aParams), nullptr /* diagnostic */)) {
+  if (!Supports(SupportDecoderParams(aParams), aParams.mDiagnostics)) {
     return nullptr;
   }
   RefPtr<MediaDataDecoder> m;
 
   const TrackInfo& config = aParams.mConfig;
   if (VorbisDataDecoder::IsVorbis(config.mMimeType)) {
     m = new VorbisDataDecoder(aParams);
   } else if (OpusDataDecoder::IsOpus(config.mMimeType)) {
--- a/dom/media/platforms/agnostic/DAV1DDecoder.h
+++ b/dom/media/platforms/agnostic/DAV1DDecoder.h
@@ -35,17 +35,17 @@ class DAV1DDecoder : public MediaDataDec
  private:
   ~DAV1DDecoder() = default;
   RefPtr<DecodePromise> InvokeDecode(MediaRawData* aSample);
   int GetPicture(DecodedData& aData, MediaResult& aResult);
   already_AddRefed<VideoData> ConstructImage(const Dav1dPicture& aPicture);
 
   Dav1dContext* mContext = nullptr;
 
-  const VideoInfo mInfo;
+  const VideoInfo& mInfo;
   const RefPtr<TaskQueue> mTaskQueue;
   const RefPtr<layers::ImageContainer> mImageContainer;
   const RefPtr<layers::KnowsCompositor> mImageAllocator;
 
   // Keep the buffers alive until dav1d
   // does not need them any more.
   MediaRawDataHashtable mDecodingBuffers;
 };
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -34,25 +34,25 @@ OpusDataDecoder::OpusDataDecoder(const C
       mDecodedHeader(false),
       mPaddingDiscarded(false),
       mFrames(0),
       mChannelMap(AudioConfig::ChannelLayout::UNKNOWN_MAP),
       mDefaultPlaybackDeviceMono(aParams.mOptions.contains(
           CreateDecoderParams::Option::DefaultPlaybackDeviceMono)) {}
 
 OpusDataDecoder::~OpusDataDecoder() {
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
   if (mOpusDecoder) {
     opus_multistream_decoder_destroy(mOpusDecoder);
     mOpusDecoder = nullptr;
   }
 }
 
 RefPtr<ShutdownPromise> OpusDataDecoder::Shutdown() {
-  // mThread may not be set if Init hasn't been called first.
-  MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 void OpusDataDecoder::AppendCodecDelay(MediaByteBuffer* config,
                                        uint64_t codecDelayUS) {
   uint8_t buffer[sizeof(uint64_t)];
   BigEndian::writeUint64(buffer, codecDelayUS);
   config->AppendElements(buffer, sizeof(uint64_t));
--- a/dom/media/platforms/agnostic/OpusDecoder.h
+++ b/dom/media/platforms/agnostic/OpusDecoder.h
@@ -42,17 +42,17 @@ class OpusDataDecoder : public MediaData
   // from the container (if any) and to precede the OpusHead
   // block in the CodecSpecificConfig buffer to verify the
   // values match.
   static void AppendCodecDelay(MediaByteBuffer* config, uint64_t codecDelayUS);
 
  private:
   nsresult DecodeHeader(const unsigned char* aData, size_t aLength);
 
-  const AudioInfo mInfo;
+  const AudioInfo& mInfo;
   nsCOMPtr<nsISerialEventTarget> mThread;
 
   // Opus decoder state
   UniquePtr<OpusParser> mOpusParser;
   OpusMSDecoder* mOpusDecoder;
 
   uint16_t mSkip;  // Samples left to trim before playback.
   bool mDecodedHeader;
--- a/dom/media/platforms/agnostic/TheoraDecoder.h
+++ b/dom/media/platforms/agnostic/TheoraDecoder.h
@@ -46,14 +46,14 @@ class TheoraDecoder : public MediaDataDe
 
   // Theora header & decoder state
   th_info mTheoraInfo;
   th_comment mTheoraComment;
   th_setup_info* mTheoraSetupInfo;
   th_dec_ctx* mTheoraDecoderContext;
   int mPacketCount;
 
-  const VideoInfo mInfo;
+  const VideoInfo& mInfo;
 };
 
 }  // namespace mozilla
 
 #endif
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -204,17 +204,17 @@ class VPXDecoder : public MediaDataDecod
   const RefPtr<TaskQueue> mTaskQueue;
 
   // VPx decoder state
   vpx_codec_ctx_t mVPX;
 
   // VPx alpha decoder state
   vpx_codec_ctx_t mVPXAlpha;
 
-  const VideoInfo mInfo;
+  const VideoInfo& mInfo;
 
   const Codec mCodec;
   const bool mLowLatency;
 };
 
 }  // namespace mozilla
 
 #endif
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -37,25 +37,25 @@ VorbisDataDecoder::VorbisDataDecoder(con
   // destructor is called before |Init|.
   PodZero(&mVorbisBlock);
   PodZero(&mVorbisDsp);
   PodZero(&mVorbisInfo);
   PodZero(&mVorbisComment);
 }
 
 VorbisDataDecoder::~VorbisDataDecoder() {
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
   vorbis_block_clear(&mVorbisBlock);
   vorbis_dsp_clear(&mVorbisDsp);
   vorbis_info_clear(&mVorbisInfo);
   vorbis_comment_clear(&mVorbisComment);
 }
 
 RefPtr<ShutdownPromise> VorbisDataDecoder::Shutdown() {
-  // mThread may not be set if Init hasn't been called first.
-  MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 RefPtr<MediaDataDecoder::InitPromise> VorbisDataDecoder::Init() {
   mThread = GetCurrentSerialEventTarget();
   vorbis_info_init(&mVorbisInfo);
   vorbis_comment_init(&mVorbisComment);
   PodZero(&mVorbisDsp);
--- a/dom/media/platforms/agnostic/VorbisDecoder.h
+++ b/dom/media/platforms/agnostic/VorbisDecoder.h
@@ -37,17 +37,17 @@ class VorbisDataDecoder : public MediaDa
 
   // Return true if mimetype is Vorbis
   static bool IsVorbis(const nsACString& aMimeType);
   static const AudioConfig::Channel* VorbisLayout(uint32_t aChannels);
 
  private:
   nsresult DecodeHeader(const unsigned char* aData, size_t aLength);
 
-  const AudioInfo mInfo;
+  const AudioInfo& mInfo;
   nsCOMPtr<nsISerialEventTarget> mThread;
 
   // Vorbis decoder state
   vorbis_info mVorbisInfo;
   vorbis_comment mVorbisComment;
   vorbis_dsp_state mVorbisDsp;
   vorbis_block mVorbisBlock;
 
--- a/dom/media/platforms/agnostic/WAVDecoder.cpp
+++ b/dom/media/platforms/agnostic/WAVDecoder.cpp
@@ -42,18 +42,17 @@ int16_t DecodeULawSample(uint8_t aValue)
   int16_t sample = (33 + 2 * mantissa) * (2 << (exponent + 1)) - 33;
   return sign * sample;
 }
 
 WaveDataDecoder::WaveDataDecoder(const CreateDecoderParams& aParams)
     : mInfo(aParams.AudioConfig()) {}
 
 RefPtr<ShutdownPromise> WaveDataDecoder::Shutdown() {
-  // mThread may not be set if Init hasn't been called first.
-  MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 RefPtr<MediaDataDecoder::InitPromise> WaveDataDecoder::Init() {
   mThread = GetCurrentSerialEventTarget();
   return InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__);
 }
 
--- a/dom/media/platforms/agnostic/WAVDecoder.h
+++ b/dom/media/platforms/agnostic/WAVDecoder.h
@@ -26,14 +26,14 @@ class WaveDataDecoder : public MediaData
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
   nsCString GetDescriptionName() const override {
     return "wave audio decoder"_ns;
   }
 
  private:
-  const AudioInfo mInfo;
+  const AudioInfo& mInfo;
   nsCOMPtr<nsISerialEventTarget> mThread;
 };
 
 }  // namespace mozilla
 #endif
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -9,21 +9,21 @@
 #include <inttypes.h>
 
 #include "Adts.h"
 #include "BlankDecoderModule.h"
 #include "ChromiumCDMVideoDecoder.h"
 #include "DecryptThroughputLimit.h"
 #include "GMPDecoderModule.h"
 #include "GMPService.h"
-#include "GMPVideoDecoder.h"
-#include "MP4Decoder.h"
 #include "MediaInfo.h"
 #include "PDMFactory.h"
 #include "mozilla/CDMProxy.h"
+#include "GMPVideoDecoder.h"
+#include "MP4Decoder.h"
 #include "mozilla/EMEUtils.h"
 #include "mozilla/StaticPrefs_media.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "nsClassHashtable.h"
 #include "nsServiceManagerUtils.h"
 
 namespace mozilla {
@@ -69,18 +69,17 @@ class ADTSSampleConverter {
   const uint8_t mFrequencyIndex;
 };
 
 class EMEDecryptor : public MediaDataDecoder,
                      public DecoderDoctorLifeLogger<EMEDecryptor> {
  public:
   EMEDecryptor(MediaDataDecoder* aDecoder, CDMProxy* aProxy,
                TrackInfo::TrackType aType,
-               const std::function<MediaEventProducer<TrackInfo::TrackType>*()>&
-                   aOnWaitingForKey,
+               MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey,
                UniquePtr<ADTSSampleConverter> aConverter = nullptr)
       : mDecoder(aDecoder),
         mProxy(aProxy),
         mSamplesWaitingForKey(
             new SamplesWaitingForKey(mProxy, aType, aOnWaitingForKey)),
         mADTSSampleConverter(std::move(aConverter)),
         mIsShutdown(false) {
     DDLINKCHILD("decoder", mDecoder.get());
@@ -238,18 +237,17 @@ class EMEDecryptor : public MediaDataDec
       auto holder = iter.UserData();
       holder->DisconnectIfExists();
       iter.Remove();
     }
     return mDecoder->Drain();
   }
 
   RefPtr<ShutdownPromise> Shutdown() override {
-    // mThread may not be set if Init hasn't been called first.
-    MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+    MOZ_ASSERT(mThread->IsOnCurrentThread());
     MOZ_ASSERT(!mIsShutdown);
     mIsShutdown = true;
     mSamplesWaitingForKey->BreakCycles();
     mSamplesWaitingForKey = nullptr;
     RefPtr<MediaDataDecoder> decoder = std::move(mDecoder);
     mProxy = nullptr;
     return decoder->Shutdown();
   }
@@ -371,94 +369,74 @@ static already_AddRefed<MediaDataDecoder
   RefPtr<MediaDataDecoderProxy> decoder(
       new EMEMediaDataDecoderProxy(aParams,
                                    do_AddRef(new ChromiumCDMVideoDecoder(
                                        GMPVideoDecoderParams(aParams), aProxy)),
                                    thread.forget(), aProxy));
   return decoder.forget();
 }
 
-RefPtr<EMEDecoderModule::CreateDecoderPromise>
-EMEDecoderModule::AsyncCreateDecoder(const CreateDecoderParams& aParams) {
+already_AddRefed<MediaDataDecoder> EMEDecoderModule::CreateVideoDecoder(
+    const CreateDecoderParams& aParams) {
   MOZ_ASSERT(aParams.mConfig.mCrypto.IsEncrypted());
-  MOZ_ASSERT(mPDM);
-
-  if (aParams.mConfig.IsVideo()) {
-    if (StaticPrefs::media_eme_video_blank()) {
-      EME_LOG(
-          "EMEDecoderModule::CreateVideoDecoder() creating a blank decoder.");
-      RefPtr<PlatformDecoderModule> m(BlankDecoderModule::Create());
-      RefPtr<MediaDataDecoder> decoder = m->CreateVideoDecoder(aParams);
-      return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve(decoder,
-                                                                      __func__);
-    }
 
-    if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) {
-      // GMP decodes. Assume that means it can decrypt too.
-      return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve(
-          CreateDecoderWrapper(mProxy, aParams), __func__);
-    }
-
-    RefPtr<EMEDecoderModule::CreateDecoderPromise> p =
-        mPDM->CreateDecoder(aParams)->Then(
-            GetCurrentSerialEventTarget(), __func__,
-            [self = RefPtr{this},
-             params = CreateDecoderParamsForAsync(aParams)](
-                RefPtr<MediaDataDecoder>&& aDecoder) {
-              RefPtr<MediaDataDecoder> emeDecoder(
-                  new EMEDecryptor(aDecoder, self->mProxy, params.mType,
-                                   params.mOnWaitingForKeyEvent));
-              return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve(
-                  emeDecoder, __func__);
-            },
-            [](const MediaResult& aError) {
-              return EMEDecoderModule::CreateDecoderPromise::CreateAndReject(
-                  aError, __func__);
-            });
-    return p;
+  if (StaticPrefs::media_eme_video_blank()) {
+    EME_LOG("EMEDecoderModule::CreateVideoDecoder() creating a blank decoder.");
+    RefPtr<PlatformDecoderModule> m(BlankDecoderModule::Create());
+    return m->CreateVideoDecoder(aParams);
   }
 
-  MOZ_ASSERT(aParams.mConfig.IsAudio());
+  if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) {
+    // GMP decodes. Assume that means it can decrypt too.
+    RefPtr<MediaDataDecoderProxy> wrapper =
+        CreateDecoderWrapper(mProxy, aParams);
+    return wrapper.forget();
+  }
+
+  MOZ_ASSERT(mPDM);
+  RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams));
+  if (!decoder) {
+    return nullptr;
+  }
+
+  RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(
+      decoder, mProxy, aParams.mType, aParams.mOnWaitingForKeyEvent));
+  return emeDecoder.forget();
+}
+
+already_AddRefed<MediaDataDecoder> EMEDecoderModule::CreateAudioDecoder(
+    const CreateDecoderParams& aParams) {
+  MOZ_ASSERT(aParams.mConfig.mCrypto.IsEncrypted());
 
   // We don't support using the GMP to decode audio.
   MOZ_ASSERT(!SupportsMimeType(aParams.mConfig.mMimeType, nullptr));
   MOZ_ASSERT(mPDM);
 
   if (StaticPrefs::media_eme_audio_blank()) {
     EME_LOG("EMEDecoderModule::CreateAudioDecoder() creating a blank decoder.");
     RefPtr<PlatformDecoderModule> m(BlankDecoderModule::Create());
-    RefPtr<MediaDataDecoder> decoder = m->CreateAudioDecoder(aParams);
-    return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve(decoder,
-                                                                    __func__);
+    return m->CreateAudioDecoder(aParams);
   }
 
   UniquePtr<ADTSSampleConverter> converter = nullptr;
   if (MP4Decoder::IsAAC(aParams.mConfig.mMimeType)) {
     // The CDM expects encrypted AAC to be in ADTS format.
     // See bug 1433344.
     converter = MakeUnique<ADTSSampleConverter>(aParams.AudioConfig());
   }
 
-  RefPtr<EMEDecoderModule::CreateDecoderPromise> p =
-      mPDM->CreateDecoder(aParams)->Then(
-          GetCurrentSerialEventTarget(), __func__,
-          [self = RefPtr{this}, params = CreateDecoderParamsForAsync(aParams),
-           converter = std::move(converter)](
-              RefPtr<MediaDataDecoder>&& aDecoder) mutable {
-            RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(
-                aDecoder, self->mProxy, params.mType,
-                params.mOnWaitingForKeyEvent, std::move(converter)));
-            return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve(
-                emeDecoder, __func__);
-          },
-          [](const MediaResult& aError) {
-            return EMEDecoderModule::CreateDecoderPromise::CreateAndReject(
-                aError, __func__);
-          });
-  return p;
+  RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams));
+  if (!decoder) {
+    return nullptr;
+  }
+
+  RefPtr<MediaDataDecoder> emeDecoder(
+      new EMEDecryptor(decoder, mProxy, aParams.mType,
+                       aParams.mOnWaitingForKeyEvent, std::move(converter)));
+  return emeDecoder.forget();
 }
 
 bool EMEDecoderModule::SupportsMimeType(
     const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const {
   Maybe<nsCString> gmp;
   gmp.emplace(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
   return GMPDecoderModule::SupportsMimeType(aMimeType, gmp);
 }
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
@@ -16,30 +16,23 @@ namespace mozilla {
 class CDMProxy;
 class PDMFactory;
 
 class EMEDecoderModule : public PlatformDecoderModule {
  public:
   EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM);
 
  protected:
-  RefPtr<CreateDecoderPromise> AsyncCreateDecoder(
+  // Decode thread.
+  already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
       const CreateDecoderParams& aParams) override;
 
   // Decode thread.
-  already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
-      const CreateDecoderParams& aParams) override {
-    MOZ_CRASH("Not used");
-  }
-
-  // Decode thread.
   already_AddRefed<MediaDataDecoder> CreateAudioDecoder(
-      const CreateDecoderParams& aParams) override {
-    MOZ_CRASH("Not used");
-  }
+      const CreateDecoderParams& aParams) override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
 
  private:
   virtual ~EMEDecoderModule();
   RefPtr<CDMProxy> mProxy;
   // Will be null if CDM has decoding capability.
--- a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp
+++ b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp
@@ -1,32 +1,30 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "SamplesWaitingForKey.h"
-
 #include "MediaData.h"
 #include "MediaEventSource.h"
 #include "mozilla/CDMCaps.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/TaskQueue.h"
 
 namespace mozilla {
 
 SamplesWaitingForKey::SamplesWaitingForKey(
     CDMProxy* aProxy, TrackInfo::TrackType aType,
-    const std::function<MediaEventProducer<TrackInfo::TrackType>*()>&
-        aOnWaitingForKeyEvent)
+    MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey)
     : mMutex("SamplesWaitingForKey"),
       mProxy(aProxy),
       mType(aType),
-      mOnWaitingForKeyEvent(aOnWaitingForKeyEvent) {}
+      mOnWaitingForKeyEvent(aOnWaitingForKey) {}
 
 SamplesWaitingForKey::~SamplesWaitingForKey() { Flush(); }
 
 RefPtr<SamplesWaitingForKey::WaitForKeyPromise>
 SamplesWaitingForKey::WaitIfKeyNotUsable(MediaRawData* aSample) {
   if (!aSample || !aSample->mCrypto.IsEncrypted() || !mProxy) {
     return WaitForKeyPromise::CreateAndResolve(aSample, __func__);
   }
@@ -37,18 +35,18 @@ SamplesWaitingForKey::WaitIfKeyNotUsable
   }
   SampleEntry entry;
   entry.mSample = aSample;
   RefPtr<WaitForKeyPromise> p = entry.mPromise.Ensure(__func__);
   {
     MutexAutoLock lock(mMutex);
     mSamples.AppendElement(std::move(entry));
   }
-  if (mOnWaitingForKeyEvent && mOnWaitingForKeyEvent()) {
-    mOnWaitingForKeyEvent()->Notify(mType);
+  if (mOnWaitingForKeyEvent) {
+    mOnWaitingForKeyEvent->Notify(mType);
   }
   caps->NotifyWhenKeyIdUsable(aSample->mCrypto.mKeyId, this);
   return p;
 }
 
 void SamplesWaitingForKey::NotifyUsable(const CencKeyId& aKeyId) {
   MutexAutoLock lock(mMutex);
   size_t i = 0;
--- a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h
+++ b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h
@@ -2,18 +2,16 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 SamplesWaitingForKey_h_
 #define SamplesWaitingForKey_h_
 
-#include <functional>
-
 #include "MediaInfo.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
 
 typedef nsTArray<uint8_t> CencKeyId;
@@ -29,18 +27,17 @@ class SamplesWaitingForKey {
  public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SamplesWaitingForKey)
 
   typedef MozPromise<RefPtr<MediaRawData>, bool, /* IsExclusive = */ true>
       WaitForKeyPromise;
 
   SamplesWaitingForKey(
       CDMProxy* aProxy, TrackInfo::TrackType aType,
-      const std::function<MediaEventProducer<TrackInfo::TrackType>*()>&
-          aOnWaitingForKeyEvent);
+      MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey);
 
   // Returns a promise that will be resolved if or when a key for decoding the
   // sample becomes usable.
   RefPtr<WaitForKeyPromise> WaitIfKeyNotUsable(MediaRawData* aSample);
 
   void NotifyUsable(const CencKeyId& aKeyId);
 
   void Flush();
@@ -54,15 +51,14 @@ class SamplesWaitingForKey {
   Mutex mMutex;
   RefPtr<CDMProxy> mProxy;
   struct SampleEntry {
     RefPtr<MediaRawData> mSample;
     MozPromiseHolder<WaitForKeyPromise> mPromise;
   };
   nsTArray<SampleEntry> mSamples;
   const TrackInfo::TrackType mType;
-  const std::function<MediaEventProducer<TrackInfo::TrackType>*()>
-      mOnWaitingForKeyEvent;
+  MediaEventProducer<TrackInfo::TrackType>* const mOnWaitingForKeyEvent;
 };
 
 }  // namespace mozilla
 
 #endif  //  SamplesWaitingForKey_h_
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.cpp
@@ -28,16 +28,17 @@ static bool IsOnGMPThread() {
   MOZ_ASSERT(NS_SUCCEEDED(rv) && gmpThread);
   return gmpThread->IsOnCurrentThread();
 }
 #endif
 
 GMPVideoDecoderParams::GMPVideoDecoderParams(const CreateDecoderParams& aParams)
     : mConfig(aParams.VideoConfig()),
       mImageContainer(aParams.mImageContainer),
+      mLayersBackend(aParams.GetLayersBackend()),
       mCrashHelper(aParams.mCrashHelper) {}
 
 void GMPVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame) {
   GMPUniquePtr<GMPVideoi420Frame> decodedFrame(aDecodedFrame);
 
   MOZ_ASSERT(IsOnGMPThread());
 
   VideoData::YCbCrBuffer b;
--- a/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
+++ b/dom/media/platforms/agnostic/gmp/GMPVideoDecoder.h
@@ -11,22 +11,23 @@
 #  include "ImageContainer.h"
 #  include "MediaDataDecoderProxy.h"
 #  include "MediaInfo.h"
 #  include "PlatformDecoderModule.h"
 #  include "mozIGeckoMediaPluginService.h"
 
 namespace mozilla {
 
-struct MOZ_STACK_CLASS GMPVideoDecoderParams {
+struct GMPVideoDecoderParams {
   explicit GMPVideoDecoderParams(const CreateDecoderParams& aParams);
 
   const VideoInfo& mConfig;
   layers::ImageContainer* mImageContainer;
-  GMPCrashHelper* mCrashHelper;
+  layers::LayersBackend mLayersBackend;
+  RefPtr<GMPCrashHelper> mCrashHelper;
 };
 
 DDLoggedTypeDeclNameAndBase(GMPVideoDecoder, MediaDataDecoder);
 
 class GMPVideoDecoder : public MediaDataDecoder,
                         public GMPVideoDecoderCallbackProxy,
                         public DecoderDoctorLifeLogger<GMPVideoDecoder> {
  public:
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -1,26 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
-#include <jni.h>
-
+#include "mozilla/java/HardwareCodecCapabilityUtilsWrappers.h"
 #include "MediaInfo.h"
 #include "OpusDecoder.h"
 #include "RemoteDataDecoder.h"
-#include "TheoraDecoder.h"
 #include "VPXDecoder.h"
 #include "VorbisDecoder.h"
-#include "mozilla/StaticPrefs_media.h"
-#include "mozilla/java/HardwareCodecCapabilityUtilsWrappers.h"
+
 #include "nsIGfxInfo.h"
 #include "nsPromiseFlatString.h"
+
 #include "prlog.h"
 
+#include <jni.h>
+
 #undef LOG
 #define LOG(arg, ...)                                     \
   MOZ_LOG(                                                \
       sAndroidDecoderModuleLog, mozilla::LogLevel::Debug, \
       ("AndroidDecoderModule(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 #define SLOG(arg, ...)                                        \
   MOZ_LOG(sAndroidDecoderModuleLog, mozilla::LogLevel::Debug, \
           ("%s: " arg, __func__, ##__VA_ARGS__))
--- a/dom/media/platforms/android/RemoteDataDecoder.h
+++ b/dom/media/platforms/android/RemoteDataDecoder.h
@@ -42,20 +42,17 @@ class RemoteDataDecoder : public MediaDa
                     const nsString& aDrmStubId);
 
   // Methods only called on mThread.
   void UpdateInputStatus(int64_t aTimestamp, bool aProcessed);
   void UpdateOutputStatus(RefPtr<MediaData>&& aSample);
   void ReturnDecodedData();
   void DrainComplete();
   void Error(const MediaResult& aError);
-  void AssertOnThread() const {
-    // mThread may not be set if Init hasn't been called first.
-    MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
-  }
+  void AssertOnThread() const { MOZ_ASSERT(mThread->IsOnCurrentThread()); }
 
   enum class State { DRAINED, DRAINABLE, DRAINING, SHUTDOWN };
   void SetState(State aState) {
     AssertOnThread();
     mState = aState;
   }
   State GetState() const {
     AssertOnThread();
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -86,25 +86,23 @@ RefPtr<MediaDataDecoder::FlushPromise> A
 
 RefPtr<MediaDataDecoder::DecodePromise> AppleATDecoder::Drain() {
   MOZ_ASSERT(mThread->IsOnCurrentThread());
   LOG("Draining AudioToolbox AAC decoder");
   return DecodePromise::CreateAndResolve(DecodedData(), __func__);
 }
 
 RefPtr<ShutdownPromise> AppleATDecoder::Shutdown() {
-  // mThread may not be set if Init hasn't been called first.
-  MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
   ProcessShutdown();
   return ShutdownPromise::CreateAndResolve(true, __func__);
 }
 
 void AppleATDecoder::ProcessShutdown() {
-  // mThread may not be set if Init hasn't been called first.
-  MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
 
   if (mStream) {
     OSStatus rv = AudioFileStreamClose(mStream);
     if (rv) {
       LOG("error %d disposing of AudioFileStream", static_cast<int>(rv));
       return;
     }
     mStream = nullptr;
--- a/dom/media/platforms/apple/AppleATDecoder.h
+++ b/dom/media/platforms/apple/AppleATDecoder.h
@@ -30,17 +30,17 @@ class AppleATDecoder : public MediaDataD
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
 
   nsCString GetDescriptionName() const override {
     return "apple coremedia decoder"_ns;
   }
 
   // Callbacks also need access to the config.
-  const AudioInfo mConfig;
+  const AudioInfo& mConfig;
 
   // Use to extract magic cookie for HE-AAC detection.
   nsTArray<uint8_t> mMagicCookie;
   // Will be set to true should an error occurred while attempting to retrieve
   // the magic cookie property.
   bool mFileStreamError;
 
   nsCOMPtr<nsISerialEventTarget> mThread;
--- a/dom/media/platforms/apple/AppleDecoderModule.cpp
+++ b/dom/media/platforms/apple/AppleDecoderModule.cpp
@@ -49,30 +49,30 @@ nsresult AppleDecoderModule::Startup() {
   if (!sInitialized) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 already_AddRefed<MediaDataDecoder> AppleDecoderModule::CreateVideoDecoder(
     const CreateDecoderParams& aParams) {
-  if (!Supports(SupportDecoderParams(aParams), nullptr /* diagnostics */)) {
+  if (!Supports(SupportDecoderParams(aParams), aParams.mDiagnostics)) {
     return nullptr;
   }
   RefPtr<MediaDataDecoder> decoder;
   if (IsVideoSupported(aParams.VideoConfig(), aParams.mOptions)) {
     decoder = new AppleVTDecoder(aParams.VideoConfig(), aParams.mImageContainer,
                                  aParams.mOptions, aParams.mKnowsCompositor);
   }
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder> AppleDecoderModule::CreateAudioDecoder(
     const CreateDecoderParams& aParams) {
-  if (!Supports(SupportDecoderParams(aParams), nullptr /* diagnostics */)) {
+  if (!Supports(SupportDecoderParams(aParams), aParams.mDiagnostics)) {
     return nullptr;
   }
   RefPtr<MediaDataDecoder> decoder = new AppleATDecoder(aParams.AudioConfig());
   return decoder.forget();
 }
 
 bool AppleDecoderModule::SupportsMimeType(
     const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const {
--- a/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
+++ b/dom/media/platforms/ffmpeg/FFmpegDecoderModule.h
@@ -27,31 +27,31 @@ class FFmpegDecoderModule : public Platf
     return pdm.forget();
   }
 
   explicit FFmpegDecoderModule(FFmpegLibWrapper* aLib) : mLib(aLib) {}
   virtual ~FFmpegDecoderModule() = default;
 
   already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
       const CreateDecoderParams& aParams) override {
-    if (!Supports(SupportDecoderParams(aParams), nullptr)) {
+    if (!Supports(SupportDecoderParams(aParams), aParams.mDiagnostics)) {
       return nullptr;
     }
     RefPtr<MediaDataDecoder> decoder = new FFmpegVideoDecoder<V>(
         mLib, aParams.VideoConfig(), aParams.mKnowsCompositor,
         aParams.mImageContainer,
         aParams.mOptions.contains(CreateDecoderParams::Option::LowLatency),
         aParams.mOptions.contains(
             CreateDecoderParams::Option::HardwareDecoderNotAllowed));
     return decoder.forget();
   }
 
   already_AddRefed<MediaDataDecoder> CreateAudioDecoder(
       const CreateDecoderParams& aParams) override {
-    if (!Supports(SupportDecoderParams(aParams), nullptr)) {
+    if (!Supports(SupportDecoderParams(aParams), aParams.mDiagnostics)) {
       return nullptr;
     }
     RefPtr<MediaDataDecoder> decoder =
         new FFmpegAudioDecoder<V>(mLib, aParams.AudioConfig());
     return decoder.forget();
   }
 
   bool SupportsMimeType(const nsACString& aMimeType,
--- a/dom/media/platforms/moz.build
+++ b/dom/media/platforms/moz.build
@@ -34,17 +34,16 @@ UNIFIED_SOURCES += [
     "agnostic/OpusDecoder.cpp",
     "agnostic/TheoraDecoder.cpp",
     "agnostic/VorbisDecoder.cpp",
     "agnostic/VPXDecoder.cpp",
     "agnostic/WAVDecoder.cpp",
     "AllocationPolicy.cpp",
     "PDMFactory.cpp",
     "PEMFactory.cpp",
-    "PlatformDecoderModule.cpp",
     "wrappers/AudioTrimmer.cpp",
     "wrappers/MediaChangeMonitor.cpp",
     "wrappers/MediaDataDecoderProxy.cpp",
 ]
 
 DIRS += ["agnostic/bytestreams", "agnostic/eme", "agnostic/gmp", "omx"]
 
 if CONFIG["MOZ_WMF"]:
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -190,18 +190,17 @@ RefPtr<MediaDataDecoder::DecodePromise> 
     RefPtr<DecodePromise> p = self->mDrainPromise.Ensure(__func__);
     self->SendEosBuffer();
     return p;
   });
 }
 
 RefPtr<ShutdownPromise> OmxDataDecoder::Shutdown() {
   LOG("");
-  // mThread may not be set if Init hasn't been called first.
-  MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mThread->IsOnCurrentThread());
 
   mShuttingDown = true;
 
   return InvokeAsync(mOmxTaskQueue, this, __func__,
                      &OmxDataDecoder::DoAsyncShutdown);
 }
 
 RefPtr<ShutdownPromise> OmxDataDecoder::DoAsyncShutdown() {
--- a/dom/media/platforms/wrappers/AudioTrimmer.cpp
+++ b/dom/media/platforms/wrappers/AudioTrimmer.cpp
@@ -51,18 +51,18 @@ RefPtr<MediaDataDecoder::DecodePromise> 
       GetCurrentSerialEventTarget(), __func__,
       [self = RefPtr{this}](DecodePromise::ResolveOrRejectValue&& aValue) {
         return self->HandleDecodedResult(std::move(aValue), nullptr);
       });
   return p;
 }
 
 RefPtr<ShutdownPromise> AudioTrimmer::Shutdown() {
-  // mThread may not be set if Init hasn't been called first.
-  MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
+  MOZ_ASSERT(mThread->IsOnCurrentThread(),
+             "We're not on the thread we were first initialized on");
   return mDecoder->Shutdown();
 }
 
 nsCString AudioTrimmer::GetDescriptionName() const {
   return mDecoder->GetDescriptionName();
 }
 
 bool AudioTrimmer::IsHardwareAccelerated(nsACString& aFailureReason) const {
--- a/dom/media/platforms/wrappers/MediaChangeMonitor.cpp
+++ b/dom/media/platforms/wrappers/MediaChangeMonitor.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "MediaChangeMonitor.h"
 
 #include "AnnexB.h"
+#include "DecoderDoctorDiagnostics.h"
 #include "H264.h"
 #include "ImageContainer.h"
 #include "MP4Decoder.h"
 #include "MediaInfo.h"
 #include "PDMFactory.h"
 #include "VPXDecoder.h"
 #include "mozilla/StaticPrefs_media.h"
 #include "mozilla/TaskQueue.h"
@@ -239,64 +240,42 @@ class VPXChangeMonitor : public MediaCha
  private:
   VideoInfo mCurrentConfig;
   const VPXDecoder::Codec mCodec;
   Maybe<VPXDecoder::VPXStreamInfo> mInfo;
   uint32_t mStreamID = 0;
   RefPtr<TrackInfoSharedPtr> mTrackInfo;
 };
 
-MediaChangeMonitor::MediaChangeMonitor(
-    PlatformDecoderModule* aPDM,
-    UniquePtr<CodecChangeMonitor>&& aCodecChangeMonitor,
-    MediaDataDecoder* aDecoder, const CreateDecoderParams& aParams)
-    : mChangeMonitor(std::move(aCodecChangeMonitor)),
-      mPDM(aPDM),
+MediaChangeMonitor::MediaChangeMonitor(PlatformDecoderModule* aPDM,
+                                       const CreateDecoderParams& aParams)
+    : mPDM(aPDM),
       mCurrentConfig(aParams.VideoConfig()),
-      mDecoder(aDecoder),
-      mParams(aParams) {}
-
-/* static */
-RefPtr<PlatformDecoderModule::CreateDecoderPromise> MediaChangeMonitor::Create(
-    PlatformDecoderModule* aPDM, const CreateDecoderParams& aParams) {
-  UniquePtr<CodecChangeMonitor> changeMonitor;
-  const VideoInfo& currentConfig = aParams.VideoConfig();
-  if (VPXDecoder::IsVPX(currentConfig.mMimeType)) {
-    changeMonitor = MakeUnique<VPXChangeMonitor>(currentConfig);
+      mKnowsCompositor(aParams.mKnowsCompositor),
+      mImageContainer(aParams.mImageContainer),
+      mDecoder(nullptr),
+      mGMPCrashHelper(aParams.mCrashHelper),
+      mLastError(NS_OK),
+      mErrorIfNoInitializationData(aParams.mOptions.contains(
+          CreateDecoderParams::Option::ErrorIfNoInitializationData)),
+      mType(aParams.mType),
+      mOnWaitingForKeyEvent(aParams.mOnWaitingForKeyEvent),
+      mDecoderOptions(aParams.mOptions),
+      mRate(aParams.mRate) {
+  mInConstructor = true;
+  if (VPXDecoder::IsVPX(mCurrentConfig.mMimeType)) {
+    mChangeMonitor = MakeUnique<VPXChangeMonitor>(mCurrentConfig);
   } else {
-    MOZ_ASSERT(MP4Decoder::IsH264(currentConfig.mMimeType));
-    changeMonitor = MakeUnique<H264ChangeMonitor>(
-        currentConfig, aParams.mOptions.contains(
-                           CreateDecoderParams::Option::FullH264Parsing));
+    MOZ_ASSERT(MP4Decoder::IsH264(mCurrentConfig.mMimeType));
+    mChangeMonitor = MakeUnique<H264ChangeMonitor>(
+        mCurrentConfig,
+        mDecoderOptions.contains(CreateDecoderParams::Option::FullH264Parsing));
   }
-
-  if (!changeMonitor->CanBeInstantiated()) {
-    // nothing found yet, will try again later
-    return PlatformDecoderModule::CreateDecoderPromise::CreateAndResolve(
-        new MediaChangeMonitor(aPDM, std::move(changeMonitor), nullptr,
-                               aParams),
-        __func__);
-  }
-
-  RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
-      aPDM->AsyncCreateDecoder(aParams)->Then(
-          GetCurrentSerialEventTarget(), __func__,
-          [params = CreateDecoderParamsForAsync(aParams), pdm = RefPtr{aPDM},
-           changeMonitor = std::move(changeMonitor)](
-              RefPtr<MediaDataDecoder>&& aDecoder) mutable {
-            RefPtr<MediaDataDecoder> decoder = new MediaChangeMonitor(
-                pdm, std::move(changeMonitor), aDecoder, params);
-            return PlatformDecoderModule::CreateDecoderPromise::
-                CreateAndResolve(decoder, __func__);
-          },
-          [](MediaResult aError) {
-            return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
-                aError, __func__);
-          });
-  return p;
+  mLastError = CreateDecoder(aParams.mDiagnostics);
+  mInConstructor = false;
 }
 
 MediaChangeMonitor::~MediaChangeMonitor() = default;
 
 RefPtr<MediaDataDecoder::InitPromise> MediaChangeMonitor::Init() {
   mThread = GetCurrentSerialEventTarget();
   if (mDecoder) {
     RefPtr<InitPromise> p = mInitPromise.Ensure(__func__);
@@ -321,29 +300,27 @@ RefPtr<MediaDataDecoder::InitPromise> Me
   // extradata.
   return MediaDataDecoder::InitPromise::CreateAndResolve(TrackType::kVideoTrack,
                                                          __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise> MediaChangeMonitor::Decode(
     MediaRawData* aSample) {
   AssertOnThread();
-  MOZ_RELEASE_ASSERT(mFlushPromise.IsEmpty(),
-                     "Flush operation didn't complete");
+  MOZ_RELEASE_ASSERT(mFlushPromise.IsEmpty(), "Flush operatin didn't complete");
 
   MOZ_RELEASE_ASSERT(
       !mDecodePromiseRequest.Exists() && !mInitPromiseRequest.Exists(),
       "Can't request a new decode until previous one completed");
 
   MediaResult rv = CheckForChange(aSample);
 
   if (rv == NS_ERROR_NOT_INITIALIZED) {
     // We are missing the required init data to create the decoder.
-    if (mParams.mOptions.contains(
-            CreateDecoderParams::Option::ErrorIfNoInitializationData)) {
+    if (mErrorIfNoInitializationData) {
       // This frame can't be decoded and should be treated as an error.
       return DecodePromise::CreateAndReject(rv, __func__);
     }
     // Swallow the frame, and await delivery of init data.
     return DecodePromise::CreateAndResolve(DecodedData(), __func__);
   }
   if (rv == NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER) {
     // The decoder is pending initialization.
@@ -376,45 +353,40 @@ RefPtr<MediaDataDecoder::FlushPromise> M
   mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
   mNeedKeyframe = true;
   mPendingFrames.Clear();
 
   MOZ_RELEASE_ASSERT(mFlushPromise.IsEmpty(), "Previous flush didn't complete");
 
   /*
     When we detect a change of content in the byte stream, we first drain the
-    current decoder (1), flush (2), shut it down (3) create a new decoder (4)
-    and initialize it (5). It is possible for MediaChangeMonitor::Flush to be
+    current decoder (1), flush (2), shut it down (3) create a new decoder and
+    initialize it (4). It is possible for MediaChangeMonitor::Flush to be
     called during any of those times. If during (1):
       - mDrainRequest will not be empty.
       - The old decoder can still be used, with the current extradata as
     stored in mCurrentConfig.mExtraData.
 
     If during (2):
       - mFlushRequest will not be empty.
       - The old decoder can still be used, with the current extradata as
     stored in mCurrentConfig.mExtraData.
 
     If during (3):
       - mShutdownRequest won't be empty.
       - mDecoder is empty.
       - The old decoder is no longer referenced by the MediaChangeMonitor.
 
     If during (4):
-      - mDecoderRequest won't be empty.
-      - mDecoder is not set. Steps will continue to (5) to set and initialize it
-
-    If during (5):
       - mInitPromiseRequest won't be empty.
       - mDecoder is set but not usable yet.
   */
 
   if (mDrainRequest.Exists() || mFlushRequest.Exists() ||
-      mShutdownRequest.Exists() || mDecoderRequest.Exists() ||
-      mInitPromiseRequest.Exists()) {
+      mShutdownRequest.Exists() || mInitPromiseRequest.Exists()) {
     // We let the current decoder complete and will resume after.
     RefPtr<FlushPromise> p = mFlushPromise.Ensure(__func__);
     return p;
   }
   if (mDecoder && mDecoderInitialized) {
     return mDecoder->Flush();
   }
   return FlushPromise::CreateAndResolve(true, __func__);
@@ -478,124 +450,108 @@ bool MediaChangeMonitor::IsHardwareAccel
 void MediaChangeMonitor::SetSeekThreshold(const media::TimeUnit& aTime) {
   if (mDecoder) {
     mDecoder->SetSeekThreshold(aTime);
   } else {
     MediaDataDecoder::SetSeekThreshold(aTime);
   }
 }
 
-RefPtr<MediaChangeMonitor::CreateDecoderPromise>
-MediaChangeMonitor::CreateDecoder() {
-  MOZ_ASSERT(mThread && mThread->IsOnCurrentThread());
+MediaResult MediaChangeMonitor::CreateDecoder(
+    DecoderDoctorDiagnostics* aDiagnostics) {
+  // This is the only one of two methods to run outside the init thread when
+  // called from the constructor.
+  MOZ_ASSERT(mInConstructor || (mThread && mThread->IsOnCurrentThread()));
 
+  if (!mChangeMonitor->CanBeInstantiated()) {
+    // nothing found yet, will try again later
+    return NS_ERROR_NOT_INITIALIZED;
+  }
   mCurrentConfig = *mChangeMonitor->Config().GetAsVideoInfo();
 
-  RefPtr<CreateDecoderPromise> p =
-      mPDM->AsyncCreateDecoder({mCurrentConfig, mParams})
-          ->Then(
-              GetCurrentSerialEventTarget(), __func__,
-              [self = RefPtr{this}, this](RefPtr<MediaDataDecoder>&& aDecoder) {
-                mDecoder = std::move(aDecoder);
-                DDLINKCHILD("decoder", mDecoder.get());
-                return CreateDecoderPromise::CreateAndResolve(true, __func__);
-              },
-              [self = RefPtr{this}, this](const MediaResult& aError) {
-                // We failed to create a decoder with the existing PDM; attempt
-                // once again with a PDMFactory.
-                RefPtr<PDMFactory> factory = new PDMFactory();
-                RefPtr<CreateDecoderPromise> p =
-                    factory
-                        ->CreateDecoder({mCurrentConfig, mParams,
-                                         CreateDecoderParams::NoWrapper(true)})
-                        ->Then(
-                            GetCurrentSerialEventTarget(), __func__,
-                            [self, this](RefPtr<MediaDataDecoder>&& aDecoder) {
-                              mDecoder = std::move(aDecoder);
-                              DDLINKCHILD("decoder", mDecoder.get());
-                              return CreateDecoderPromise::CreateAndResolve(
-                                  true, __func__);
-                            },
-                            [self](const MediaResult& aError) {
-                              return CreateDecoderPromise::CreateAndReject(
-                                  aError, __func__);
-                            });
-                return p;
-              });
+  MediaResult error = NS_OK;
+  mDecoder = mPDM->CreateVideoDecoder(
+      {mCurrentConfig, aDiagnostics, mImageContainer, mKnowsCompositor,
+       mGMPCrashHelper, mType, mOnWaitingForKeyEvent, mDecoderOptions, mRate,
+       &error});
+
+  if (!mDecoder) {
+    // We failed to create a decoder with the existing PDM; attempt once again
+    // with a PDMFactory.
+    RefPtr<PDMFactory> factory = new PDMFactory();
+    mDecoder = factory->CreateDecoder(
+        {mCurrentConfig, aDiagnostics, mImageContainer, mKnowsCompositor,
+         mGMPCrashHelper, mType, mOnWaitingForKeyEvent, mDecoderOptions, mRate,
+         &error, CreateDecoderParams::NoWrapper(true)});
+
+    if (!mDecoder) {
+      if (NS_FAILED(error)) {
+        // The decoder supports CreateDecoderParam::mError, returns the value.
+        return error;
+      }
+      return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                         RESULT_DETAIL("Unable to create decoder"));
+    }
+  }
+
+  DDLINKCHILD("decoder", mDecoder.get());
 
   mDecoderInitialized = false;
   mNeedKeyframe = true;
 
-  return p;
+  return NS_OK;
 }
 
 MediaResult MediaChangeMonitor::CreateDecoderAndInit(MediaRawData* aSample) {
   MediaResult rv = mChangeMonitor->CheckForChange(aSample);
   if (!NS_SUCCEEDED(rv) && rv != NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) {
     return rv;
   }
 
-  if (!mChangeMonitor->CanBeInstantiated()) {
-    // Nothing found yet, will try again later.
-    return NS_ERROR_NOT_INITIALIZED;
-  }
+  rv = CreateDecoder(/* DecoderDoctorDiagnostics* */ nullptr);
 
-  CreateDecoder()
-      ->Then(
-          GetCurrentSerialEventTarget(), __func__,
-          [self = RefPtr{this}, this, sample = RefPtr{aSample}] {
-            mDecoderRequest.Complete();
-            mDecoder->Init()
-                ->Then(
-                    GetCurrentSerialEventTarget(), __func__,
-                    [self, sample, this](const TrackType aTrackType) {
-                      mInitPromiseRequest.Complete();
-                      mDecoderInitialized = true;
-                      mConversionRequired = Some(mDecoder->NeedsConversion());
-                      mCanRecycleDecoder = Some(CanRecycleDecoder());
+  if (NS_SUCCEEDED(rv)) {
+    RefPtr<MediaChangeMonitor> self = this;
+    RefPtr<MediaRawData> sample = aSample;
+    mDecoder->Init()
+        ->Then(
+            GetCurrentSerialEventTarget(), __func__,
+            [self, sample, this](const TrackType aTrackType) {
+              mInitPromiseRequest.Complete();
+              mDecoderInitialized = true;
+              mConversionRequired = Some(mDecoder->NeedsConversion());
+              mCanRecycleDecoder = Some(CanRecycleDecoder());
 
-                      if (!mFlushPromise.IsEmpty()) {
-                        // A Flush is pending, abort the current operation.
-                        mFlushPromise.Resolve(true, __func__);
-                        return;
-                      }
+              if (!mFlushPromise.IsEmpty()) {
+                // A Flush is pending, abort the current operation.
+                mFlushPromise.Resolve(true, __func__);
+                return;
+              }
 
-                      DecodeFirstSample(sample);
-                    },
-                    [self, this](const MediaResult& aError) {
-                      mInitPromiseRequest.Complete();
+              DecodeFirstSample(sample);
+            },
+            [self, this](const MediaResult& aError) {
+              mInitPromiseRequest.Complete();
 
-                      if (!mFlushPromise.IsEmpty()) {
-                        // A Flush is pending, abort the current operation.
-                        mFlushPromise.Reject(aError, __func__);
-                        return;
-                      }
+              if (!mFlushPromise.IsEmpty()) {
+                // A Flush is pending, abort the current operation.
+                mFlushPromise.Reject(aError, __func__);
+                return;
+              }
 
-                      mDecodePromise.Reject(
-                          MediaResult(
-                              NS_ERROR_DOM_MEDIA_FATAL_ERR,
-                              RESULT_DETAIL("Unable to initialize decoder")),
-                          __func__);
-                    })
-                ->Track(mInitPromiseRequest);
-          },
-          [self = RefPtr{this}, this](const MediaResult& aError) {
-            mDecoderRequest.Complete();
-            if (!mFlushPromise.IsEmpty()) {
-              // A Flush is pending, abort the current operation.
-              mFlushPromise.Reject(aError, __func__);
-              return;
-            }
-            mDecodePromise.Reject(
-                MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
-                            RESULT_DETAIL("Unable to create decoder")),
-                __func__);
-          })
-      ->Track(mDecoderRequest);
-  return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER;
+              mDecodePromise.Reject(
+                  MediaResult(
+                      NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                      RESULT_DETAIL("Unable to initialize H264 decoder")),
+                  __func__);
+            })
+        ->Track(mInitPromiseRequest);
+    return NS_ERROR_DOM_MEDIA_INITIALIZING_DECODER;
+  }
+  return rv;
 }
 
 bool MediaChangeMonitor::CanRecycleDecoder() const {
   MOZ_ASSERT(mDecoder);
   return StaticPrefs::media_decoder_recycle_enabled() &&
          mDecoder->SupportDecoderRecycling();
 }
 
--- a/dom/media/platforms/wrappers/MediaChangeMonitor.h
+++ b/dom/media/platforms/wrappers/MediaChangeMonitor.h
@@ -9,31 +9,34 @@
 
 #include "PlatformDecoderModule.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 
+class DecoderDoctorDiagnostics;
+
 DDLoggedTypeDeclNameAndBase(MediaChangeMonitor, MediaDataDecoder);
 
 // MediaChangeMonitor is a MediaDataDecoder wrapper used to ensure that
 // only one type of content is fed to the underlying MediaDataDecoder.
 // The MediaChangeMonitor allows playback of content where some out of band
 // extra data (such as SPS NAL for H264 content) may not be provided in the
 // init segment (e.g. AVC3 or Annex B) MediaChangeMonitor will monitor the
 // input data, and will delay creation of the MediaDataDecoder until such out
 // of band have been extracted should the underlying decoder required it.
 
 class MediaChangeMonitor : public MediaDataDecoder,
                            public DecoderDoctorLifeLogger<MediaChangeMonitor> {
  public:
-  static RefPtr<PlatformDecoderModule::CreateDecoderPromise> Create(
-      PlatformDecoderModule* aPDM, const CreateDecoderParams& aParams);
+  MediaChangeMonitor(PlatformDecoderModule* aPDM,
+                     const CreateDecoderParams& aParams);
+  virtual ~MediaChangeMonitor();
 
   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;
   nsCString GetDescriptionName() const override {
@@ -52,75 +55,75 @@ class MediaChangeMonitor : public MediaD
 
   ConversionRequired NeedsConversion() const override {
     if (mDecoder) {
       return mDecoder->NeedsConversion();
     }
     // Default so no conversion is performed.
     return ConversionRequired::kNeedNone;
   }
+  MediaResult GetLastError() const { return mLastError; }
 
   class CodecChangeMonitor {
    public:
     virtual bool CanBeInstantiated() const = 0;
     virtual MediaResult CheckForChange(MediaRawData* aSample) = 0;
     virtual const TrackInfo& Config() const = 0;
     virtual MediaResult PrepareSample(
         MediaDataDecoder::ConversionRequired aConversion, MediaRawData* aSample,
         bool aNeedKeyFrame) = 0;
     virtual ~CodecChangeMonitor() = default;
   };
 
  private:
-  MediaChangeMonitor(PlatformDecoderModule* aPDM,
-                     UniquePtr<CodecChangeMonitor>&& aCodecChangeMonitor,
-                     MediaDataDecoder* aDecoder,
-                     const CreateDecoderParams& aParams);
-  virtual ~MediaChangeMonitor();
+  UniquePtr<CodecChangeMonitor> mChangeMonitor;
 
-  void AssertOnThread() const {
-    // mThread may not be set if Init hasn't been called first.
-    MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread());
-  }
+  void AssertOnThread() const { MOZ_ASSERT(mThread->IsOnCurrentThread()); }
 
   bool CanRecycleDecoder() const;
 
-  typedef MozPromise<bool, MediaResult, true /* exclusive */>
-      CreateDecoderPromise;
   // 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.
-  RefPtr<CreateDecoderPromise> CreateDecoder();
+  MediaResult CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics);
   MediaResult CreateDecoderAndInit(MediaRawData* aSample);
   MediaResult CheckForChange(MediaRawData* aSample);
 
   void DecodeFirstSample(MediaRawData* aSample);
   void DrainThenFlushDecoder(MediaRawData* aPendingSample);
   void FlushThenShutdownDecoder(MediaRawData* aPendingSample);
   RefPtr<ShutdownPromise> ShutdownDecoder();
 
-  UniquePtr<CodecChangeMonitor> mChangeMonitor;
   RefPtr<PlatformDecoderModule> mPDM;
   VideoInfo mCurrentConfig;
+  RefPtr<layers::KnowsCompositor> mKnowsCompositor;
+  RefPtr<layers::ImageContainer> mImageContainer;
   nsCOMPtr<nsISerialEventTarget> mThread;
   RefPtr<MediaDataDecoder> mDecoder;
-  MozPromiseRequestHolder<CreateDecoderPromise> mDecoderRequest;
   MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
   MozPromiseHolder<InitPromise> mInitPromise;
   MozPromiseRequestHolder<DecodePromise> mDecodePromiseRequest;
   MozPromiseHolder<DecodePromise> mDecodePromise;
   MozPromiseRequestHolder<FlushPromise> mFlushRequest;
   MediaDataDecoder::DecodedData mPendingFrames;
   MozPromiseRequestHolder<DecodePromise> mDrainRequest;
   MozPromiseRequestHolder<ShutdownPromise> mShutdownRequest;
   RefPtr<ShutdownPromise> mShutdownPromise;
   MozPromiseHolder<FlushPromise> mFlushPromise;
 
+  RefPtr<GMPCrashHelper> mGMPCrashHelper;
+  MediaResult mLastError;
   bool mNeedKeyframe = true;
+  const bool mErrorIfNoInitializationData;
+  const TrackInfo::TrackType mType;
+  MediaEventProducer<TrackInfo::TrackType>* const mOnWaitingForKeyEvent;
+  const CreateDecoderParams::OptionSet mDecoderOptions;
+  const CreateDecoderParams::VideoFrameRate mRate;
   Maybe<bool> mCanRecycleDecoder;
   Maybe<MediaDataDecoder::ConversionRequired> mConversionRequired;
+  // Used for debugging purposes only
+  Atomic<bool> mInConstructor;
   bool mDecoderInitialized = false;
-  const CreateDecoderParamsForAsync mParams;
 };
 
 }  // namespace mozilla
 
 #endif  // mozilla_H264Converter_h
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -118,18 +118,17 @@ class MediaDecodeTask final : public Run
       nsCOMPtr<nsIRunnable> event = new ReportResultTask(
           mDecodeJob, &WebAudioDecodeJob::OnFailure, aErrorCode);
       mMainThread->Dispatch(event.forget());
     }
   }
 
   void Decode();
 
-  void OnCreateDecoderCompleted(RefPtr<MediaDataDecoder> aDecoder);
-  MOZ_CAN_RUN_SCRIPT void OnCreateDecoderFailed(const MediaResult& aError);
+  MediaResult CreateDecoder(const AudioInfo& info);
 
   MOZ_CAN_RUN_SCRIPT void OnInitDemuxerCompleted();
   MOZ_CAN_RUN_SCRIPT void OnInitDemuxerFailed(const MediaResult& aError);
 
   void InitDecoder();
   void OnInitDecoderCompleted();
   MOZ_CAN_RUN_SCRIPT void OnInitDecoderFailed();
 
@@ -265,47 +264,55 @@ void MediaDecodeTask::OnInitDemuxerCompl
     UniquePtr<TrackInfo> audioInfo = mTrackDemuxer->GetInfo();
     // We actively ignore audio tracks that we know we can't play.
     if (audioInfo && audioInfo->IsValid() &&
         platform->SupportsMimeType(audioInfo->mMimeType, nullptr)) {
       mMediaInfo.mAudio = *audioInfo->GetAsAudioInfo();
     }
   }
 
-  RefPtr<PDMFactory> pdm = new PDMFactory();
-  pdm->CreateDecoder(
-         {*mMediaInfo.mAudio.GetAsAudioInfo(), TrackInfo::kAudioTrack})
-      ->Then(PSupervisorTaskQueue(), __func__, this,
-             &MediaDecodeTask::OnCreateDecoderCompleted,
-             &MediaDecodeTask::OnCreateDecoderFailed);
-}
-
-void MediaDecodeTask::OnCreateDecoderCompleted(
-    RefPtr<MediaDataDecoder> aDecoder) {
-  MOZ_ASSERT(OnPSupervisorTaskQueue());
-
-  mDecoder = new MediaDataDecoderProxy(aDecoder.forget(),
-                                       do_AddRef(mPDecoderTaskQueue.get()));
+  if (NS_FAILED(CreateDecoder(*mMediaInfo.mAudio.GetAsAudioInfo()))) {
+    LOG("MediaDecodeTask: Could not create a decoder.");
+    ReportFailureOnMainThread(WebAudioDecodeJob::UnknownContent);
+    return;
+  }
   InitDecoder();
 }
 
-void MediaDecodeTask::OnCreateDecoderFailed(const MediaResult& aError) {
-  MOZ_ASSERT(OnPSupervisorTaskQueue());
-
-  LOG("MediaDecodeTask: Could not create a decoder.");
-  ReportFailureOnMainThread(WebAudioDecodeJob::UnknownContent);
-}
-
 void MediaDecodeTask::OnInitDemuxerFailed(const MediaResult& aError) {
   MOZ_ASSERT(OnPSupervisorTaskQueue());
 
   LOG("MediaDecodeTask: Could not initialize the demuxer.");
   ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
 }
 
+MediaResult MediaDecodeTask::CreateDecoder(const AudioInfo& info) {
+  MOZ_ASSERT(OnPSupervisorTaskQueue());
+
+  RefPtr<PDMFactory> pdm = new PDMFactory();
+  // result may not be updated by PDMFactory::CreateDecoder, as such it must be
+  // initialized to a fatal error by default.
+  MediaResult result =
+      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+                  nsPrintfCString("error creating %s decoder",
+                                  TrackTypeToStr(TrackInfo::kAudioTrack)));
+  RefPtr<MediaDataDecoder> decoder =
+      pdm->CreateDecoder({info, &result, TrackInfo::kAudioTrack});
+
+  if (decoder) {
+    mDecoder = new MediaDataDecoderProxy(decoder.forget(),
+                                         do_AddRef(mPDecoderTaskQueue.get()));
+    return NS_OK;
+  }
+
+  MOZ_RELEASE_ASSERT(NS_FAILED(result), "PDM returned an invalid error code");
+
+  return result;
+}
+
 void MediaDecodeTask::InitDecoder() {
   MOZ_ASSERT(OnPSupervisorTaskQueue());
 
   mDecoder->Init()->Then(PSupervisorTaskQueue(), __func__, this,
                          &MediaDecodeTask::OnInitDecoderCompleted,
                          &MediaDecodeTask::OnInitDecoderFailed);
 }
 
--- a/dom/media/webrtc/libwebrtcglue/MediaDataCodec.cpp
+++ b/dom/media/webrtc/libwebrtcglue/MediaDataCodec.cpp
@@ -1,18 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "MediaDataCodec.h"
-
-#include "PDMFactory.h"
-#include "WebrtcGmpVideoCodec.h"
 #include "WebrtcMediaDataDecoderCodec.h"
 #include "WebrtcMediaDataEncoderCodec.h"
+#include "WebrtcGmpVideoCodec.h"
 #include "mozilla/StaticPrefs_media.h"
 
 namespace mozilla {
 
 /* static */
 WebrtcVideoEncoder* MediaDataCodec::CreateEncoder(
     webrtc::VideoCodecType aCodecType) {
 #if defined(MOZ_APPLEMEDIA) || defined(MOZ_WIDGET_ANDROID)
@@ -36,32 +34,12 @@ WebrtcVideoDecoder* MediaDataCodec::Crea
     case webrtc::VideoCodecType::kVideoCodecH264:
       if (!StaticPrefs::media_navigator_mediadatadecoder_h264_enabled()) {
         return nullptr;
       }
       break;
     default:
       return nullptr;
   }
-
-  nsAutoCString codec;
-  switch (aCodecType) {
-    case webrtc::VideoCodecType::kVideoCodecVP8:
-      codec = "video/vp8";
-      break;
-    case webrtc::VideoCodecType::kVideoCodecVP9:
-      codec = "video/vp9";
-      break;
-    case webrtc::VideoCodecType::kVideoCodecH264:
-      codec = "video/avc";
-      break;
-    default:
-      return nullptr;
-  }
-  RefPtr<PDMFactory> pdm = new PDMFactory();
-  if (!pdm->SupportsMimeType(codec, nullptr /* dddoctor */)) {
-    return nullptr;
-  }
-
-  return new WebrtcMediaDataDecoder(codec);
+  return new WebrtcMediaDataDecoder();
 }
 
 }  // namespace mozilla
--- a/dom/media/webrtc/libwebrtcglue/WebrtcMediaDataDecoderCodec.cpp
+++ b/dom/media/webrtc/libwebrtcglue/WebrtcMediaDataDecoderCodec.cpp
@@ -10,34 +10,48 @@
 #include "PDMFactory.h"
 #include "VideoUtils.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/media/MediaUtils.h"
 #include "webrtc/rtc_base/keep_ref_until_done.h"
 
 namespace mozilla {
 
-WebrtcMediaDataDecoder::WebrtcMediaDataDecoder(nsACString& aCodecMimeType)
+WebrtcMediaDataDecoder::WebrtcMediaDataDecoder()
     : mThreadPool(GetMediaThreadPool(MediaThreadType::SUPERVISOR)),
       mTaskQueue(new TaskQueue(do_AddRef(mThreadPool),
                                "WebrtcMediaDataDecoder::mTaskQueue")),
       mImageContainer(layers::LayerManager::CreateImageContainer(
           layers::ImageContainer::ASYNCHRONOUS)),
       mFactory(new PDMFactory()),
-      mTrackType(TrackInfo::kUndefinedTrack),
-      mCodecType(aCodecMimeType) {}
+      mTrackType(TrackInfo::kUndefinedTrack) {}
 
 WebrtcMediaDataDecoder::~WebrtcMediaDataDecoder() {}
 
 int32_t WebrtcMediaDataDecoder::InitDecode(
     const webrtc::VideoCodec* aCodecSettings, int32_t aNumberOfCores) {
   nsCString codec;
+  switch (aCodecSettings->codecType) {
+    case webrtc::VideoCodecType::kVideoCodecVP8:
+      codec = "video/vp8";
+      break;
+    case webrtc::VideoCodecType::kVideoCodecVP9:
+      codec = "video/vp9";
+      break;
+    case webrtc::VideoCodecType::kVideoCodecH264:
+      codec = "video/avc";
+      break;
+    default:
+      return WEBRTC_VIDEO_CODEC_ERROR;
+  }
+
   mTrackType = TrackInfo::kVideoTrack;
+
   mInfo = VideoInfo(aCodecSettings->width, aCodecSettings->height);
-  mInfo.mMimeType = mCodecType;
+  mInfo.mMimeType = codec;
 
   return CreateDecoder();
 }
 
 int32_t WebrtcMediaDataDecoder::Decode(
     const webrtc::EncodedImage& aInputImage, bool aMissingFrames,
     const webrtc::RTPFragmentationHeader* aFragmentation,
     const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
@@ -137,53 +151,35 @@ bool WebrtcMediaDataDecoder::OnTaskQueue
 int32_t WebrtcMediaDataDecoder::CreateDecoder() {
   RefPtr<layers::KnowsCompositor> knowsCompositor =
       layers::ImageBridgeChild::GetSingleton();
 
   if (mDecoder) {
     Release();
   }
 
-  RefPtr<TaskQueue> tq =
-      new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
-                    "webrtc decode TaskQueue");
-  RefPtr<MediaDataDecoder> decoder;
-
-  media::Await(do_AddRef(mThreadPool), InvokeAsync(tq, __func__, [&] {
-                 RefPtr<GenericPromise> p =
-                     mFactory
-                         ->CreateDecoder(
-                             {mInfo,
-                              CreateDecoderParams::OptionSet(
-                                  CreateDecoderParams::Option::LowLatency,
-                                  CreateDecoderParams::Option::FullH264Parsing,
-                                  CreateDecoderParams::Option::
-                                      ErrorIfNoInitializationData),
-                              mTrackType, mImageContainer, knowsCompositor})
-                         ->Then(
-                             tq, __func__,
-                             [&](RefPtr<MediaDataDecoder>&& aDecoder) {
-                               decoder = std::move(aDecoder);
-                               return GenericPromise::CreateAndResolve(
-                                   true, __func__);
-                             },
-                             [](const MediaResult& aResult) {
-                               return GenericPromise::CreateAndReject(
-                                   NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
-                             });
-                 return p;
-               }));
+  RefPtr<MediaDataDecoder> decoder = mFactory->CreateDecoder(
+      {mInfo,
+       CreateDecoderParams::OptionSet(
+           CreateDecoderParams::Option::LowLatency,
+           CreateDecoderParams::Option::FullH264Parsing,
+           CreateDecoderParams::Option::ErrorIfNoInitializationData),
+       mTrackType, mImageContainer, knowsCompositor});
 
   if (!decoder) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   // We need to wrap our decoder in a MediaDataDecoderProxy so that it always
   // run on an nsISerialEventTarget (which the webrtc code doesn't do)
-  mDecoder = new MediaDataDecoderProxy(decoder.forget(), tq.forget());
+  mDecoder = new MediaDataDecoderProxy(
+      decoder.forget(),
+      MakeAndAddRef<TaskQueue>(
+          GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
+          "webrtc decode TaskQueue"));
 
   media::Await(
       do_AddRef(mThreadPool), mDecoder->Init(),
       [&](TrackInfo::TrackType) { mError = NS_OK; },
       [&](const MediaResult& aError) { mError = aError; });
 
   return NS_SUCCEEDED(mError) ? WEBRTC_VIDEO_CODEC_OK
                               : WEBRTC_VIDEO_CODEC_ERROR;
--- a/dom/media/webrtc/libwebrtcglue/WebrtcMediaDataDecoderCodec.h
+++ b/dom/media/webrtc/libwebrtcglue/WebrtcMediaDataDecoderCodec.h
@@ -24,17 +24,17 @@ class ImageContainer;
 }  // namespace layers
 
 class PDMFactory;
 class SharedThreadPool;
 class TaskQueue;
 
 class WebrtcMediaDataDecoder : public WebrtcVideoDecoder {
  public:
-  explicit WebrtcMediaDataDecoder(nsACString& aCodecMimeType);
+  WebrtcMediaDataDecoder();
 
   // Implement VideoDecoder interface.
   uint64_t PluginID() const override { return 0; }
 
   int32_t InitDecode(const webrtc::VideoCodec* codecSettings,
                      int32_t numberOfCores) override;
 
   int32_t Decode(const webrtc::EncodedImage& inputImage, bool missingFrames,
@@ -61,14 +61,13 @@ class WebrtcMediaDataDecoder : public We
   webrtc::DecodedImageCallback* mCallback = nullptr;
   VideoInfo mInfo;
   TrackInfo::TrackType mTrackType;
   bool mNeedKeyframe = true;
   MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDecodeRequest;
 
   MediaResult mError = NS_OK;
   MediaDataDecoder::DecodedData mResults;
-  const nsCString mCodecType;
 };
 
 }  // namespace mozilla
 
 #endif  // WebrtcMediaDataDecoderCodec_h__
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -756,17 +756,17 @@ bool BackgroundParentImpl::DeallocPCamer
 #ifdef MOZ_WEBRTC
   RefPtr<mozilla::camera::CamerasParent> actor =
       dont_AddRef(static_cast<mozilla::camera::CamerasParent*>(aActor));
 #endif
   return true;
 }
 
 auto BackgroundParentImpl::AllocPUDPSocketParent(
-    const Maybe<PrincipalInfo>& /* unused */, const nsCString& /* unused */)
+    const Maybe<PrincipalInfo>& /* unused */, const nsCString & /* unused */)
     -> PUDPSocketParent* {
   RefPtr<UDPSocketParent> p = new UDPSocketParent(this);
 
   return p.forget().take();
 }
 
 mozilla::ipc::IPCResult BackgroundParentImpl::RecvPUDPSocketConstructor(
     PUDPSocketParent* aActor, const Maybe<PrincipalInfo>& aOptionalPrincipal,
@@ -1309,37 +1309,24 @@ mozilla::ipc::IPCResult BackgroundParent
     const PrincipalInfo& aPrincipalInfo) {
   static_cast<dom::EndpointForReportParent*>(aActor)->Run(aGroupName,
                                                           aPrincipalInfo);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 BackgroundParentImpl::RecvEnsureRDDProcessAndCreateBridge(
-    EnsureRDDProcessAndCreateBridgeResolver&& aResolver) {
+    nsresult* aRv, Endpoint<PRemoteDecoderManagerChild>* aEndpoint) {
   RDDProcessManager* rdd = RDDProcessManager::Get();
-  using Type =
-      Tuple<const nsresult&, Endpoint<mozilla::PRemoteDecoderManagerChild>&&>;
-  if (!rdd) {
-    aResolver(
-        Type(NS_ERROR_NOT_AVAILABLE, Endpoint<PRemoteDecoderManagerChild>()));
+  if (rdd && rdd->EnsureRDDProcessAndCreateBridge(OtherPid(), aEndpoint)) {
+    *aRv = NS_OK;
   } else {
-    rdd->EnsureRDDProcessAndCreateBridge(OtherPid())
-        ->Then(GetCurrentSerialEventTarget(), __func__,
-               [resolver = std::move(aResolver)](
-                   mozilla::RDDProcessManager::EnsureRDDPromise::
-                       ResolveOrRejectValue&& aValue) mutable {
-                 if (aValue.IsReject()) {
-                   resolver(Type(aValue.RejectValue(),
-                                 Endpoint<PRemoteDecoderManagerChild>()));
-                   return;
-                 }
-                 resolver(Type(NS_OK, std::move(aValue.ResolveValue())));
-               });
+    *aRv = NS_ERROR_NOT_AVAILABLE;
   }
+
   return IPC_OK();
 }
 
 bool BackgroundParentImpl::DeallocPEndpointForReportParent(
     PEndpointForReportParent* aActor) {
   RefPtr<dom::EndpointForReportParent> actor =
       dont_AddRef(static_cast<dom::EndpointForReportParent*>(aActor));
   return true;
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -387,17 +387,17 @@ class BackgroundParentImpl : public PBac
   PEndpointForReportParent* AllocPEndpointForReportParent(
       const nsString& aGroupName, const PrincipalInfo& aPrincipalInfo) override;
 
   mozilla::ipc::IPCResult RecvPEndpointForReportConstructor(
       PEndpointForReportParent* actor, const nsString& aGroupName,
       const PrincipalInfo& aPrincipalInfo) override;
 
   mozilla::ipc::IPCResult RecvEnsureRDDProcessAndCreateBridge(
-      EnsureRDDProcessAndCreateBridgeResolver&& aResolver) override;
+      nsresult* aRv, Endpoint<PRemoteDecoderManagerChild>* aEndpoint) override;
 
   bool DeallocPEndpointForReportParent(
       PEndpointForReportParent* aActor) override;
 
   mozilla::ipc::IPCResult RecvRemoveEndpoint(
       const nsString& aGroupName, const nsCString& aEndpointURL,
       const PrincipalInfo& aPrincipalInfo) override;
 
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -258,17 +258,18 @@ parent:
                              int32_t aPort,
                              OriginAttributes aOriginAttributes,
                              ByteArray? aStapledOCSPResponse,
                              ByteArray? aSctsFromTLSExtension,
                              DelegatedCredentialInfoArg? aDcInfo,
                              uint32_t aProviderFlags,
                              uint32_t aCertVerifierFlags);
 
-  async EnsureRDDProcessAndCreateBridge()
+  // See Bug 1518344 - Investigate using async for PBackground::EnsureRDDProcessAndCreateBridge
+  sync EnsureRDDProcessAndCreateBridge()
       returns (nsresult rv, Endpoint<PRemoteDecoderManagerChild> aEndpoint);
 
 child:
   async PCache();
   async PCacheStreamControl();
 
   async PParentToChildStream();
 
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -877,18 +877,22 @@ description = legacy sync IPC - please a
 [PGMPService::LaunchGMPForNodeId]
 description = legacy sync IPC - please add detailed description
 [PGMPService::GetGMPNodeId]
 description = legacy sync IPC - please add detailed description
 [PGMPVideoDecoder::NeedShmem]
 description = legacy sync IPC - please add detailed description
 [PGMPVideoEncoder::NeedShmem]
 description = legacy sync IPC - please add detailed description
+[PRemoteDecoderManager::PRemoteDecoder]
+description = See Bug 1505976 - investigate changing to async instead of matching GPU pattern
 [PRemoteDecoderManager::Readback]
 description = legacy sync IPC - please add detailed description
+[PBackground::EnsureRDDProcessAndCreateBridge]
+description = See Bug 1518344 - investigate using async for PBackground::EnsureRDDProcessAndCreateBridge
 [PBackgroundStorage::Preload]
 description = legacy sync IPC - please add detailed description
 [PBackgroundLSDatabase::PBackgroundLSSnapshot]
 description = See corresponding comment in PBackgroundLSDatabase.ipdl
 [PBackgroundLSSnapshot::LoadValueAndMoreItems]
 description = See corresponding comment in PBackgroundLSSnapshot.ipdl
 [PBackgroundLSSnapshot::LoadKeys]
 description = See corresponding comment in PBackgroundLSSnapshot.ipdl
--- a/mfbt/WeakPtr.h
+++ b/mfbt/WeakPtr.h
@@ -289,18 +289,16 @@ class WeakPtr {
 #ifdef MOZILLA_INTERNAL_API
     if (Destruct == detail::WeakPtrDestructorBehavior::ProxyToMainThread) {
       MOZ_ASSERT(NS_IsMainThread(),
                  "MainThreadWeakPtr makes no sense on non-main threads");
     }
 #endif
   }
 
-  explicit WeakPtr(const RefPtr<T>& aOther) : WeakPtr(aOther.get()) {}
-
   // Ensure that mRef is dereferenceable in the uninitialized state.
   WeakPtr() : mRef(new WeakReference(nullptr)) {}
 
   explicit operator bool() const { return mRef->get(); }
   T* get() const { return static_cast<T*>(mRef->get()); }
   operator T*() const { return get(); }
   T& operator*() const { return *get(); }
   T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return get(); }