PlatformEncoderModule.h (9328B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #if !defined(PlatformEncoderModule_h_) 8 # define PlatformEncoderModule_h_ 9 10 # include "EncoderConfig.h" 11 # include "MP4Decoder.h" 12 # include "MediaCodecsSupport.h" 13 # include "MediaResult.h" 14 # include "VPXDecoder.h" 15 # include "VideoUtils.h" 16 # include "mozilla/Maybe.h" 17 # include "mozilla/MozPromise.h" 18 # include "mozilla/RefPtr.h" 19 # include "mozilla/TaskQueue.h" 20 # include "mozilla/dom/ImageBitmapBinding.h" 21 # include "nsISupportsImpl.h" 22 23 namespace mozilla { 24 25 class MediaDataEncoder; 26 class MediaData; 27 class EncoderConfigurationChangeList; 28 29 class PlatformEncoderModule { 30 public: 31 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformEncoderModule) 32 33 virtual already_AddRefed<MediaDataEncoder> CreateVideoEncoder( 34 const EncoderConfig& aConfig, const RefPtr<TaskQueue>& aTaskQueue) const { 35 return nullptr; 36 }; 37 38 virtual already_AddRefed<MediaDataEncoder> CreateAudioEncoder( 39 const EncoderConfig& aConfig, const RefPtr<TaskQueue>& aTaskQueue) const { 40 return nullptr; 41 }; 42 43 using CreateEncoderPromise = MozPromise<RefPtr<MediaDataEncoder>, MediaResult, 44 /* IsExclusive = */ true>; 45 46 // Indicates if the PlatformDecoderModule supports encoding of a codec. 47 virtual media::EncodeSupportSet Supports( 48 const EncoderConfig& aConfig) const = 0; 49 virtual media::EncodeSupportSet SupportsCodec(CodecType aCodecType) const = 0; 50 51 // Returns a readable name for this Platform Encoder Module 52 virtual const char* GetName() const = 0; 53 54 // Asychronously create an encoder 55 virtual RefPtr<PlatformEncoderModule::CreateEncoderPromise> 56 AsyncCreateEncoder(const EncoderConfig& aEncoderConfig, 57 const RefPtr<TaskQueue>& aTaskQueue); 58 59 protected: 60 PlatformEncoderModule() = default; 61 virtual ~PlatformEncoderModule() = default; 62 }; 63 64 class MediaDataEncoder { 65 public: 66 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 67 68 using InitPromise = MozPromise<bool, MediaResult, /* IsExclusive = */ true>; 69 using EncodedData = nsTArray<RefPtr<MediaRawData>>; 70 using EncodePromise = 71 MozPromise<EncodedData, MediaResult, /* IsExclusive = */ true>; 72 using ReconfigurationPromise = 73 MozPromise<bool, MediaResult, /* IsExclusive = */ true>; 74 75 // Initialize the encoder. It should be ready to encode once the returned 76 // promise resolves. The encoder should do any initialization here, rather 77 // than in its constructor or PlatformEncoderModule::Create*Encoder(), 78 // so that if the client needs to shutdown during initialization, 79 // it can call Shutdown() to cancel this operation. Any initialization 80 // that requires blocking the calling thread in this function *must* 81 // be done here so that it can be canceled by calling Shutdown()! 82 virtual RefPtr<InitPromise> Init() = 0; 83 84 // Inserts a sample into the encoder's encode pipeline. The EncodePromise it 85 // returns will be resolved with already encoded MediaRawData at the moment, 86 // or empty when there is none available yet. 87 virtual RefPtr<EncodePromise> Encode(const MediaData* aSample) = 0; 88 89 // Inserts a batch of samples into the encoder's encode pipeline. The 90 // EncodePromise it returns will be resolved with already encoded MediaRawData 91 // at the moment, or empty when there is none available yet. 92 virtual RefPtr<EncodePromise> Encode(nsTArray<RefPtr<MediaData>>&& aSamples) { 93 MOZ_ASSERT_UNREACHABLE("Encode samples in a batch is not implemented"); 94 return EncodePromise::CreateAndReject( 95 MediaResult(NS_ERROR_NOT_IMPLEMENTED, 96 "Encode samples in a batch is not implemented"), 97 __func__); 98 } 99 100 // Attempt to reconfigure the encoder on the fly. This can fail if the 101 // underlying PEM doesn't support this type of reconfiguration. 102 virtual RefPtr<ReconfigurationPromise> Reconfigure( 103 const RefPtr<const EncoderConfigurationChangeList>& 104 aConfigurationChanges) = 0; 105 106 // Causes all complete samples in the pipeline that can be encoded to be 107 // output. It indicates that there is no more input sample to insert. 108 // This function is asynchronous. 109 // The MediaDataEncoder shall resolve the pending EncodePromise with drained 110 // samples. Drain will be called multiple times until the resolved 111 // EncodePromise is empty which indicates that there are no more samples to 112 // drain. 113 virtual RefPtr<EncodePromise> Drain() = 0; 114 115 // Cancels all init/encode/drain operations, and shuts down the encoder. The 116 // platform encoder should clean up any resources it's using and release 117 // memory etc. The shutdown promise will be resolved once the encoder has 118 // completed shutdown. The client will delete the decoder once the promise is 119 // resolved. 120 // The ShutdownPromise must only ever be resolved. 121 virtual RefPtr<ShutdownPromise> Shutdown() = 0; 122 123 virtual RefPtr<GenericPromise> SetBitrate(uint32_t aBitsPerSec) { 124 return GenericPromise::CreateAndResolve(true, __func__); 125 } 126 127 // Decoder needs to decide whether or not hardware acceleration is supported 128 // after creating. It doesn't need to call Init() before calling this 129 // function. 130 virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const { 131 return false; 132 } 133 134 // Return the name of the MediaDataEncoder, only used for encoding. 135 // May be accessed in a non thread-safe fashion. 136 virtual nsCString GetDescriptionName() const = 0; 137 138 friend class PlatformEncoderModule; 139 140 protected: 141 virtual ~MediaDataEncoder() = default; 142 }; 143 144 // Wrap a type to make it unique. This allows using ergonomically in the Variant 145 // below. Simply aliasing with `using` isn't enough, because typedefs in C++ 146 // don't produce strong types, so two integer variants result in 147 // the same type, making it ambiguous to the Variant code. 148 // T is the type to be wrapped. Phantom is a type that is only used to 149 // disambiguate and should be unique in the program. 150 template <typename T, typename Phantom> 151 class StrongTypedef { 152 public: 153 StrongTypedef() = default; 154 explicit StrongTypedef(T const& value) : mValue(value) {} 155 explicit StrongTypedef(T&& value) : mValue(std::move(value)) {} 156 T& get() { return mValue; } 157 T const& get() const { return mValue; } 158 159 private: 160 T mValue{}; 161 162 friend struct IPC::ParamTraits<StrongTypedef<T, Phantom>>; 163 }; 164 165 // Dimensions of the video frames 166 using DimensionsChange = 167 StrongTypedef<gfx::IntSize, struct DimensionsChangeType>; 168 // Expected display size of the encoded frames, can influence encoding 169 using DisplayDimensionsChange = 170 StrongTypedef<Maybe<gfx::IntSize>, struct DisplayDimensionsChangeType>; 171 // If present, the bitrate in kbps of the encoded stream. If absent, let the 172 // platform decide. 173 using BitrateChange = StrongTypedef<Maybe<uint32_t>, struct BitrateChangeType>; 174 // If present, the expected framerate of the output video stream. If absent, 175 // infer from the input frames timestamp. 176 using FramerateChange = 177 StrongTypedef<Maybe<double>, struct FramerateChangeType>; 178 // The bitrate mode (variable, constant) of the encoding 179 using BitrateModeChange = 180 StrongTypedef<BitrateMode, struct BitrateModeChangeType>; 181 // The usage for the encoded stream, this influence latency, ordering, etc. 182 using UsageChange = StrongTypedef<Usage, struct UsageChangeType>; 183 // If present, the expected content of the video frames (screen, movie, etc.). 184 // The value the string can have isn't decided just yet. When absent, the 185 // encoder uses generic settings. 186 using ContentHintChange = 187 StrongTypedef<Maybe<nsString>, struct ContentHintTypeType>; 188 // If present, the new sample-rate of the audio 189 using SampleRateChange = StrongTypedef<uint32_t, struct SampleRateChangeType>; 190 // If present, the new sample-rate of the audio 191 using NumberOfChannelsChange = 192 StrongTypedef<uint32_t, struct NumberOfChannelsChangeType>; 193 194 // A change to a parameter of an encoder instance. 195 using EncoderConfigurationItem = 196 Variant<DimensionsChange, DisplayDimensionsChange, BitrateModeChange, 197 BitrateChange, FramerateChange, UsageChange, ContentHintChange, 198 SampleRateChange, NumberOfChannelsChange>; 199 200 // A list of changes to an encoder configuration, that _might_ be able to change 201 // on the fly. Not all encoder modules can adjust their configuration on the 202 // fly. 203 class EncoderConfigurationChangeList { 204 public: 205 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(EncoderConfigurationChangeList) 206 bool Empty() const { return mChanges.IsEmpty(); } 207 template <typename T> 208 void Push(const T& aItem) { 209 mChanges.AppendElement(aItem); 210 } 211 nsString ToString() const; 212 213 nsTArray<EncoderConfigurationItem> mChanges; 214 215 private: 216 ~EncoderConfigurationChangeList() = default; 217 }; 218 219 // Just by inspecting the configuration and before asking the PEM, it's 220 // sometimes possible to know that a media won't be able to be encoded. For 221 // example, VP8 encodes the frame size on 14 bits, so a resolution of more than 222 // 16383x16383 pixels cannot work. 223 bool CanLikelyEncode(const EncoderConfig& aConfig); 224 225 } // namespace mozilla 226 227 #endif /* PlatformEncoderModule_h_ */