mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
ef5511ef68
This patch makes MediaDataEncoder declare its refcounting as virtual. This will allow a future patch in this series to add subclasses that have multiple superclasses using refcounting. Differential Revision: https://phabricator.services.mozilla.com/D211650
217 lines
8.6 KiB
C++
217 lines
8.6 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/. */
|
|
|
|
#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_ */
|