tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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