summaryrefslogtreecommitdiffstats
path: root/dom/media/webcodecs/DecoderTemplate.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webcodecs/DecoderTemplate.h')
-rw-r--r--dom/media/webcodecs/DecoderTemplate.h260
1 files changed, 260 insertions, 0 deletions
diff --git a/dom/media/webcodecs/DecoderTemplate.h b/dom/media/webcodecs/DecoderTemplate.h
new file mode 100644
index 0000000000..fe0cb5baee
--- /dev/null
+++ b/dom/media/webcodecs/DecoderTemplate.h
@@ -0,0 +1,260 @@
+/* -*- 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 mozilla_dom_DecoderTemplate_h
+#define mozilla_dom_DecoderTemplate_h
+
+#include <queue>
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/DecoderAgent.h"
+#include "mozilla/MozPromise.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/Result.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/dom/WorkerRef.h"
+#include "mozilla/media/MediaUtils.h"
+#include "nsStringFwd.h"
+#include "WebCodecsUtils.h"
+
+namespace mozilla {
+
+class TrackInfo;
+
+namespace dom {
+
+class WebCodecsErrorCallback;
+class Promise;
+enum class CodecState : uint8_t;
+
+template <typename DecoderType>
+class DecoderTemplate : public DOMEventTargetHelper {
+ using Self = DecoderTemplate<DecoderType>;
+ using ConfigType = typename DecoderType::ConfigType;
+ using ConfigTypeInternal = typename DecoderType::ConfigTypeInternal;
+ using InputType = typename DecoderType::InputType;
+ using InputTypeInternal = typename DecoderType::InputTypeInternal;
+ using OutputType = typename DecoderType::OutputType;
+ using OutputCallbackType = typename DecoderType::OutputCallbackType;
+
+ /* ControlMessage classes */
+ protected:
+ class ConfigureMessage;
+ class DecodeMessage;
+ class FlushMessage;
+
+ class ControlMessage {
+ public:
+ explicit ControlMessage(const nsACString& aTitle);
+ virtual ~ControlMessage() = default;
+ virtual void Cancel() = 0;
+ virtual bool IsProcessing() = 0;
+
+ virtual const nsCString& ToString() const { return mTitle; }
+ virtual ConfigureMessage* AsConfigureMessage() { return nullptr; }
+ virtual DecodeMessage* AsDecodeMessage() { return nullptr; }
+ virtual FlushMessage* AsFlushMessage() { return nullptr; }
+
+ const nsCString mTitle; // Used to identify the message in the logs.
+ };
+
+ class ConfigureMessage final
+ : public ControlMessage,
+ public MessageRequestHolder<DecoderAgent::ConfigurePromise> {
+ public:
+ using Id = DecoderAgent::Id;
+ static constexpr Id NoId = 0;
+ static ConfigureMessage* Create(UniquePtr<ConfigTypeInternal>&& aConfig);
+
+ ~ConfigureMessage() = default;
+ virtual void Cancel() override { Disconnect(); }
+ virtual bool IsProcessing() override { return Exists(); };
+ virtual ConfigureMessage* AsConfigureMessage() override { return this; }
+ const ConfigTypeInternal& Config() { return *mConfig; }
+ UniquePtr<ConfigTypeInternal> TakeConfig() { return std::move(mConfig); }
+
+ const Id mId; // A unique id shown in log.
+
+ private:
+ ConfigureMessage(Id aId, UniquePtr<ConfigTypeInternal>&& aConfig);
+
+ UniquePtr<ConfigTypeInternal> mConfig;
+ };
+
+ class DecodeMessage final
+ : public ControlMessage,
+ public MessageRequestHolder<DecoderAgent::DecodePromise> {
+ public:
+ using Id = size_t;
+ using ConfigId = typename Self::ConfigureMessage::Id;
+ DecodeMessage(Id aId, ConfigId aConfigId,
+ UniquePtr<InputTypeInternal>&& aData);
+ ~DecodeMessage() = default;
+ virtual void Cancel() override { Disconnect(); }
+ virtual bool IsProcessing() override { return Exists(); };
+ virtual DecodeMessage* AsDecodeMessage() override { return this; }
+ const Id mId; // A unique id shown in log.
+
+ UniquePtr<InputTypeInternal> mData;
+ };
+
+ class FlushMessage final
+ : public ControlMessage,
+ public MessageRequestHolder<DecoderAgent::DecodePromise> {
+ public:
+ using Id = size_t;
+ using ConfigId = typename Self::ConfigureMessage::Id;
+ FlushMessage(Id aId, ConfigId aConfigId, Promise* aPromise);
+ ~FlushMessage() = default;
+ virtual void Cancel() override { Disconnect(); }
+ virtual bool IsProcessing() override { return Exists(); };
+ virtual FlushMessage* AsFlushMessage() override { return this; }
+ already_AddRefed<Promise> TakePromise() { return mPromise.forget(); }
+ void RejectPromiseIfAny(const nsresult& aReason);
+
+ const Id mId; // A unique id shown in log.
+
+ private:
+ RefPtr<Promise> mPromise;
+ };
+
+ protected:
+ DecoderTemplate(nsIGlobalObject* aGlobalObject,
+ RefPtr<WebCodecsErrorCallback>&& aErrorCallback,
+ RefPtr<OutputCallbackType>&& aOutputCallback);
+
+ virtual ~DecoderTemplate() = default;
+
+ /* WebCodecs interfaces */
+ public:
+ IMPL_EVENT_HANDLER(dequeue)
+
+ CodecState State() const { return mState; };
+
+ uint32_t DecodeQueueSize() const { return mDecodeQueueSize; };
+
+ void Configure(const ConfigType& aConfig, ErrorResult& aRv);
+
+ void Decode(InputType& aInput, ErrorResult& aRv);
+
+ already_AddRefed<Promise> Flush(ErrorResult& aRv);
+
+ void Reset(ErrorResult& aRv);
+
+ void Close(ErrorResult& aRv);
+
+ /* Type conversion functions for the Decoder implementation */
+ protected:
+ virtual already_AddRefed<MediaRawData> InputDataToMediaRawData(
+ UniquePtr<InputTypeInternal>&& aData, TrackInfo& aInfo,
+ const ConfigTypeInternal& aConfig) = 0;
+ virtual nsTArray<RefPtr<OutputType>> DecodedDataToOutputType(
+ nsIGlobalObject* aGlobalObject, const nsTArray<RefPtr<MediaData>>&& aData,
+ ConfigTypeInternal& aConfig) = 0;
+
+ protected:
+ // DecoderTemplate can run on either main thread or worker thread.
+ void AssertIsOnOwningThread() const {
+ NS_ASSERT_OWNINGTHREAD(DecoderTemplate);
+ }
+
+ Result<Ok, nsresult> ResetInternal(const nsresult& aResult);
+ // Calling this method calls the error callback synchronously.
+ MOZ_CAN_RUN_SCRIPT
+ void CloseInternal(const nsresult& aResult);
+ // Calling this method doesn't call the error calback.
+ Result<Ok, nsresult> CloseInternalWithAbort();
+
+ MOZ_CAN_RUN_SCRIPT void ReportError(const nsresult& aResult);
+ MOZ_CAN_RUN_SCRIPT void OutputDecodedData(
+ const nsTArray<RefPtr<MediaData>>&& aData);
+
+ void ScheduleDequeueEventIfNeeded();
+ nsresult FireEvent(nsAtom* aTypeWithOn, const nsAString& aEventType);
+
+ void ProcessControlMessageQueue();
+ void CancelPendingControlMessages(const nsresult& aResult);
+
+ // Queue a task to the control thread. This is to be used when a task needs to
+ // perform multiple steps.
+ template <typename Func>
+ void QueueATask(const char* aName, Func&& aSteps);
+
+ MessageProcessedResult ProcessConfigureMessage(
+ UniquePtr<ControlMessage>& aMessage);
+
+ MessageProcessedResult ProcessDecodeMessage(
+ UniquePtr<ControlMessage>& aMessage);
+
+ MessageProcessedResult ProcessFlushMessage(
+ UniquePtr<ControlMessage>& aMessage);
+
+ // Returns true when mAgent can be created.
+ bool CreateDecoderAgent(DecoderAgent::Id aId,
+ UniquePtr<ConfigTypeInternal>&& aConfig,
+ UniquePtr<TrackInfo>&& aInfo);
+ void DestroyDecoderAgentIfAny();
+
+ // Constant in practice, only set in ctor.
+ RefPtr<WebCodecsErrorCallback> mErrorCallback;
+ RefPtr<OutputCallbackType> mOutputCallback;
+
+ CodecState mState;
+ bool mKeyChunkRequired;
+
+ bool mMessageQueueBlocked;
+ std::queue<UniquePtr<ControlMessage>> mControlMessageQueue;
+ UniquePtr<ControlMessage> mProcessingMessage;
+
+ uint32_t mDecodeQueueSize;
+ bool mDequeueEventScheduled;
+
+ // A unique id tracking the ConfigureMessage and will be used as the
+ // DecoderAgent's Id.
+ uint32_t mLatestConfigureId;
+ // Tracking how many decode data has been enqueued and this number will be
+ // used as the DecodeMessage's Id.
+ size_t mDecodeCounter;
+ // Tracking how many flush request has been enqueued and this number will be
+ // used as the FlushMessage's Id.
+ size_t mFlushCounter;
+
+ // DecoderAgent will be created every time "configure" is being processed, and
+ // will be destroyed when "reset" or another "configure" is called (spec
+ // allows calling two "configure" without a "reset" in between).
+ RefPtr<DecoderAgent> mAgent;
+ UniquePtr<ConfigTypeInternal> mActiveConfig;
+
+ // Used to add a nsIAsyncShutdownBlocker on main thread to block
+ // xpcom-shutdown before the underlying MediaDataDecoder is created. The
+ // blocker will be held until the underlying MediaDataDecoder has been shut
+ // down. This blocker guarantees RemoteDecoderManagerChild's thread, where the
+ // underlying RemoteMediaDataDecoder is on, outlives the
+ // RemoteMediaDataDecoder, since the thread releasing, which happens on main
+ // thread when getting a xpcom-shutdown signal, is blocked by the added
+ // blocker. As a result, RemoteMediaDataDecoder can safely work on worker
+ // thread with a holding blocker (otherwise, if RemoteDecoderManagerChild
+ // releases its thread on main thread before RemoteMediaDataDecoder's
+ // Shutdown() task run on worker thread, RemoteMediaDataDecoder has no thread
+ // to run).
+ UniquePtr<media::ShutdownBlockingTicket> mShutdownBlocker;
+
+ // Held to make sure the dispatched tasks can be done before worker is going
+ // away. As long as this worker-ref is held somewhere, the tasks dispatched to
+ // the worker can be executed (otherwise the tasks would be canceled). This
+ // ref should be activated as long as the underlying MediaDataDecoder is
+ // alive, and should keep alive until mShutdownBlocker is dropped, so all
+ // MediaDataDecoder's tasks and mShutdownBlocker-releasing task can be
+ // executed.
+ // TODO: Use StrongWorkerRef instead if this is always used in the same
+ // thread?
+ RefPtr<ThreadSafeWorkerRef> mWorkerRef;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DecoderTemplate_h