summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/AllocationPolicy.h
blob: a53f923483c520fed1dac56ce930ef7571c6a20b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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