/* -*- 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/. */
#if !
defined(PlatformEncoderModule_h_)
# define PlatformEncoderModule_h_
# include
"MP4Decoder.h"
# include
"MediaResult.h"
# include
"VPXDecoder.h"
# include
"mozilla/Maybe.h"
# include
"mozilla/MozPromise.h"
# include
"mozilla/RefPtr.h"
# include
"mozilla/TaskQueue.h"
# include
"mozilla/dom/ImageBitmapBinding.h"
# include
"nsISupportsImpl.h"
# include
"VideoUtils.h"
# include
"EncoderConfig.h"
namespace mozilla {
class MediaDataEncoder;
class MediaData;
struct EncoderConfigurationChangeList;
class PlatformEncoderModule {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformEncoderModule)
virtual already_AddRefed<MediaDataEncoder> CreateVideoEncoder(
const EncoderConfig& aConfig,
const RefPtr<TaskQueue>& aTaskQueue)
const {
return nullptr;
};
virtual already_AddRefed<MediaDataEncoder> CreateAudioEncoder(
const EncoderConfig& aConfig,
const RefPtr<TaskQueue>& aTaskQueue)
const {
return nullptr;
};
using CreateEncoderPromise = MozPromise<RefPtr<MediaDataEncoder>, MediaResult,
/* IsExclusive = */ true>;
// Indicates if the PlatformDecoderModule supports encoding of a codec.
virtual bool Supports(
const EncoderConfig& aConfig)
const = 0;
virtual bool SupportsCodec(CodecType aCodecType)
const = 0;
// Returns a readable name for this Platform Encoder Module
virtual const char* GetName()
const = 0;
// Asychronously create an encoder
RefPtr<PlatformEncoderModule::CreateEncoderPromise> AsyncCreateEncoder(
const EncoderConfig& aEncoderConfig,
const RefPtr<TaskQueue>& aTaskQueue);
protected:
PlatformEncoderModule() =
default;
virtual ~PlatformEncoderModule() =
default;
};
class MediaDataEncoder {
public:
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
static bool IsVideo(
const CodecType aCodec) {
return aCodec > CodecType::_BeginVideo_ && aCodec < CodecType::_EndVideo_;
}
static bool IsAudio(
const CodecType aCodec) {
return aCodec > CodecType::_BeginAudio_ && aCodec < CodecType::_EndAudio_;
}
using InitPromise = MozPromise<
bool, MediaResult,
/* IsExclusive = */ true>;
using EncodedData = nsTArray<RefPtr<MediaRawData>>;
using EncodePromise =
MozPromise<EncodedData, MediaResult,
/* IsExclusive = */ true>;
using ReconfigurationPromise =
MozPromise<
bool, MediaResult,
/* IsExclusive = */ true>;
// Initialize the encoder. It should be ready to encode once the returned
// promise resolves. The encoder should do any initialization here, rather
// than in its constructor or PlatformEncoderModule::Create*Encoder(),
// so that if the client needs to shutdown during initialization,
// it can call Shutdown() to cancel this operation. Any initialization
// that requires blocking the calling thread in this function *must*
// be done here so that it can be canceled by calling Shutdown()!
virtual RefPtr<InitPromise> Init() = 0;
// Inserts a sample into the encoder's encode pipeline. The EncodePromise it
// returns will be resolved with already encoded MediaRawData at the moment,
// or empty when there is none available yet.
virtual RefPtr<EncodePromise> Encode(
const MediaData* aSample) = 0;
// Attempt to reconfigure the encoder on the fly. This can fail if the
// underlying PEM doesn't support this type of reconfiguration.
virtual RefPtr<ReconfigurationPromise> Reconfigure(
const RefPtr<
const EncoderConfigurationChangeList>&
aConfigurationChanges) = 0;
// Causes all complete samples in the pipeline that can be encoded to be
// output. It indicates that there is no more input sample to insert.
// This function is asynchronous.
// The MediaDataEncoder shall resolve the pending EncodePromise with drained
// samples. Drain will be called multiple times until the resolved
// EncodePromise is empty which indicates that there are no more samples to
// drain.
virtual RefPtr<EncodePromise> Drain() = 0;
// Cancels all init/encode/drain operations, and shuts down the encoder. The
// platform encoder should clean up any resources it's using and release
// memory etc. The shutdown promise will be resolved once the encoder has
// completed shutdown. The client will delete the decoder once the promise is
// resolved.
// The ShutdownPromise must only ever be resolved.
virtual RefPtr<ShutdownPromise> Shutdown() = 0;
virtual RefPtr<GenericPromise> SetBitrate(uint32_t aBitsPerSec) {
return GenericPromise::CreateAndResolve(
true, __func__);
}
// Decoder needs to decide whether or not hardware acceleration is supported
// after creating. It doesn't need to call Init() before calling this
// function.
virtual bool IsHardwareAccelerated(nsACString& aFailureReason)
const {
return false;
}
// Return the name of the MediaDataEncoder, only used for encoding.
// May be accessed in a non thread-safe fashion.
virtual nsCString GetDescriptionName()
const = 0;
friend class PlatformEncoderModule;
protected:
virtual ~MediaDataEncoder() =
default;
};
// Wrap a type to make it unique. This allows using ergonomically in the Variant
// below. Simply aliasing with `using` isn't enough, because typedefs in C++
// don't produce strong types, so two integer variants result in
// the same type, making it ambiguous to the Variant code.
// T is the type to be wrapped. Phantom is a type that is only used to
// disambiguate and should be unique in the program.
template <
typename T,
typename Phantom>
class StrongTypedef {
public:
explicit StrongTypedef(T
const& value) : mValue(value) {}
explicit StrongTypedef(T&& value) : mValue(std::move(value)) {}
T& get() {
return mValue; }
T
const& get()
const {
return mValue; }
private:
T mValue;
};
// Dimensions of the video frames
using DimensionsChange =
StrongTypedef<gfx::IntSize,
struct DimensionsChangeType>;
// Expected display size of the encoded frames, can influence encoding
using DisplayDimensionsChange =
StrongTypedef<Maybe<gfx::IntSize>,
struct DisplayDimensionsChangeType>;
// If present, the bitrate in kbps of the encoded stream. If absent, let the
// platform decide.
using BitrateChange = StrongTypedef<Maybe<uint32_t>,
struct BitrateChangeType>;
// If present, the expected framerate of the output video stream. If absent,
// infer from the input frames timestamp.
using FramerateChange =
StrongTypedef<Maybe<
double>,
struct FramerateChangeType>;
// The bitrate mode (variable, constant) of the encoding
using BitrateModeChange =
StrongTypedef<BitrateMode,
struct BitrateModeChangeType>;
// The usage for the encoded stream, this influence latency, ordering, etc.
using UsageChange = StrongTypedef<Usage,
struct UsageChangeType>;
// If present, the expected content of the video frames (screen, movie, etc.).
// The value the string can have isn't decided just yet. When absent, the
// encoder uses generic settings.
using ContentHintChange =
StrongTypedef<Maybe<nsString>,
struct ContentHintTypeType>;
// If present, the new sample-rate of the audio
using SampleRateChange = StrongTypedef<uint32_t,
struct SampleRateChangeType>;
// If present, the new sample-rate of the audio
using NumberOfChannelsChange =
StrongTypedef<uint32_t,
struct NumberOfChannelsChangeType>;
// A change to a parameter of an encoder instance.
using EncoderConfigurationItem =
Variant<DimensionsChange, DisplayDimensionsChange, BitrateModeChange,
BitrateChange, FramerateChange, UsageChange, ContentHintChange,
SampleRateChange, NumberOfChannelsChange>;
// A list of changes to an encoder configuration, that _might_ be able to change
// on the fly. Not all encoder modules can adjust their configuration on the
// fly.
struct EncoderConfigurationChangeList {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(EncoderConfigurationChangeList)
bool Empty()
const {
return mChanges.IsEmpty(); }
template <
typename T>
void Push(
const T& aItem) {
mChanges.AppendElement(aItem);
}
nsString ToString()
const;
nsTArray<EncoderConfigurationItem> mChanges;
private:
~EncoderConfigurationChangeList() =
default;
};
// Just by inspecting the configuration and before asking the PEM, it's
// sometimes possible to know that a media won't be able to be encoded. For
// example, VP8 encodes the frame size on 14 bits, so a resolution of more than
// 16383x16383 pixels cannot work.
bool CanLikelyEncode(
const EncoderConfig& aConfig);
}
// namespace mozilla
#endif /* PlatformEncoderModule_h_ */