diff options
Diffstat (limited to 'dom/media/platforms/AllocationPolicy.h')
-rw-r--r-- | dom/media/platforms/AllocationPolicy.h | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/dom/media/platforms/AllocationPolicy.h b/dom/media/platforms/AllocationPolicy.h new file mode 100644 index 0000000000..a53f923483 --- /dev/null +++ b/dom/media/platforms/AllocationPolicy.h @@ -0,0 +1,183 @@ +/* -*- 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/. */ + +#ifndef AllocationPolicy_h_ +#define AllocationPolicy_h_ + +#include <queue> + +#include "MediaInfo.h" +#include "PlatformDecoderModule.h" +#include "TimeUnits.h" +#include "mozilla/MozPromise.h" +#include "mozilla/NotNull.h" +#include "mozilla/ReentrantMonitor.h" +#include "mozilla/StaticMutex.h" + +namespace mozilla { + +/** + * Before calling PDMFactory::CreateDecoder(), Alloc() must be called on the + * policy to get a token object as a permission to create a decoder. The + * token should stay alive until Shutdown() is called on the decoder. The + * destructor of the token will restore the decoder count so it is available + * for next calls of Alloc(). + */ +class AllocPolicy { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AllocPolicy) + + public: + class Token { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Token) + protected: + virtual ~Token() = default; + }; + using Promise = MozPromise<RefPtr<Token>, bool, true>; + + // Acquire a token for decoder creation. Thread-safe. + virtual RefPtr<Promise> Alloc() = 0; + + protected: + virtual ~AllocPolicy() = default; +}; + +/** + * This is a singleton which controls the number of decoders that can be created + * concurrently. + * Instance() will return the TrackType global AllocPolicy. + * Instance() will always return a non-null value. + */ +class GlobalAllocPolicy { + public: + // Get the singleton for the given track type. Thread-safe. + static NotNull<AllocPolicy*> Instance(TrackInfo::TrackType aTrack); + + private: + // Protect access to Instance(). + static StaticMutex sMutex MOZ_UNANNOTATED; +}; + +/** This the actual base implementation underneath all AllocPolicy objects and + * control how many decoders can be created concurrently. + * Alloc() must be called to get a token object as a permission to perform an + * action. The token should stay alive until Shutdown() is called on the + * decoder. The destructor of the token will restore the decoder count so it is + * available for next calls of Alloc(). + **/ +class AllocPolicyImpl : public AllocPolicy { + public: + explicit AllocPolicyImpl(int aDecoderLimit); + RefPtr<Promise> Alloc() override; + + protected: + virtual ~AllocPolicyImpl(); + void RejectAll(); + int MaxDecoderLimit() const { return mMaxDecoderLimit; } + + private: + class AutoDeallocToken; + using PromisePrivate = Promise::Private; + // Called by the destructor of TokenImpl to restore the decoder limit. + void Dealloc(); + // Decrement the decoder limit and resolve a promise if available. + void ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock); + + const int mMaxDecoderLimit; + ReentrantMonitor mMonitor MOZ_UNANNOTATED; + // The number of decoders available for creation. + int mDecoderLimit; + // Requests to acquire tokens. + std::queue<RefPtr<PromisePrivate>> mPromises; +}; + +/** + * This class allows to track and serialise a single decoder allocation at a + * time + */ +class SingleAllocPolicy : public AllocPolicyImpl { + using TrackType = TrackInfo::TrackType; + + public: + SingleAllocPolicy(TrackType aTrack, TaskQueue* aOwnerThread) + : AllocPolicyImpl(1), mTrack(aTrack), mOwnerThread(aOwnerThread) {} + + RefPtr<Promise> Alloc() override; + + // Cancel the request to GlobalAllocPolicy and reject the current token + // request. Note this must happen before mOwnerThread->BeginShutdown(). + void Cancel(); + + private: + class AutoDeallocCombinedToken; + virtual ~SingleAllocPolicy(); + + const TrackType mTrack; + RefPtr<TaskQueue> mOwnerThread; + MozPromiseHolder<Promise> mPendingPromise; + MozPromiseRequestHolder<Promise> mTokenRequest; +}; + +class AllocationWrapper final : public MediaDataDecoder { + using Token = AllocPolicy::Token; + + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AllocationWrapper, final); + + AllocationWrapper(already_AddRefed<MediaDataDecoder> aDecoder, + already_AddRefed<Token> aToken); + + RefPtr<InitPromise> Init() override { return mDecoder->Init(); } + RefPtr<DecodePromise> Decode(MediaRawData* aSample) override { + return mDecoder->Decode(aSample); + } + bool CanDecodeBatch() const override { return mDecoder->CanDecodeBatch(); } + RefPtr<DecodePromise> DecodeBatch( + nsTArray<RefPtr<MediaRawData>>&& aSamples) override { + return mDecoder->DecodeBatch(std::move(aSamples)); + } + RefPtr<DecodePromise> Drain() override { return mDecoder->Drain(); } + RefPtr<FlushPromise> Flush() override { return mDecoder->Flush(); } + bool IsHardwareAccelerated(nsACString& aFailureReason) const override { + return mDecoder->IsHardwareAccelerated(aFailureReason); + } + nsCString GetDescriptionName() const override { + return mDecoder->GetDescriptionName(); + } + nsCString GetProcessName() const override { + return mDecoder->GetProcessName(); + } + nsCString GetCodecName() const override { return mDecoder->GetCodecName(); } + void SetSeekThreshold(const media::TimeUnit& aTime) override { + mDecoder->SetSeekThreshold(aTime); + } + bool SupportDecoderRecycling() const override { + return mDecoder->SupportDecoderRecycling(); + } + RefPtr<ShutdownPromise> Shutdown() override; + ConversionRequired NeedsConversion() const override { + return mDecoder->NeedsConversion(); + } + + typedef MozPromise<RefPtr<MediaDataDecoder>, MediaResult, + /* IsExclusive = */ true> + AllocateDecoderPromise; + // Will create a decoder has soon as one can be created according to the + // AllocPolicy (or GlobalAllocPolicy if aPolicy is null) + // Warning: all aParams members must be valid until the promise has been + // resolved, as some contains raw pointers to objects. + static RefPtr<AllocateDecoderPromise> CreateDecoder( + const CreateDecoderParams& aParams, AllocPolicy* aPolicy = nullptr); + + private: + ~AllocationWrapper(); + + RefPtr<MediaDataDecoder> mDecoder; + RefPtr<Token> mToken; +}; + +} // namespace mozilla + +#endif |