--- 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 - ? ¶ms.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(); }