DecoderTemplate.h (10209B)
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 mozilla_dom_DecoderTemplate_h 8 #define mozilla_dom_DecoderTemplate_h 9 10 #include <queue> 11 12 #include "SimpleMap.h" 13 #include "WebCodecsUtils.h" 14 #include "mozilla/DOMEventTargetHelper.h" 15 #include "mozilla/DecoderAgent.h" 16 #include "mozilla/MozPromise.h" 17 #include "mozilla/RefPtr.h" 18 #include "mozilla/Result.h" 19 #include "mozilla/UniquePtr.h" 20 #include "mozilla/dom/WorkerRef.h" 21 #include "mozilla/media/MediaUtils.h" 22 #include "nsStringFwd.h" 23 24 namespace mozilla { 25 26 class TrackInfo; 27 28 namespace dom { 29 30 class WebCodecsErrorCallback; 31 class Promise; 32 enum class CodecState : uint8_t; 33 34 template <typename DecoderType> 35 class DecoderTemplate : public DOMEventTargetHelper { 36 using Self = DecoderTemplate<DecoderType>; 37 using ConfigType = typename DecoderType::ConfigType; 38 using ConfigTypeInternal = typename DecoderType::ConfigTypeInternal; 39 using InputType = typename DecoderType::InputType; 40 using InputTypeInternal = typename DecoderType::InputTypeInternal; 41 using OutputType = typename DecoderType::OutputType; 42 using OutputCallbackType = typename DecoderType::OutputCallbackType; 43 44 /* ControlMessage classes */ 45 protected: 46 class ConfigureMessage; 47 class DecodeMessage; 48 class FlushMessage; 49 50 class ControlMessage { 51 public: 52 ControlMessage(WebCodecsId aConfigId) : mConfigId(aConfigId) {}; 53 virtual ~ControlMessage() = default; 54 virtual void Cancel() = 0; 55 virtual bool IsProcessing() = 0; 56 57 virtual nsCString ToString() const = 0; 58 virtual ConfigureMessage* AsConfigureMessage() { return nullptr; } 59 virtual DecodeMessage* AsDecodeMessage() { return nullptr; } 60 virtual FlushMessage* AsFlushMessage() { return nullptr; } 61 62 // All the control message follows a specific configuration. Knowing the 63 // associated configuration of a decode/flush request is helpful in 64 // debugging logs. This id is used to identify which ConfigureMessage the 65 // request follows. 66 const WebCodecsId mConfigId; 67 }; 68 69 class ConfigureMessage final 70 : public ControlMessage, 71 public MessageRequestHolder<DecoderAgent::ConfigurePromise> { 72 public: 73 static ConfigureMessage* Create( 74 already_AddRefed<ConfigTypeInternal> aConfig); 75 76 ~ConfigureMessage() = default; 77 virtual void Cancel() override { Disconnect(); } 78 virtual bool IsProcessing() override { return Exists(); }; 79 virtual nsCString ToString() const override; 80 virtual ConfigureMessage* AsConfigureMessage() override { return this; } 81 const ConfigTypeInternal& Config() { return *mConfig; } 82 already_AddRefed<ConfigTypeInternal> TakeConfig() { 83 return mConfig.forget(); 84 } 85 86 private: 87 ConfigureMessage(WebCodecsId aConfigId, 88 already_AddRefed<ConfigTypeInternal> aConfig); 89 90 RefPtr<ConfigTypeInternal> mConfig; 91 const nsCString mCodec; 92 }; 93 94 class DecodeMessage final 95 : public ControlMessage, 96 public MessageRequestHolder<DecoderAgent::DecodePromise> { 97 public: 98 DecodeMessage(WebCodecsId aSeqId, WebCodecsId aConfigId, 99 UniquePtr<InputTypeInternal>&& aData); 100 ~DecodeMessage() = default; 101 virtual void Cancel() override { Disconnect(); } 102 virtual bool IsProcessing() override { return Exists(); }; 103 virtual nsCString ToString() const override; 104 virtual DecodeMessage* AsDecodeMessage() override { return this; } 105 106 // The sequence id of a decode request associated with a specific 107 // configuration. 108 const WebCodecsId mSeqId; 109 UniquePtr<InputTypeInternal> mData; 110 }; 111 112 class FlushMessage final 113 : public ControlMessage, 114 public MessageRequestHolder<DecoderAgent::DecodePromise> { 115 public: 116 FlushMessage(WebCodecsId aSeqId, WebCodecsId aConfigId); 117 ~FlushMessage() = default; 118 virtual void Cancel() override { Disconnect(); } 119 virtual bool IsProcessing() override { return Exists(); }; 120 virtual nsCString ToString() const override; 121 virtual FlushMessage* AsFlushMessage() override { return this; } 122 123 // The sequence id of a flush request associated with a specific 124 // configuration. 125 const WebCodecsId mSeqId; 126 const int64_t mUniqueId; 127 }; 128 129 protected: 130 DecoderTemplate(nsIGlobalObject* aGlobalObject, 131 RefPtr<WebCodecsErrorCallback>&& aErrorCallback, 132 RefPtr<OutputCallbackType>&& aOutputCallback); 133 134 virtual ~DecoderTemplate() = default; 135 136 /* WebCodecs interfaces */ 137 public: 138 IMPL_EVENT_HANDLER(dequeue) 139 140 CodecState State() const { return mState; }; 141 142 uint32_t DecodeQueueSize() const { return mDecodeQueueSize; }; 143 144 void Configure(const ConfigType& aConfig, ErrorResult& aRv); 145 146 void Decode(InputType& aInput, ErrorResult& aRv); 147 148 already_AddRefed<Promise> Flush(ErrorResult& aRv); 149 150 void Reset(ErrorResult& aRv); 151 152 void Close(ErrorResult& aRv); 153 154 /* Type conversion functions for the Decoder implementation */ 155 protected: 156 virtual already_AddRefed<MediaRawData> InputDataToMediaRawData( 157 UniquePtr<InputTypeInternal>&& aData, TrackInfo& aInfo, 158 const ConfigTypeInternal& aConfig) = 0; 159 virtual nsTArray<RefPtr<OutputType>> DecodedDataToOutputType( 160 nsIGlobalObject* aGlobalObject, const nsTArray<RefPtr<MediaData>>&& aData, 161 const ConfigTypeInternal& aConfig) = 0; 162 163 protected: 164 // DecoderTemplate can run on either main thread or worker thread. 165 void AssertIsOnOwningThread() const { 166 NS_ASSERT_OWNINGTHREAD(DecoderTemplate); 167 } 168 169 Result<Ok, nsresult> ResetInternal(const nsresult& aResult); 170 // Calling this method calls the error callback synchronously. 171 MOZ_CAN_RUN_SCRIPT 172 void CloseInternal(const nsresult& aResult); 173 // Calling this method doesn't call the error calback. 174 Result<Ok, nsresult> CloseInternalWithAbort(); 175 176 MOZ_CAN_RUN_SCRIPT void ReportError(const nsresult& aResult); 177 MOZ_CAN_RUN_SCRIPT void OutputDecodedData( 178 const nsTArray<RefPtr<MediaData>>&& aData, 179 const ConfigTypeInternal& aConfig); 180 181 void ScheduleDequeueEventIfNeeded(); 182 nsresult FireEvent(nsAtom* aTypeWithOn, const nsAString& aEventType); 183 184 void ProcessControlMessageQueue(); 185 void CancelPendingControlMessagesAndFlushPromises(const nsresult& aResult); 186 187 // Queue a task to the control thread. This is to be used when a task needs to 188 // perform multiple steps. 189 template <typename Func> 190 void QueueATask(const char* aName, Func&& aSteps); 191 192 MessageProcessedResult ProcessConfigureMessage( 193 UniquePtr<ControlMessage>& aMessage); 194 195 MessageProcessedResult ProcessDecodeMessage( 196 UniquePtr<ControlMessage>& aMessage); 197 198 MessageProcessedResult ProcessFlushMessage( 199 UniquePtr<ControlMessage>& aMessage); 200 201 // Returns true when mAgent can be created. 202 bool CreateDecoderAgent(DecoderAgent::Id aId, 203 already_AddRefed<ConfigTypeInternal> aConfig, 204 UniquePtr<TrackInfo>&& aInfo); 205 void DestroyDecoderAgentIfAny(); 206 207 // Constant in practice, only set in ctor. 208 RefPtr<WebCodecsErrorCallback> mErrorCallback; 209 RefPtr<OutputCallbackType> mOutputCallback; 210 211 CodecState mState; 212 bool mKeyChunkRequired; 213 214 bool mMessageQueueBlocked; 215 std::queue<UniquePtr<ControlMessage>> mControlMessageQueue; 216 UniquePtr<ControlMessage> mProcessingMessage; 217 218 // When a flush request is initiated, a promise is created and stored in 219 // mPendingFlushPromises until it is settled in the task delivering the flush 220 // result or Reset() is called before the promise is settled. 221 SimpleMap<int64_t, RefPtr<Promise>> mPendingFlushPromises; 222 223 uint32_t mDecodeQueueSize; 224 bool mDequeueEventScheduled; 225 226 // A unique id tracking the ConfigureMessage and will be used as the 227 // DecoderAgent's Id. 228 uint32_t mLatestConfigureId; 229 // Tracking how many decode data has been enqueued and this number will be 230 // used as the DecodeMessage's sequence Id. 231 size_t mDecodeCounter; 232 // Tracking how many flush request has been enqueued and this number will be 233 // used as the FlushMessage's sequence Id. 234 size_t mFlushCounter; 235 236 // DecoderAgent will be created every time "configure" is being processed, and 237 // will be destroyed when "reset" or another "configure" is called (spec 238 // allows calling two "configure" without a "reset" in between). 239 RefPtr<DecoderAgent> mAgent; 240 RefPtr<ConfigTypeInternal> mActiveConfig; 241 242 // Used to add a nsIAsyncShutdownBlocker on main thread to block 243 // xpcom-shutdown before the underlying MediaDataDecoder is created. The 244 // blocker will be held until the underlying MediaDataDecoder has been shut 245 // down. This blocker guarantees RemoteDecoderManagerChild's thread, where the 246 // underlying RemoteMediaDataDecoder is on, outlives the 247 // RemoteMediaDataDecoder, since the thread releasing, which happens on main 248 // thread when getting a xpcom-shutdown signal, is blocked by the added 249 // blocker. As a result, RemoteMediaDataDecoder can safely work on worker 250 // thread with a holding blocker (otherwise, if RemoteDecoderManagerChild 251 // releases its thread on main thread before RemoteMediaDataDecoder's 252 // Shutdown() task run on worker thread, RemoteMediaDataDecoder has no thread 253 // to run). 254 UniquePtr<media::ShutdownBlockingTicket> mShutdownBlocker; 255 256 // Held to make sure the dispatched tasks can be done before worker is going 257 // away. As long as this worker-ref is held somewhere, the tasks dispatched to 258 // the worker can be executed (otherwise the tasks would be canceled). This 259 // ref should be activated as long as the underlying MediaDataDecoder is 260 // alive, and should keep alive until mShutdownBlocker is dropped, so all 261 // MediaDataDecoder's tasks and mShutdownBlocker-releasing task can be 262 // executed. 263 // TODO: Use StrongWorkerRef instead if this is always used in the same 264 // thread? 265 RefPtr<ThreadSafeWorkerRef> mWorkerRef; 266 267 AsyncDurationTracker mAsyncDurationTracker; 268 }; 269 270 } // namespace dom 271 } // namespace mozilla 272 273 #endif // mozilla_dom_DecoderTemplate_h