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/. */
7 #ifndef mozilla_dom_DecoderTemplate_h
8 #define mozilla_dom_DecoderTemplate_h
12 #include "mozilla/DOMEventTargetHelper.h"
13 #include "mozilla/DecoderAgent.h"
14 #include "mozilla/MozPromise.h"
15 #include "mozilla/RefPtr.h"
16 #include "mozilla/Result.h"
17 #include "mozilla/UniquePtr.h"
18 #include "mozilla/dom/WorkerRef.h"
19 #include "mozilla/media/MediaUtils.h"
20 #include "nsStringFwd.h"
21 #include "WebCodecsUtils.h"
29 class WebCodecsErrorCallback
;
31 enum class CodecState
: uint8_t;
33 template <typename DecoderType
>
34 class DecoderTemplate
: public DOMEventTargetHelper
{
35 using Self
= DecoderTemplate
<DecoderType
>;
36 using ConfigType
= typename
DecoderType::ConfigType
;
37 using ConfigTypeInternal
= typename
DecoderType::ConfigTypeInternal
;
38 using InputType
= typename
DecoderType::InputType
;
39 using InputTypeInternal
= typename
DecoderType::InputTypeInternal
;
40 using OutputType
= typename
DecoderType::OutputType
;
41 using OutputCallbackType
= typename
DecoderType::OutputCallbackType
;
43 /* ControlMessage classes */
45 class ConfigureMessage
;
49 class ControlMessage
{
51 explicit ControlMessage(const nsACString
& aTitle
);
52 virtual ~ControlMessage() = default;
53 virtual void Cancel() = 0;
54 virtual bool IsProcessing() = 0;
56 virtual const nsCString
& ToString() const { return mTitle
; }
57 virtual ConfigureMessage
* AsConfigureMessage() { return nullptr; }
58 virtual DecodeMessage
* AsDecodeMessage() { return nullptr; }
59 virtual FlushMessage
* AsFlushMessage() { return nullptr; }
61 const nsCString mTitle
; // Used to identify the message in the logs.
64 class ConfigureMessage final
65 : public ControlMessage
,
66 public MessageRequestHolder
<DecoderAgent::ConfigurePromise
> {
68 using Id
= DecoderAgent::Id
;
69 static constexpr Id NoId
= 0;
70 static ConfigureMessage
* Create(UniquePtr
<ConfigTypeInternal
>&& aConfig
);
72 ~ConfigureMessage() = default;
73 virtual void Cancel() override
{ Disconnect(); }
74 virtual bool IsProcessing() override
{ return Exists(); };
75 virtual ConfigureMessage
* AsConfigureMessage() override
{ return this; }
76 const ConfigTypeInternal
& Config() { return *mConfig
; }
77 UniquePtr
<ConfigTypeInternal
> TakeConfig() { return std::move(mConfig
); }
79 const Id mId
; // A unique id shown in log.
82 ConfigureMessage(Id aId
, UniquePtr
<ConfigTypeInternal
>&& aConfig
);
84 UniquePtr
<ConfigTypeInternal
> mConfig
;
87 class DecodeMessage final
88 : public ControlMessage
,
89 public MessageRequestHolder
<DecoderAgent::DecodePromise
> {
92 using ConfigId
= typename
Self::ConfigureMessage::Id
;
93 DecodeMessage(Id aId
, ConfigId aConfigId
,
94 UniquePtr
<InputTypeInternal
>&& aData
);
95 ~DecodeMessage() = default;
96 virtual void Cancel() override
{ Disconnect(); }
97 virtual bool IsProcessing() override
{ return Exists(); };
98 virtual DecodeMessage
* AsDecodeMessage() override
{ return this; }
99 const Id mId
; // A unique id shown in log.
101 UniquePtr
<InputTypeInternal
> mData
;
104 class FlushMessage final
105 : public ControlMessage
,
106 public MessageRequestHolder
<DecoderAgent::DecodePromise
> {
109 using ConfigId
= typename
Self::ConfigureMessage::Id
;
110 FlushMessage(Id aId
, ConfigId aConfigId
, Promise
* aPromise
);
111 ~FlushMessage() = default;
112 virtual void Cancel() override
{ Disconnect(); }
113 virtual bool IsProcessing() override
{ return Exists(); };
114 virtual FlushMessage
* AsFlushMessage() override
{ return this; }
115 already_AddRefed
<Promise
> TakePromise() { return mPromise
.forget(); }
116 void RejectPromiseIfAny(const nsresult
& aReason
);
118 const Id mId
; // A unique id shown in log.
121 RefPtr
<Promise
> mPromise
;
125 DecoderTemplate(nsIGlobalObject
* aGlobalObject
,
126 RefPtr
<WebCodecsErrorCallback
>&& aErrorCallback
,
127 RefPtr
<OutputCallbackType
>&& aOutputCallback
);
129 virtual ~DecoderTemplate() = default;
131 /* WebCodecs interfaces */
133 IMPL_EVENT_HANDLER(dequeue
)
135 CodecState
State() const { return mState
; };
137 uint32_t DecodeQueueSize() const { return mDecodeQueueSize
; };
139 void Configure(const ConfigType
& aConfig
, ErrorResult
& aRv
);
141 void Decode(InputType
& aInput
, ErrorResult
& aRv
);
143 already_AddRefed
<Promise
> Flush(ErrorResult
& aRv
);
145 void Reset(ErrorResult
& aRv
);
147 void Close(ErrorResult
& aRv
);
149 /* Type conversion functions for the Decoder implementation */
151 virtual already_AddRefed
<MediaRawData
> InputDataToMediaRawData(
152 UniquePtr
<InputTypeInternal
>&& aData
, TrackInfo
& aInfo
,
153 const ConfigTypeInternal
& aConfig
) = 0;
154 virtual nsTArray
<RefPtr
<OutputType
>> DecodedDataToOutputType(
155 nsIGlobalObject
* aGlobalObject
, const nsTArray
<RefPtr
<MediaData
>>&& aData
,
156 ConfigTypeInternal
& aConfig
) = 0;
159 // DecoderTemplate can run on either main thread or worker thread.
160 void AssertIsOnOwningThread() const {
161 NS_ASSERT_OWNINGTHREAD(DecoderTemplate
);
164 Result
<Ok
, nsresult
> ResetInternal(const nsresult
& aResult
);
165 // Calling this method calls the error callback synchronously.
167 void CloseInternal(const nsresult
& aResult
);
168 // Calling this method doesn't call the error calback.
169 Result
<Ok
, nsresult
> CloseInternalWithAbort();
171 MOZ_CAN_RUN_SCRIPT
void ReportError(const nsresult
& aResult
);
172 MOZ_CAN_RUN_SCRIPT
void OutputDecodedData(
173 const nsTArray
<RefPtr
<MediaData
>>&& aData
);
175 void ScheduleDequeueEventIfNeeded();
176 nsresult
FireEvent(nsAtom
* aTypeWithOn
, const nsAString
& aEventType
);
178 void ProcessControlMessageQueue();
179 void CancelPendingControlMessages(const nsresult
& aResult
);
181 // Queue a task to the control thread. This is to be used when a task needs to
182 // perform multiple steps.
183 template <typename Func
>
184 void QueueATask(const char* aName
, Func
&& aSteps
);
186 MessageProcessedResult
ProcessConfigureMessage(
187 UniquePtr
<ControlMessage
>& aMessage
);
189 MessageProcessedResult
ProcessDecodeMessage(
190 UniquePtr
<ControlMessage
>& aMessage
);
192 MessageProcessedResult
ProcessFlushMessage(
193 UniquePtr
<ControlMessage
>& aMessage
);
195 // Returns true when mAgent can be created.
196 bool CreateDecoderAgent(DecoderAgent::Id aId
,
197 UniquePtr
<ConfigTypeInternal
>&& aConfig
,
198 UniquePtr
<TrackInfo
>&& aInfo
);
199 void DestroyDecoderAgentIfAny();
201 // Constant in practice, only set in ctor.
202 RefPtr
<WebCodecsErrorCallback
> mErrorCallback
;
203 RefPtr
<OutputCallbackType
> mOutputCallback
;
206 bool mKeyChunkRequired
;
208 bool mMessageQueueBlocked
;
209 std::queue
<UniquePtr
<ControlMessage
>> mControlMessageQueue
;
210 UniquePtr
<ControlMessage
> mProcessingMessage
;
212 uint32_t mDecodeQueueSize
;
213 bool mDequeueEventScheduled
;
215 // A unique id tracking the ConfigureMessage and will be used as the
216 // DecoderAgent's Id.
217 uint32_t mLatestConfigureId
;
218 // Tracking how many decode data has been enqueued and this number will be
219 // used as the DecodeMessage's Id.
220 size_t mDecodeCounter
;
221 // Tracking how many flush request has been enqueued and this number will be
222 // used as the FlushMessage's Id.
223 size_t mFlushCounter
;
225 // DecoderAgent will be created every time "configure" is being processed, and
226 // will be destroyed when "reset" or another "configure" is called (spec
227 // allows calling two "configure" without a "reset" in between).
228 RefPtr
<DecoderAgent
> mAgent
;
229 UniquePtr
<ConfigTypeInternal
> mActiveConfig
;
231 // Used to add a nsIAsyncShutdownBlocker on main thread to block
232 // xpcom-shutdown before the underlying MediaDataDecoder is created. The
233 // blocker will be held until the underlying MediaDataDecoder has been shut
234 // down. This blocker guarantees RemoteDecoderManagerChild's thread, where the
235 // underlying RemoteMediaDataDecoder is on, outlives the
236 // RemoteMediaDataDecoder, since the thread releasing, which happens on main
237 // thread when getting a xpcom-shutdown signal, is blocked by the added
238 // blocker. As a result, RemoteMediaDataDecoder can safely work on worker
239 // thread with a holding blocker (otherwise, if RemoteDecoderManagerChild
240 // releases its thread on main thread before RemoteMediaDataDecoder's
241 // Shutdown() task run on worker thread, RemoteMediaDataDecoder has no thread
243 UniquePtr
<media::ShutdownBlockingTicket
> mShutdownBlocker
;
245 // Held to make sure the dispatched tasks can be done before worker is going
246 // away. As long as this worker-ref is held somewhere, the tasks dispatched to
247 // the worker can be executed (otherwise the tasks would be canceled). This
248 // ref should be activated as long as the underlying MediaDataDecoder is
249 // alive, and should keep alive until mShutdownBlocker is dropped, so all
250 // MediaDataDecoder's tasks and mShutdownBlocker-releasing task can be
252 // TODO: Use StrongWorkerRef instead if this is always used in the same
254 RefPtr
<ThreadSafeWorkerRef
> mWorkerRef
;
258 } // namespace mozilla
260 #endif // mozilla_dom_DecoderTemplate_h