AllocationPolicy.h (6355B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef AllocationPolicy_h_ 8 #define AllocationPolicy_h_ 9 10 #include <queue> 11 12 #include "MediaInfo.h" 13 #include "PlatformDecoderModule.h" 14 #include "TimeUnits.h" 15 #include "mozilla/MozPromise.h" 16 #include "mozilla/NotNull.h" 17 #include "mozilla/ReentrantMonitor.h" 18 #include "mozilla/StaticMutex.h" 19 20 namespace mozilla { 21 22 /** 23 * Before calling PDMFactory::CreateDecoder(), Alloc() must be called on the 24 * policy to get a token object as a permission to create a decoder. The 25 * token should stay alive until Shutdown() is called on the decoder. The 26 * destructor of the token will restore the decoder count so it is available 27 * for next calls of Alloc(). 28 */ 29 class AllocPolicy { 30 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AllocPolicy) 31 32 public: 33 class Token { 34 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Token) 35 protected: 36 virtual ~Token() = default; 37 }; 38 using Promise = MozPromise<RefPtr<Token>, bool, true>; 39 40 // Acquire a token for decoder creation. Thread-safe. 41 virtual RefPtr<Promise> Alloc() = 0; 42 43 protected: 44 virtual ~AllocPolicy() = default; 45 }; 46 47 /** 48 * This is a singleton which controls the number of decoders that can be created 49 * concurrently. 50 * Instance() will return the TrackType global AllocPolicy. 51 * Instance() will always return a non-null value. 52 */ 53 class GlobalAllocPolicy { 54 public: 55 // Get the singleton for the given track type. Thread-safe. 56 static NotNull<AllocPolicy*> Instance(TrackInfo::TrackType aTrack); 57 58 private: 59 // Protect access to Instance(). 60 static StaticMutex sMutex MOZ_UNANNOTATED; 61 }; 62 63 /** This the actual base implementation underneath all AllocPolicy objects and 64 * control how many decoders can be created concurrently. 65 * Alloc() must be called to get a token object as a permission to perform an 66 * action. The token should stay alive until Shutdown() is called on the 67 * decoder. The destructor of the token will restore the decoder count so it is 68 * available for next calls of Alloc(). 69 **/ 70 class AllocPolicyImpl : public AllocPolicy { 71 public: 72 explicit AllocPolicyImpl(int aDecoderLimit); 73 RefPtr<Promise> Alloc() override; 74 75 protected: 76 virtual ~AllocPolicyImpl(); 77 void RejectAll(); 78 int MaxDecoderLimit() const { return mMaxDecoderLimit; } 79 80 private: 81 class AutoDeallocToken; 82 using PromisePrivate = Promise::Private; 83 // Called by the destructor of TokenImpl to restore the decoder limit. 84 void Dealloc(); 85 // Decrement the decoder limit and resolve a promise if available. 86 void ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock); 87 88 const int mMaxDecoderLimit; 89 ReentrantMonitor mMonitor MOZ_UNANNOTATED; 90 // The number of decoders available for creation. 91 int mDecoderLimit; 92 // Requests to acquire tokens. 93 std::queue<RefPtr<PromisePrivate>> mPromises; 94 }; 95 96 /** 97 * This class allows to track and serialise a single decoder allocation at a 98 * time 99 */ 100 class SingleAllocPolicy : public AllocPolicyImpl { 101 using TrackType = TrackInfo::TrackType; 102 103 public: 104 SingleAllocPolicy(TrackType aTrack, TaskQueue* aOwnerThread) 105 : AllocPolicyImpl(1), mTrack(aTrack), mOwnerThread(aOwnerThread) {} 106 107 RefPtr<Promise> Alloc() override; 108 109 // Cancel the request to GlobalAllocPolicy and reject the current token 110 // request. Note this must happen before mOwnerThread->BeginShutdown(). 111 void Cancel(); 112 113 private: 114 class AutoDeallocCombinedToken; 115 virtual ~SingleAllocPolicy(); 116 117 const TrackType mTrack; 118 RefPtr<TaskQueue> mOwnerThread; 119 MozPromiseHolder<Promise> mPendingPromise; 120 MozPromiseRequestHolder<Promise> mTokenRequest; 121 }; 122 123 class AllocationWrapper final : public MediaDataDecoder { 124 using Token = AllocPolicy::Token; 125 126 public: 127 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AllocationWrapper, final); 128 129 AllocationWrapper(already_AddRefed<MediaDataDecoder> aDecoder, 130 already_AddRefed<Token> aToken); 131 132 RefPtr<InitPromise> Init() override { return mDecoder->Init(); } 133 RefPtr<DecodePromise> Decode(MediaRawData* aSample) override { 134 return mDecoder->Decode(aSample); 135 } 136 bool CanDecodeBatch() const override { return mDecoder->CanDecodeBatch(); } 137 RefPtr<DecodePromise> DecodeBatch( 138 nsTArray<RefPtr<MediaRawData>>&& aSamples) override { 139 return mDecoder->DecodeBatch(std::move(aSamples)); 140 } 141 RefPtr<DecodePromise> Drain() override { return mDecoder->Drain(); } 142 RefPtr<FlushPromise> Flush() override { return mDecoder->Flush(); } 143 bool IsHardwareAccelerated(nsACString& aFailureReason) const override { 144 return mDecoder->IsHardwareAccelerated(aFailureReason); 145 } 146 nsCString GetDescriptionName() const override { 147 return mDecoder->GetDescriptionName(); 148 } 149 nsCString GetProcessName() const override { 150 return mDecoder->GetProcessName(); 151 } 152 nsCString GetCodecName() const override { return mDecoder->GetCodecName(); } 153 void SetSeekThreshold(const media::TimeUnit& aTime) override { 154 mDecoder->SetSeekThreshold(aTime); 155 } 156 bool SupportDecoderRecycling() const override { 157 return mDecoder->SupportDecoderRecycling(); 158 } 159 bool ShouldDecoderAlwaysBeRecycled() const override { 160 return mDecoder->ShouldDecoderAlwaysBeRecycled(); 161 } 162 RefPtr<ShutdownPromise> Shutdown() override; 163 ConversionRequired NeedsConversion() const override { 164 return mDecoder->NeedsConversion(); 165 } 166 167 Maybe<PropertyValue> GetDecodeProperty(PropertyName aName) const override { 168 return mDecoder->GetDecodeProperty(aName); 169 } 170 171 typedef MozPromise<RefPtr<MediaDataDecoder>, MediaResult, 172 /* IsExclusive = */ true> 173 AllocateDecoderPromise; 174 // Will create a decoder has soon as one can be created according to the 175 // AllocPolicy (or GlobalAllocPolicy if aPolicy is null) 176 // Warning: all aParams members must be valid until the promise has been 177 // resolved, as some contains raw pointers to objects. 178 static RefPtr<AllocateDecoderPromise> CreateDecoder( 179 const CreateDecoderParams& aParams, AllocPolicy* aPolicy = nullptr); 180 181 private: 182 ~AllocationWrapper(); 183 184 RefPtr<MediaDataDecoder> mDecoder; 185 RefPtr<Token> mToken; 186 }; 187 188 } // namespace mozilla 189 190 #endif