/* -*- 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 CreateVideoEncoder( const EncoderConfig& aConfig, const RefPtr& aTaskQueue) const { return nullptr; }; virtual already_AddRefed CreateAudioEncoder( const EncoderConfig& aConfig, const RefPtr& aTaskQueue) const { return nullptr; }; using CreateEncoderPromise = MozPromise, 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 AsyncCreateEncoder( const EncoderConfig& aEncoderConfig, const RefPtr& aTaskQueue); protected: PlatformEncoderModule() = default; virtual ~PlatformEncoderModule() = default; }; class MediaDataEncoder { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDataEncoder) 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; using EncodedData = nsTArray>; using EncodePromise = MozPromise; using ReconfigurationPromise = MozPromise; // 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 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 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 Reconfigure( const RefPtr& 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 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 Shutdown() = 0; virtual RefPtr 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 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; // Expected display size of the encoded frames, can influence encoding using DisplayDimensionsChange = StrongTypedef, struct DisplayDimensionsChangeType>; // If present, the bitrate in kbps of the encoded stream. If absent, let the // platform decide. using BitrateChange = StrongTypedef, struct BitrateChangeType>; // If present, the expected framerate of the output video stream. If absent, // infer from the input frames timestamp. using FramerateChange = StrongTypedef, struct FramerateChangeType>; // The bitrate mode (variable, constant) of the encoding using BitrateModeChange = StrongTypedef; // The usage for the encoded stream, this influence latency, ordering, etc. using UsageChange = StrongTypedef; // 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, struct ContentHintTypeType>; // If present, the new sample-rate of the audio using SampleRateChange = StrongTypedef; // If present, the new sample-rate of the audio using NumberOfChannelsChange = StrongTypedef; // A change to a parameter of an encoder instance. using EncoderConfigurationItem = Variant; // 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 void Push(const T& aItem) { mChanges.AppendElement(aItem); } nsString ToString() const; nsTArray 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_ */