EMEDecoderModule.cpp (18679B)
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 #include "EMEDecoderModule.h" 8 9 #include <inttypes.h> 10 11 #include "Adts.h" 12 #include "BlankDecoderModule.h" 13 #include "ChromiumCDMVideoDecoder.h" 14 #include "DecryptThroughputLimit.h" 15 #include "GMPDecoderModule.h" 16 #include "GMPService.h" 17 #include "GMPVideoDecoder.h" 18 #include "MP4Decoder.h" 19 #include "MediaInfo.h" 20 #include "PDMFactory.h" 21 #include "mozilla/CDMProxy.h" 22 #include "mozilla/EMEUtils.h" 23 #include "mozilla/RemoteCDMChild.h" 24 #include "mozilla/StaticPrefs_media.h" 25 #include "mozilla/UniquePtr.h" 26 #include "nsClassHashtable.h" 27 #include "nsServiceManagerUtils.h" 28 29 namespace mozilla { 30 31 using DecryptPromiseRequestHolder = MozPromiseRequestHolder<DecryptPromise>; 32 33 DDLoggedTypeDeclNameAndBase(EMEDecryptor, MediaDataDecoder); 34 35 class ADTSSampleConverter { 36 public: 37 explicit ADTSSampleConverter(const AudioInfo& aInfo) 38 : mNumChannels(aInfo.mChannels) 39 // Note: we set profile to 2 if we encounter an extended profile (which 40 // set mProfile to 0 and then set mExtendedProfile) such as HE-AACv2 41 // (profile 5). These can then pass through conversion to ADTS and back. 42 // This is done as ADTS only has 2 bits for profile, and the transform 43 // subtracts one from the value. We check if the profile supplied is > 4 44 // for safety. 2 is used as a fallback value, though it seems the CDM 45 // doesn't care what is set. 46 , 47 mProfile(aInfo.mProfile < 1 || aInfo.mProfile > 4 ? 2 : aInfo.mProfile), 48 mFrequencyIndex(ADTS::GetFrequencyIndex(aInfo.mRate).unwrapOr(255)) { 49 EME_LOG("ADTSSampleConvertor(): aInfo.mProfile=%" PRIi8 50 " aInfo.mExtendedProfile=%" PRIi8, 51 aInfo.mProfile, aInfo.mExtendedProfile); 52 if (aInfo.mProfile < 1 || aInfo.mProfile > 4) { 53 EME_LOG( 54 "ADTSSampleConvertor(): Profile not in [1, 4]! Samples will " 55 "their profile set to 2!"); 56 } 57 } 58 bool Convert(MediaRawData* aSample) const { 59 return ADTS::ConvertSample(mNumChannels, mFrequencyIndex, mProfile, 60 aSample); 61 } 62 bool Revert(MediaRawData* aSample) const { 63 return ADTS::RevertSample(aSample); 64 } 65 66 private: 67 const uint32_t mNumChannels; 68 const uint8_t mProfile; 69 const uint8_t mFrequencyIndex{}; 70 }; 71 72 class EMEDecryptor final : public MediaDataDecoder, 73 public DecoderDoctorLifeLogger<EMEDecryptor> { 74 public: 75 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(EMEDecryptor, final); 76 77 EMEDecryptor(MediaDataDecoder* aDecoder, CDMProxy* aProxy, 78 TrackInfo::TrackType aType, 79 const std::function<MediaEventProducer<TrackInfo::TrackType>*()>& 80 aOnWaitingForKey, 81 UniquePtr<ADTSSampleConverter> aConverter = nullptr) 82 : mDecoder(aDecoder), 83 mProxy(aProxy), 84 mSamplesWaitingForKey( 85 new SamplesWaitingForKey(mProxy, aType, aOnWaitingForKey)), 86 mADTSSampleConverter(std::move(aConverter)), 87 mIsShutdown(false) { 88 DDLINKCHILD("decoder", mDecoder.get()); 89 } 90 91 RefPtr<InitPromise> Init() override { 92 MOZ_ASSERT(!mIsShutdown); 93 mThread = GetCurrentSerialEventTarget(); 94 uint32_t maxThroughputMs = StaticPrefs::media_eme_max_throughput_ms(); 95 EME_LOG("EME max-throughput-ms=%" PRIu32, maxThroughputMs); 96 mThroughputLimiter.emplace(mThread, maxThroughputMs); 97 98 return mDecoder->Init(); 99 } 100 101 RefPtr<DecodePromise> Decode(MediaRawData* aSample) override { 102 MOZ_ASSERT(mThread->IsOnCurrentThread()); 103 MOZ_RELEASE_ASSERT(mDecrypts.Count() == 0, 104 "Can only process one sample at a time"); 105 RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__); 106 107 RefPtr<EMEDecryptor> self = this; 108 mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample) 109 ->Then( 110 mThread, __func__, 111 [self](const RefPtr<MediaRawData>& aSample) { 112 self->mKeyRequest.Complete(); 113 self->ThrottleDecode(aSample); 114 }, 115 [self]() { self->mKeyRequest.Complete(); }) 116 ->Track(mKeyRequest); 117 return p; 118 } 119 120 void ThrottleDecode(MediaRawData* aSample) { 121 MOZ_ASSERT(mThread->IsOnCurrentThread()); 122 123 RefPtr<EMEDecryptor> self = this; 124 mThroughputLimiter->Throttle(aSample) 125 ->Then( 126 mThread, __func__, 127 [self](const RefPtr<MediaRawData>& aSample) { 128 self->mThrottleRequest.Complete(); 129 self->AttemptDecode(aSample); 130 }, 131 [self]() { self->mThrottleRequest.Complete(); }) 132 ->Track(mThrottleRequest); 133 } 134 135 void AttemptDecode(MediaRawData* aSample) { 136 MOZ_ASSERT(mThread->IsOnCurrentThread()); 137 if (mIsShutdown) { 138 NS_WARNING("EME encrypted sample arrived after shutdown"); 139 mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 140 return; 141 } 142 143 if (mADTSSampleConverter && !mADTSSampleConverter->Convert(aSample)) { 144 mDecodePromise.RejectIfExists( 145 MediaResult( 146 NS_ERROR_DOM_MEDIA_FATAL_ERR, 147 RESULT_DETAIL("Failed to convert encrypted AAC sample to ADTS")), 148 __func__); 149 return; 150 } 151 152 const auto& decrypt = mDecrypts.InsertOrUpdate( 153 aSample, MakeUnique<DecryptPromiseRequestHolder>()); 154 mProxy->Decrypt(aSample) 155 ->Then(mThread, __func__, this, &EMEDecryptor::Decrypted, 156 &EMEDecryptor::Decrypted) 157 ->Track(*decrypt); 158 } 159 160 void Decrypted(const DecryptResult& aDecrypted) { 161 MOZ_ASSERT(mThread->IsOnCurrentThread()); 162 MOZ_ASSERT(aDecrypted.mSample); 163 164 UniquePtr<DecryptPromiseRequestHolder> holder; 165 mDecrypts.Remove(aDecrypted.mSample, &holder); 166 if (holder) { 167 holder->Complete(); 168 } else { 169 // Decryption is not in the list of decrypt operations waiting 170 // for a result. It must have been flushed or drained. Ignore result. 171 return; 172 } 173 174 if (mADTSSampleConverter && 175 !mADTSSampleConverter->Revert(aDecrypted.mSample)) { 176 mDecodePromise.RejectIfExists( 177 MediaResult( 178 NS_ERROR_DOM_MEDIA_FATAL_ERR, 179 RESULT_DETAIL("Failed to revert decrypted ADTS sample to AAC")), 180 __func__); 181 return; 182 } 183 184 if (mIsShutdown) { 185 NS_WARNING("EME decrypted sample arrived after shutdown"); 186 return; 187 } 188 189 if (aDecrypted.mStatus == eme::NoKeyErr) { 190 // Key became unusable after we sent the sample to CDM to decrypt. 191 // Call Decode() again, so that the sample is enqueued for decryption 192 // if the key becomes usable again. 193 AttemptDecode(aDecrypted.mSample); 194 } else if (aDecrypted.mStatus != eme::Ok) { 195 mDecodePromise.RejectIfExists( 196 MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, 197 RESULT_DETAIL("decrypted.mStatus=%u", 198 uint32_t(aDecrypted.mStatus))), 199 __func__); 200 } else { 201 MOZ_ASSERT(!mIsShutdown); 202 // The sample is no longer encrypted, so clear its crypto metadata. 203 UniquePtr<MediaRawDataWriter> writer(aDecrypted.mSample->CreateWriter()); 204 writer->mCrypto = CryptoSample(); 205 RefPtr<EMEDecryptor> self = this; 206 mDecoder->Decode(aDecrypted.mSample) 207 ->Then(mThread, __func__, 208 [self](DecodePromise::ResolveOrRejectValue&& aValue) { 209 self->mDecodeRequest.Complete(); 210 self->mDecodePromise.ResolveOrReject(std::move(aValue), 211 __func__); 212 }) 213 ->Track(mDecodeRequest); 214 } 215 } 216 217 RefPtr<FlushPromise> Flush() override { 218 MOZ_ASSERT(mThread->IsOnCurrentThread()); 219 MOZ_ASSERT(!mIsShutdown); 220 mKeyRequest.DisconnectIfExists(); 221 mThrottleRequest.DisconnectIfExists(); 222 mDecodeRequest.DisconnectIfExists(); 223 mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 224 mThroughputLimiter->Flush(); 225 for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) { 226 auto* holder = iter.UserData(); 227 holder->DisconnectIfExists(); 228 iter.Remove(); 229 } 230 RefPtr<SamplesWaitingForKey> k = mSamplesWaitingForKey; 231 return mDecoder->Flush()->Then(mThread, __func__, [k]() { 232 k->Flush(); 233 return FlushPromise::CreateAndResolve(true, __func__); 234 }); 235 } 236 237 RefPtr<DecodePromise> Drain() override { 238 MOZ_ASSERT(mThread->IsOnCurrentThread()); 239 MOZ_ASSERT(!mIsShutdown); 240 MOZ_ASSERT(mDecodePromise.IsEmpty() && !mDecodeRequest.Exists(), 241 "Must wait for decoding to complete"); 242 for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) { 243 auto* holder = iter.UserData(); 244 holder->DisconnectIfExists(); 245 iter.Remove(); 246 } 247 return mDecoder->Drain(); 248 } 249 250 RefPtr<ShutdownPromise> Shutdown() override { 251 // mThread may not be set if Init hasn't been called first. 252 MOZ_ASSERT(!mThread || mThread->IsOnCurrentThread()); 253 MOZ_ASSERT(!mIsShutdown); 254 mIsShutdown = true; 255 mSamplesWaitingForKey->BreakCycles(); 256 mSamplesWaitingForKey = nullptr; 257 RefPtr<MediaDataDecoder> decoder = std::move(mDecoder); 258 mProxy = nullptr; 259 return decoder->Shutdown(); 260 } 261 262 nsCString GetProcessName() const override { 263 return mDecoder->GetProcessName(); 264 } 265 266 nsCString GetDescriptionName() const override { 267 return mDecoder->GetDescriptionName(); 268 } 269 270 nsCString GetCodecName() const override { return mDecoder->GetCodecName(); } 271 272 ConversionRequired NeedsConversion() const override { 273 return mDecoder->NeedsConversion(); 274 } 275 276 private: 277 ~EMEDecryptor() = default; 278 279 RefPtr<MediaDataDecoder> mDecoder; 280 nsCOMPtr<nsISerialEventTarget> mThread; 281 RefPtr<CDMProxy> mProxy; 282 nsClassHashtable<nsRefPtrHashKey<MediaRawData>, DecryptPromiseRequestHolder> 283 mDecrypts; 284 RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey; 285 MozPromiseRequestHolder<SamplesWaitingForKey::WaitForKeyPromise> mKeyRequest; 286 Maybe<DecryptThroughputLimit> mThroughputLimiter; 287 MozPromiseRequestHolder<DecryptThroughputLimit::ThrottlePromise> 288 mThrottleRequest; 289 MozPromiseHolder<DecodePromise> mDecodePromise; 290 MozPromiseHolder<DecodePromise> mDrainPromise; 291 MozPromiseHolder<FlushPromise> mFlushPromise; 292 MozPromiseRequestHolder<DecodePromise> mDecodeRequest; 293 UniquePtr<ADTSSampleConverter> mADTSSampleConverter; 294 bool mIsShutdown; 295 }; 296 297 EMEMediaDataDecoderProxy::EMEMediaDataDecoderProxy( 298 const CreateDecoderParams& aParams, 299 already_AddRefed<MediaDataDecoder> aProxyDecoder, 300 already_AddRefed<nsISerialEventTarget> aProxyThread, CDMProxy* aProxy) 301 : MediaDataDecoderProxy(std::move(aProxyDecoder), std::move(aProxyThread)), 302 mThread(GetCurrentSerialEventTarget()), 303 mSamplesWaitingForKey(new SamplesWaitingForKey( 304 aProxy, aParams.mType, aParams.mOnWaitingForKeyEvent)), 305 mProxy(aProxy) {} 306 307 EMEMediaDataDecoderProxy::EMEMediaDataDecoderProxy( 308 const CreateDecoderParams& aParams, 309 already_AddRefed<MediaDataDecoder> aProxyDecoder, CDMProxy* aProxy) 310 : MediaDataDecoderProxy(std::move(aProxyDecoder), 311 do_AddRef(GetCurrentSerialEventTarget())), 312 mThread(GetCurrentSerialEventTarget()), 313 mSamplesWaitingForKey(new SamplesWaitingForKey( 314 aProxy, aParams.mType, aParams.mOnWaitingForKeyEvent)), 315 mProxy(aProxy) {} 316 317 RefPtr<MediaDataDecoder::DecodePromise> EMEMediaDataDecoderProxy::Decode( 318 MediaRawData* aSample) { 319 RefPtr<EMEMediaDataDecoderProxy> self = this; 320 RefPtr<MediaRawData> sample = aSample; 321 return InvokeAsync(mThread, __func__, [self, this, sample]() { 322 RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__); 323 mSamplesWaitingForKey->WaitIfKeyNotUsable(sample) 324 ->Then( 325 mThread, __func__, 326 [self, this](const RefPtr<MediaRawData>& aSample) { 327 mKeyRequest.Complete(); 328 329 MediaDataDecoderProxy::Decode(aSample) 330 ->Then(mThread, __func__, 331 [self, 332 this](DecodePromise::ResolveOrRejectValue&& aValue) { 333 mDecodeRequest.Complete(); 334 mDecodePromise.ResolveOrReject(std::move(aValue), 335 __func__); 336 }) 337 ->Track(mDecodeRequest); 338 }, 339 [self]() { 340 self->mKeyRequest.Complete(); 341 MOZ_CRASH("Should never get here"); 342 }) 343 ->Track(mKeyRequest); 344 345 return p; 346 }); 347 } 348 349 RefPtr<MediaDataDecoder::FlushPromise> EMEMediaDataDecoderProxy::Flush() { 350 RefPtr<EMEMediaDataDecoderProxy> self = this; 351 return InvokeAsync(mThread, __func__, [self, this]() { 352 mKeyRequest.DisconnectIfExists(); 353 mDecodeRequest.DisconnectIfExists(); 354 mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); 355 return MediaDataDecoderProxy::Flush(); 356 }); 357 } 358 359 RefPtr<ShutdownPromise> EMEMediaDataDecoderProxy::Shutdown() { 360 RefPtr<EMEMediaDataDecoderProxy> self = this; 361 return InvokeAsync(mThread, __func__, [self, this]() { 362 mSamplesWaitingForKey->BreakCycles(); 363 mSamplesWaitingForKey = nullptr; 364 mProxy = nullptr; 365 return MediaDataDecoderProxy::Shutdown(); 366 }); 367 } 368 369 EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM) 370 : mProxy(aProxy), mPDM(aPDM) {} 371 372 EMEDecoderModule::~EMEDecoderModule() = default; 373 374 static already_AddRefed<MediaDataDecoderProxy> CreateDecoderWrapper( 375 CDMProxy* aProxy, const CreateDecoderParams& aParams) { 376 RefPtr<gmp::GeckoMediaPluginService> s( 377 gmp::GeckoMediaPluginService::GetGeckoMediaPluginService()); 378 if (!s) { 379 return nullptr; 380 } 381 nsCOMPtr<nsISerialEventTarget> thread(s->GetGMPThread()); 382 if (!thread) { 383 return nullptr; 384 } 385 RefPtr<MediaDataDecoderProxy> decoder( 386 new EMEMediaDataDecoderProxy(aParams, 387 do_AddRef(new ChromiumCDMVideoDecoder( 388 GMPVideoDecoderParams(aParams), aProxy)), 389 thread.forget(), aProxy)); 390 return decoder.forget(); 391 } 392 393 RefPtr<EMEDecoderModule::CreateDecoderPromise> 394 EMEDecoderModule::AsyncCreateDecoder(const CreateDecoderParams& aParams) { 395 MOZ_ASSERT(aParams.mConfig.mCrypto.IsEncrypted() || 396 aParams.mEncryptedCustomIdent == 397 CreateDecoderParams::EncryptedCustomIdent::True); 398 MOZ_ASSERT(mPDM); 399 400 // If the CDMProxy is a RemoteCDMChild actor, then we know that the CDM 401 // functionality will be exercised by the decoder in the remote process. 402 if (auto* cdm = static_cast<PRemoteCDMActor*>(mProxy->AsRemoteCDMChild())) { 403 return mPDM->CreateDecoder(CreateDecoderParams{aParams, cdm}); 404 } 405 406 if (aParams.mConfig.IsVideo()) { 407 if (StaticPrefs::media_eme_video_blank()) { 408 EME_LOG( 409 "EMEDecoderModule::CreateVideoDecoder() creating a blank decoder."); 410 RefPtr<PlatformDecoderModule> m(BlankDecoderModule::Create()); 411 RefPtr<MediaDataDecoder> decoder = m->CreateVideoDecoder(aParams); 412 return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve(decoder, 413 __func__); 414 } 415 416 if (!SupportsMimeType(aParams.mConfig.mMimeType, nullptr).isEmpty()) { 417 // GMP decodes. Assume that means it can decrypt too. 418 return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve( 419 CreateDecoderWrapper(mProxy, aParams), __func__); 420 } 421 422 RefPtr<EMEDecoderModule::CreateDecoderPromise> p = 423 mPDM->CreateDecoder(aParams)->Then( 424 GetCurrentSerialEventTarget(), __func__, 425 [self = RefPtr{this}, 426 params = CreateDecoderParamsForAsync(aParams)]( 427 RefPtr<MediaDataDecoder>&& aDecoder) { 428 RefPtr<MediaDataDecoder> emeDecoder( 429 new EMEDecryptor(aDecoder, self->mProxy, params.mType, 430 params.mOnWaitingForKeyEvent)); 431 return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve( 432 emeDecoder, __func__); 433 }, 434 [](const MediaResult& aError) { 435 return EMEDecoderModule::CreateDecoderPromise::CreateAndReject( 436 aError, __func__); 437 }); 438 return p; 439 } 440 441 MOZ_ASSERT(aParams.mConfig.IsAudio()); 442 443 // We don't support using the GMP to decode audio. 444 MOZ_ASSERT(SupportsMimeType(aParams.mConfig.mMimeType, nullptr).isEmpty()); 445 MOZ_ASSERT(mPDM); 446 447 if (StaticPrefs::media_eme_audio_blank()) { 448 EME_LOG("EMEDecoderModule::CreateAudioDecoder() creating a blank decoder."); 449 RefPtr<PlatformDecoderModule> m(BlankDecoderModule::Create()); 450 RefPtr<MediaDataDecoder> decoder = m->CreateAudioDecoder(aParams); 451 return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve(decoder, 452 __func__); 453 } 454 455 UniquePtr<ADTSSampleConverter> converter = nullptr; 456 if (MP4Decoder::IsAAC(aParams.mConfig.mMimeType)) { 457 // The CDM expects encrypted AAC to be in ADTS format. 458 // See bug 1433344. 459 converter = MakeUnique<ADTSSampleConverter>(aParams.AudioConfig()); 460 } 461 462 RefPtr<EMEDecoderModule::CreateDecoderPromise> p = 463 mPDM->CreateDecoder(aParams)->Then( 464 GetCurrentSerialEventTarget(), __func__, 465 [self = RefPtr{this}, params = CreateDecoderParamsForAsync(aParams), 466 converter = std::move(converter)]( 467 RefPtr<MediaDataDecoder>&& aDecoder) mutable { 468 RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor( 469 aDecoder, self->mProxy, params.mType, 470 params.mOnWaitingForKeyEvent, std::move(converter))); 471 return EMEDecoderModule::CreateDecoderPromise::CreateAndResolve( 472 emeDecoder, __func__); 473 }, 474 [](const MediaResult& aError) { 475 return EMEDecoderModule::CreateDecoderPromise::CreateAndReject( 476 aError, __func__); 477 }); 478 return p; 479 } 480 481 media::DecodeSupportSet EMEDecoderModule::SupportsMimeType( 482 const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const { 483 Maybe<nsCString> keySystem; 484 keySystem.emplace(NS_ConvertUTF16toUTF8(mProxy->KeySystem())); 485 return GMPDecoderModule::SupportsMimeType( 486 aMimeType, nsLiteralCString(CHROMIUM_CDM_API), keySystem); 487 } 488 489 } // namespace mozilla