Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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();
}
bool ShouldDecoderAlwaysBeRecycled() const override {
return mDecoder->ShouldDecoderAlwaysBeRecycled();
}
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