271 lines
9.9 KiB
C++
271 lines
9.9 KiB
C++
/* -*- 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 "SimpleMap.h"
|
|
#include "WebCodecsUtils.h"
|
|
#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"
|
|
|
|
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:
|
|
ControlMessage(WebCodecsId aConfigId) : mConfigId(aConfigId) {};
|
|
virtual ~ControlMessage() = default;
|
|
virtual void Cancel() = 0;
|
|
virtual bool IsProcessing() = 0;
|
|
|
|
virtual nsCString ToString() const = 0;
|
|
virtual ConfigureMessage* AsConfigureMessage() { return nullptr; }
|
|
virtual DecodeMessage* AsDecodeMessage() { return nullptr; }
|
|
virtual FlushMessage* AsFlushMessage() { return nullptr; }
|
|
|
|
// All the control message follows a specific configuration. Knowing the
|
|
// associated configuration of a decode/flush request is helpful in
|
|
// debugging logs. This id is used to identify which ConfigureMessage the
|
|
// request follows.
|
|
const WebCodecsId mConfigId;
|
|
};
|
|
|
|
class ConfigureMessage final
|
|
: public ControlMessage,
|
|
public MessageRequestHolder<DecoderAgent::ConfigurePromise> {
|
|
public:
|
|
static ConfigureMessage* Create(
|
|
already_AddRefed<ConfigTypeInternal> aConfig);
|
|
|
|
~ConfigureMessage() = default;
|
|
virtual void Cancel() override { Disconnect(); }
|
|
virtual bool IsProcessing() override { return Exists(); };
|
|
virtual nsCString ToString() const override;
|
|
virtual ConfigureMessage* AsConfigureMessage() override { return this; }
|
|
const ConfigTypeInternal& Config() { return *mConfig; }
|
|
already_AddRefed<ConfigTypeInternal> TakeConfig() {
|
|
return mConfig.forget();
|
|
}
|
|
|
|
private:
|
|
ConfigureMessage(WebCodecsId aConfigId,
|
|
already_AddRefed<ConfigTypeInternal> aConfig);
|
|
|
|
RefPtr<ConfigTypeInternal> mConfig;
|
|
const nsCString mCodec;
|
|
};
|
|
|
|
class DecodeMessage final
|
|
: public ControlMessage,
|
|
public MessageRequestHolder<DecoderAgent::DecodePromise> {
|
|
public:
|
|
DecodeMessage(WebCodecsId aSeqId, WebCodecsId aConfigId,
|
|
UniquePtr<InputTypeInternal>&& aData);
|
|
~DecodeMessage() = default;
|
|
virtual void Cancel() override { Disconnect(); }
|
|
virtual bool IsProcessing() override { return Exists(); };
|
|
virtual nsCString ToString() const override;
|
|
virtual DecodeMessage* AsDecodeMessage() override { return this; }
|
|
|
|
// The sequence id of a decode request associated with a specific
|
|
// configuration.
|
|
const WebCodecsId mSeqId;
|
|
UniquePtr<InputTypeInternal> mData;
|
|
};
|
|
|
|
class FlushMessage final
|
|
: public ControlMessage,
|
|
public MessageRequestHolder<DecoderAgent::DecodePromise> {
|
|
public:
|
|
FlushMessage(WebCodecsId aSeqId, WebCodecsId aConfigId);
|
|
~FlushMessage() = default;
|
|
virtual void Cancel() override { Disconnect(); }
|
|
virtual bool IsProcessing() override { return Exists(); };
|
|
virtual nsCString ToString() const override;
|
|
virtual FlushMessage* AsFlushMessage() override { return this; }
|
|
|
|
// The sequence id of a flush request associated with a specific
|
|
// configuration.
|
|
const WebCodecsId mSeqId;
|
|
const int64_t mUniqueId;
|
|
};
|
|
|
|
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,
|
|
const 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,
|
|
const ConfigTypeInternal& aConfig);
|
|
|
|
void ScheduleDequeueEventIfNeeded();
|
|
nsresult FireEvent(nsAtom* aTypeWithOn, const nsAString& aEventType);
|
|
|
|
void ProcessControlMessageQueue();
|
|
void CancelPendingControlMessagesAndFlushPromises(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,
|
|
already_AddRefed<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;
|
|
|
|
// When a flush request is initiated, a promise is created and stored in
|
|
// mPendingFlushPromises until it is settled in the task delivering the flush
|
|
// result or Reset() is called before the promise is settled.
|
|
SimpleMap<int64_t, RefPtr<Promise>> mPendingFlushPromises;
|
|
|
|
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 sequence Id.
|
|
size_t mDecodeCounter;
|
|
// Tracking how many flush request has been enqueued and this number will be
|
|
// used as the FlushMessage's sequence 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;
|
|
RefPtr<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
|