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 "MP4Decoder.h" 11 # include "MediaData.h" 12 # include "MediaInfo.h" 13 # include "MediaResult.h" 14 # include "mozilla/Attributes.h" 15 # include "mozilla/Maybe.h" 16 # include "mozilla/MozPromise.h" 17 # include "mozilla/RefPtr.h" 18 # include "mozilla/TaskQueue.h" 19 # include "mozilla/dom/ImageBitmapBinding.h" 20 # include "nsISupportsImpl.h" 21 # include "VPXDecoder.h" 22 23 namespace mozilla { 24 25 class MediaDataEncoder; 26 struct CreateEncoderParams; 27 28 class PlatformEncoderModule { 29 public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformEncoderModule)30 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformEncoderModule) 31 32 virtual already_AddRefed<MediaDataEncoder> CreateVideoEncoder( 33 const CreateEncoderParams& aParams) const { 34 return nullptr; 35 }; 36 CreateAudioEncoder(const CreateEncoderParams & aParams)37 virtual already_AddRefed<MediaDataEncoder> CreateAudioEncoder( 38 const CreateEncoderParams& aParams) const { 39 return nullptr; 40 }; 41 42 // Indicates if the PlatformDecoderModule supports encoding of aMimeType. 43 virtual bool SupportsMimeType(const nsACString& aMimeType) const = 0; 44 45 protected: 46 PlatformEncoderModule() = default; 47 virtual ~PlatformEncoderModule() = default; 48 }; 49 50 class MediaDataEncoder { 51 public: 52 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDataEncoder) 53 54 enum class Usage { 55 Realtime, // For WebRTC 56 Record // For MediaRecoder 57 }; 58 59 enum class CodecType { 60 _BeginVideo_, 61 H264, 62 VP8, 63 VP9, 64 _EndVideo_, 65 _BeginAudio_ = _EndVideo_, 66 Opus, 67 G722, 68 _EndAudio_, 69 Unknown, 70 }; 71 72 struct H264Specific final { 73 enum class ProfileLevel { BaselineAutoLevel, MainAutoLevel }; 74 75 const ProfileLevel mProfileLevel; 76 H264Specificfinal77 explicit H264Specific(const ProfileLevel aProfileLevel) 78 : mProfileLevel(aProfileLevel) {} 79 }; 80 81 struct OpusSpecific final { 82 enum class Application { Voip, Audio, RestricedLowDelay }; 83 84 const Application mApplication; 85 const uint8_t mComplexity; // from 0-10 86 OpusSpecificfinal87 OpusSpecific(const Application aApplication, const uint8_t aComplexity) 88 : mApplication(aApplication), mComplexity(aComplexity) { 89 MOZ_ASSERT(mComplexity <= 10); 90 } 91 }; 92 93 // From webrtc::VideoCodecVP8. mResilience is a boolean value because while 94 // VP8ResilienceMode has 3 values, kResilientFrames is not supported. 95 # define VPX_COMMON_SETTINGS \ 96 const Complexity mComplexity; \ 97 const bool mResilience; \ 98 const uint8_t mNumTemporalLayers; \ 99 const bool mDenoising; \ 100 const bool mAutoResize; \ 101 const bool mFrameDropping; 102 103 // See webrtc::VideoEncoder::GetDefaultVp(8|9)Settings(). 104 # define VPX_COMMON_DEFAULTS(resize) \ 105 mComplexity(Complexity::Normal), mResilience(true), mNumTemporalLayers(1), \ 106 mDenoising(true), mAutoResize(resize), mFrameDropping(0) 107 108 struct VPXSpecific final { 109 enum class Complexity { Normal, High, Higher, Max }; 110 struct VP8 final { 111 VPX_COMMON_SETTINGS 112 // Ignore webrtc::VideoCodecVP8::errorConcealmentOn, 113 // for it's always false in the codebase (except libwebrtc test cases). 114 VP8final::final115 VP8() : VPX_COMMON_DEFAULTS(false /* auto resize */) {} VP8final::final116 VP8(const Complexity aComplexity, const bool aResilience, 117 const uint8_t aNumTemporalLayers, const bool aDenoising, 118 const bool aAutoResize, const bool aFrameDropping) 119 : mComplexity(aComplexity), 120 mResilience(aResilience), 121 mNumTemporalLayers(aNumTemporalLayers), 122 mDenoising(aDenoising), 123 mAutoResize(aAutoResize), 124 mFrameDropping(aFrameDropping) {} 125 }; 126 127 struct VP9 final { 128 VPX_COMMON_SETTINGS 129 // From webrtc::VideoCodecVP9. 130 bool mAdaptiveQp; 131 uint8_t mNumSpatialLayers; 132 bool mFlexible; 133 VP9final::final134 VP9() 135 : VPX_COMMON_DEFAULTS(true /* auto resize */), 136 mAdaptiveQp(true), 137 mNumSpatialLayers(1), 138 mFlexible(false) {} VP9final::final139 VP9(const Complexity aComplexity, const bool aResilience, 140 const uint8_t aNumTemporalLayers, const bool aDenoising, 141 const bool aAutoResize, const bool aFrameDropping, 142 const bool aAdaptiveQp, const uint8_t aNumSpatialLayers, 143 const bool aFlexible) 144 : mComplexity(aComplexity), 145 mResilience(aResilience), 146 mNumTemporalLayers(aNumTemporalLayers), 147 mDenoising(aDenoising), 148 mAutoResize(aAutoResize), 149 mFrameDropping(aFrameDropping), 150 mAdaptiveQp(aAdaptiveQp), 151 mNumSpatialLayers(aNumSpatialLayers), 152 mFlexible(aFlexible) {} 153 }; 154 155 VPXSpecific() = delete; 156 }; 157 IsVideo(const CodecType aCodec)158 static bool IsVideo(const CodecType aCodec) { 159 return aCodec > CodecType::_BeginVideo_ && aCodec < CodecType::_EndVideo_; 160 } IsAudio(const CodecType aCodec)161 static bool IsAudio(const CodecType aCodec) { 162 return aCodec > CodecType::_BeginAudio_ && aCodec < CodecType::_EndAudio_; 163 } 164 165 using PixelFormat = dom::ImageBitmapFormat; 166 // Sample rate for audio, framerate for video, and bitrate for both. 167 using Rate = uint32_t; 168 169 using InitPromise = 170 MozPromise<TrackInfo::TrackType, MediaResult, /* IsExclusive = */ true>; 171 using EncodedData = nsTArray<RefPtr<MediaRawData>>; 172 using EncodePromise = 173 MozPromise<EncodedData, MediaResult, /* IsExclusive = */ true>; 174 175 // Initialize the encoder. It should be ready to encode once the returned 176 // promise resolves. The encoder should do any initialization here, rather 177 // than in its constructor or PlatformEncoderModule::Create*Encoder(), 178 // so that if the client needs to shutdown during initialization, 179 // it can call Shutdown() to cancel this operation. Any initialization 180 // that requires blocking the calling thread in this function *must* 181 // be done here so that it can be canceled by calling Shutdown()! 182 virtual RefPtr<InitPromise> Init() = 0; 183 184 // Inserts a sample into the encoder's encode pipeline. The EncodePromise it 185 // returns will be resolved with already encoded MediaRawData at the moment, 186 // or empty when there is none available yet. 187 virtual RefPtr<EncodePromise> Encode(const MediaData* aSample) = 0; 188 189 // Causes all complete samples in the pipeline that can be encoded to be 190 // output. It indicates that there is no more input sample to insert. 191 // This function is asynchronous. 192 // The MediaDataEncoder shall resolve the pending EncodePromise with drained 193 // samples. Drain will be called multiple times until the resolved 194 // EncodePromise is empty which indicates that there are no more samples to 195 // drain. 196 virtual RefPtr<EncodePromise> Drain() = 0; 197 198 // Cancels all init/encode/drain operations, and shuts down the encoder. The 199 // platform encoder should clean up any resources it's using and release 200 // memory etc. The shutdown promise will be resolved once the encoder has 201 // completed shutdown. The client will delete the decoder once the promise is 202 // resolved. 203 // The ShutdownPromise must only ever be resolved. 204 virtual RefPtr<ShutdownPromise> Shutdown() = 0; 205 SetBitrate(Rate aBitsPerSec)206 virtual RefPtr<GenericPromise> SetBitrate(Rate aBitsPerSec) { 207 return GenericPromise::CreateAndResolve(true, __func__); 208 } 209 210 // Decoder needs to decide whether or not hardware acceleration is supported 211 // after creating. It doesn't need to call Init() before calling this 212 // function. IsHardwareAccelerated(nsACString & aFailureReason)213 virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const { 214 return false; 215 } 216 217 // Return the name of the MediaDataEncoder, only used for encoding. 218 // May be accessed in a non thread-safe fashion. 219 virtual nsCString GetDescriptionName() const = 0; 220 221 friend class PlatformEncoderModule; 222 223 protected: 224 template <typename T> 225 struct BaseConfig { 226 const CodecType mCodecType; 227 const Usage mUsage; 228 const Rate mBitsPerSec; 229 Maybe<T> mCodecSpecific; 230 SetCodecSpecificBaseConfig231 void SetCodecSpecific(const T& aCodecSpecific) { 232 mCodecSpecific.emplace(aCodecSpecific); 233 } 234 235 protected: BaseConfigBaseConfig236 BaseConfig(const CodecType aCodecType, const Usage aUsage, 237 const Rate aBitsPerSec) 238 : mCodecType(aCodecType), mUsage(aUsage), mBitsPerSec(aBitsPerSec) {} 239 240 virtual ~BaseConfig() = default; 241 }; 242 243 template <typename T> 244 struct VideoConfig final : public BaseConfig<T> { 245 const gfx::IntSize mSize; 246 const PixelFormat mSourcePixelFormat; 247 const uint8_t mFramerate; 248 const size_t mKeyframeInterval; 249 VideoConfigfinal250 VideoConfig(const CodecType aCodecType, const Usage aUsage, 251 const gfx::IntSize& aSize, const PixelFormat aSourcePixelFormat, 252 const uint8_t aFramerate, const size_t aKeyframeInterval, 253 const Rate aBitrate) 254 : BaseConfig<T>(aCodecType, aUsage, aBitrate), 255 mSize(aSize), 256 mSourcePixelFormat(aSourcePixelFormat), 257 mFramerate(aFramerate), 258 mKeyframeInterval(aKeyframeInterval) {} 259 }; 260 261 template <typename T> 262 struct AudioConfig final : public BaseConfig<T> { 263 const uint8_t mNumChannels; 264 const Rate mSampleRate; 265 AudioConfigfinal266 AudioConfig(const CodecType aCodecType, const Usage aUsage, 267 const Rate aBitrate, const Rate aSampleRate, 268 const uint8_t aNumChannels) 269 : BaseConfig<T>(aCodecType, aUsage, aBitrate), 270 mNumChannels(aNumChannels), 271 mSampleRate(aSampleRate) {} 272 }; 273 274 virtual ~MediaDataEncoder() = default; 275 276 public: 277 using H264Config = VideoConfig<H264Specific>; 278 using VP8Config = VideoConfig<VPXSpecific::VP8>; 279 using VP9Config = VideoConfig<VPXSpecific::VP9>; 280 }; 281 282 struct MOZ_STACK_CLASS CreateEncoderParams final { 283 union CodecSpecific { 284 MediaDataEncoder::H264Specific mH264; 285 MediaDataEncoder::OpusSpecific mOpus; 286 MediaDataEncoder::VPXSpecific::VP8 mVP8; 287 MediaDataEncoder::VPXSpecific::VP9 mVP9; 288 CodecSpecific(const MediaDataEncoder::H264Specific && aH264)289 explicit CodecSpecific(const MediaDataEncoder::H264Specific&& aH264) 290 : mH264(aH264) {} CodecSpecific(const MediaDataEncoder::OpusSpecific && aOpus)291 explicit CodecSpecific(const MediaDataEncoder::OpusSpecific&& aOpus) 292 : mOpus(aOpus) {} CodecSpecific(const MediaDataEncoder::VPXSpecific::VP8 && aVP8)293 explicit CodecSpecific(const MediaDataEncoder::VPXSpecific::VP8&& aVP8) 294 : mVP8(aVP8) {} CodecSpecific(const MediaDataEncoder::VPXSpecific::VP9 && aVP9)295 explicit CodecSpecific(const MediaDataEncoder::VPXSpecific::VP9&& aVP9) 296 : mVP9(aVP9) {} 297 }; 298 CreateEncoderParamsfinal299 CreateEncoderParams(const TrackInfo& aConfig, 300 const MediaDataEncoder::Usage aUsage, 301 const RefPtr<TaskQueue> aTaskQueue, 302 const MediaDataEncoder::PixelFormat aPixelFormat, 303 const uint8_t aFramerate, const size_t aKeyframeInterval, 304 const MediaDataEncoder::Rate aBitrate) 305 : mConfig(aConfig), 306 mUsage(aUsage), 307 mTaskQueue(aTaskQueue), 308 mPixelFormat(aPixelFormat), 309 mFramerate(aFramerate), 310 mKeyframeInterval(aKeyframeInterval), 311 mBitrate(aBitrate) { 312 MOZ_ASSERT(mTaskQueue); 313 } 314 315 template <typename... Ts> CreateEncoderParamsfinal316 CreateEncoderParams(const TrackInfo& aConfig, 317 const MediaDataEncoder::Usage aUsage, 318 const RefPtr<TaskQueue> aTaskQueue, 319 const MediaDataEncoder::PixelFormat aPixelFormat, 320 const uint8_t aFramerate, const size_t aKeyframeInterval, 321 const MediaDataEncoder::Rate aBitrate, 322 const Ts&&... aCodecSpecific) 323 : mConfig(aConfig), 324 mUsage(aUsage), 325 mTaskQueue(aTaskQueue), 326 mPixelFormat(aPixelFormat), 327 mFramerate(aFramerate), 328 mKeyframeInterval(aKeyframeInterval), 329 mBitrate(aBitrate) { 330 MOZ_ASSERT(mTaskQueue); 331 SetCodecSpecific(std::forward<const Ts>(aCodecSpecific)...); 332 } 333 334 template <typename T> SetCodecSpecificfinal335 void SetCodecSpecific(const T&& aCodecSpecific) { 336 mCodecSpecific.emplace(std::forward<const T>(aCodecSpecific)); 337 } 338 ToH264Configfinal339 const MediaDataEncoder::H264Config ToH264Config() const { 340 const VideoInfo* info = mConfig.GetAsVideoInfo(); 341 MOZ_ASSERT(info); 342 343 auto config = MediaDataEncoder::H264Config( 344 MediaDataEncoder::CodecType::H264, mUsage, info->mImage, mPixelFormat, 345 mFramerate, mKeyframeInterval, mBitrate); 346 if (mCodecSpecific) { 347 config.SetCodecSpecific(mCodecSpecific.ref().mH264); 348 } 349 350 return config; 351 } 352 ToVP8Configfinal353 const MediaDataEncoder::VP8Config ToVP8Config() const { 354 const VideoInfo* info = mConfig.GetAsVideoInfo(); 355 MOZ_ASSERT(info); 356 357 auto config = MediaDataEncoder::VP8Config( 358 CodecTypeForMime(info->mMimeType), mUsage, info->mImage, mPixelFormat, 359 mFramerate, mKeyframeInterval, mBitrate); 360 if (mCodecSpecific) { 361 config.SetCodecSpecific(mCodecSpecific.ref().mVP8); 362 } 363 return config; 364 } 365 ToVP9Configfinal366 const MediaDataEncoder::VP9Config ToVP9Config() const { 367 const VideoInfo* info = mConfig.GetAsVideoInfo(); 368 MOZ_ASSERT(info); 369 370 auto config = MediaDataEncoder::VP9Config( 371 CodecTypeForMime(info->mMimeType), mUsage, info->mImage, mPixelFormat, 372 mFramerate, mKeyframeInterval, mBitrate); 373 if (mCodecSpecific) { 374 config.SetCodecSpecific(mCodecSpecific.ref().mVP9); 375 } 376 return config; 377 } 378 CodecTypeForMimefinal379 static MediaDataEncoder::CodecType CodecTypeForMime( 380 const nsACString& aMimeType) { 381 if (MP4Decoder::IsH264(aMimeType)) { 382 return MediaDataEncoder::CodecType::H264; 383 } else if (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8)) { 384 return MediaDataEncoder::CodecType::VP8; 385 } else if (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP9)) { 386 return MediaDataEncoder::CodecType::VP9; 387 } else { 388 MOZ_ASSERT_UNREACHABLE("Unsupported Mimetype"); 389 return MediaDataEncoder::CodecType::Unknown; 390 } 391 } 392 393 const TrackInfo& mConfig; 394 const MediaDataEncoder::Usage mUsage; 395 const RefPtr<TaskQueue> mTaskQueue; 396 const MediaDataEncoder::PixelFormat mPixelFormat; 397 const uint8_t mFramerate; 398 const size_t mKeyframeInterval; 399 const MediaDataEncoder::Rate mBitrate; 400 Maybe<CodecSpecific> mCodecSpecific; 401 402 private: 403 }; 404 405 } // namespace mozilla 406 407 #endif /* PlatformEncoderModule_h_ */ 408