LCOV - code coverage report
Current view: top level - dom/media/platforms/agnostic/eme - EMEDecoderModule.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 229 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 58 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "EMEVideoDecoder.h"
       9             : #include "GMPDecoderModule.h"
      10             : #include "GMPService.h"
      11             : #include "MP4Decoder.h"
      12             : #include "MediaInfo.h"
      13             : #include "MediaPrefs.h"
      14             : #include "PDMFactory.h"
      15             : #include "gmp-decryption.h"
      16             : #include "mozIGeckoMediaPluginService.h"
      17             : #include "mozilla/CDMProxy.h"
      18             : #include "mozilla/EMEUtils.h"
      19             : #include "mozilla/Unused.h"
      20             : #include "nsAutoPtr.h"
      21             : #include "nsClassHashtable.h"
      22             : #include "nsServiceManagerUtils.h"
      23             : #include "DecryptThroughputLimit.h"
      24             : 
      25             : namespace mozilla {
      26             : 
      27             : typedef MozPromiseRequestHolder<DecryptPromise> DecryptPromiseRequestHolder;
      28             : extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
      29             : 
      30           0 : class EMEDecryptor : public MediaDataDecoder
      31             : {
      32             : public:
      33           0 :   EMEDecryptor(MediaDataDecoder* aDecoder, CDMProxy* aProxy,
      34             :                TaskQueue* aDecodeTaskQueue, TrackInfo::TrackType aType,
      35             :                MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey)
      36           0 :     : mDecoder(aDecoder)
      37             :     , mTaskQueue(aDecodeTaskQueue)
      38             :     , mProxy(aProxy)
      39             :     , mSamplesWaitingForKey(
      40           0 :         new SamplesWaitingForKey(mProxy, aType, aOnWaitingForKey))
      41             :     , mThroughputLimiter(aDecodeTaskQueue)
      42           0 :     , mIsShutdown(false)
      43             :   {
      44           0 :   }
      45             : 
      46           0 :   RefPtr<InitPromise> Init() override
      47             :   {
      48           0 :     MOZ_ASSERT(!mIsShutdown);
      49           0 :     return mDecoder->Init();
      50             :   }
      51             : 
      52           0 :   RefPtr<DecodePromise> Decode(MediaRawData* aSample) override
      53             :   {
      54           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
      55           0 :     MOZ_RELEASE_ASSERT(mDecrypts.Count() == 0,
      56             :                        "Can only process one sample at a time");
      57           0 :     RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__);
      58             : 
      59           0 :     RefPtr<EMEDecryptor> self = this;
      60           0 :     mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)
      61           0 :       ->Then(mTaskQueue, __func__,
      62           0 :              [self, this](RefPtr<MediaRawData> aSample) {
      63           0 :                mKeyRequest.Complete();
      64           0 :                ThrottleDecode(aSample);
      65           0 :              },
      66           0 :              [self, this]() {
      67           0 :                mKeyRequest.Complete();
      68           0 :              })
      69           0 :       ->Track(mKeyRequest);
      70             : 
      71           0 :     return p;
      72             :   }
      73             : 
      74           0 :   void ThrottleDecode(MediaRawData* aSample)
      75             :   {
      76           0 :     RefPtr<EMEDecryptor> self = this;
      77           0 :     mThroughputLimiter.Throttle(aSample)
      78           0 :       ->Then(mTaskQueue, __func__,
      79           0 :              [self, this] (RefPtr<MediaRawData> aSample) {
      80           0 :                mThrottleRequest.Complete();
      81           0 :                AttemptDecode(aSample);
      82           0 :              },
      83           0 :              [self, this]() {
      84           0 :                 mThrottleRequest.Complete();
      85           0 :              })
      86           0 :       ->Track(mThrottleRequest);
      87           0 :   }
      88             : 
      89           0 :   void AttemptDecode(MediaRawData* aSample)
      90             :   {
      91           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
      92           0 :     if (mIsShutdown) {
      93           0 :       NS_WARNING("EME encrypted sample arrived after shutdown");
      94           0 :       mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
      95           0 :       return;
      96             :     }
      97             : 
      98           0 :     nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter());
      99           0 :     mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId,
     100           0 :                                   writer->mCrypto.mSessionIds);
     101             : 
     102           0 :     mDecrypts.Put(aSample, new DecryptPromiseRequestHolder());
     103           0 :     mProxy->Decrypt(aSample)
     104           0 :       ->Then(mTaskQueue, __func__, this,
     105             :             &EMEDecryptor::Decrypted,
     106           0 :             &EMEDecryptor::Decrypted)
     107           0 :       ->Track(*mDecrypts.Get(aSample));
     108             :   }
     109             : 
     110           0 :   void Decrypted(const DecryptResult& aDecrypted)
     111             :   {
     112           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     113           0 :     MOZ_ASSERT(aDecrypted.mSample);
     114             : 
     115           0 :     nsAutoPtr<DecryptPromiseRequestHolder> holder;
     116           0 :     mDecrypts.Remove(aDecrypted.mSample, &holder);
     117           0 :     if (holder) {
     118           0 :       holder->Complete();
     119             :     } else {
     120             :       // Decryption is not in the list of decrypt operations waiting
     121             :       // for a result. It must have been flushed or drained. Ignore result.
     122           0 :       return;
     123             :     }
     124             : 
     125           0 :     if (mIsShutdown) {
     126           0 :       NS_WARNING("EME decrypted sample arrived after shutdown");
     127           0 :       return;
     128             :     }
     129             : 
     130           0 :     if (aDecrypted.mStatus == eme::NoKeyErr) {
     131             :       // Key became unusable after we sent the sample to CDM to decrypt.
     132             :       // Call Decode() again, so that the sample is enqueued for decryption
     133             :       // if the key becomes usable again.
     134           0 :       AttemptDecode(aDecrypted.mSample);
     135           0 :     } else if (aDecrypted.mStatus != eme::Ok) {
     136           0 :       mDecodePromise.RejectIfExists(
     137           0 :         MediaResult(
     138             :           NS_ERROR_DOM_MEDIA_FATAL_ERR,
     139           0 :           RESULT_DETAIL("decrypted.mStatus=%u", uint32_t(aDecrypted.mStatus))),
     140           0 :         __func__);
     141             :     } else {
     142           0 :       MOZ_ASSERT(!mIsShutdown);
     143             :       // The sample is no longer encrypted, so clear its crypto metadata.
     144           0 :       UniquePtr<MediaRawDataWriter> writer(aDecrypted.mSample->CreateWriter());
     145           0 :       writer->mCrypto = CryptoSample();
     146           0 :       RefPtr<EMEDecryptor> self = this;
     147           0 :       mDecoder->Decode(aDecrypted.mSample)
     148           0 :         ->Then(mTaskQueue, __func__,
     149           0 :                [self, this](const DecodedData& aResults) {
     150           0 :                  mDecodeRequest.Complete();
     151           0 :                  mDecodePromise.ResolveIfExists(aResults, __func__);
     152           0 :                },
     153           0 :                [self, this](const MediaResult& aError) {
     154           0 :                  mDecodeRequest.Complete();
     155           0 :                  mDecodePromise.RejectIfExists(aError, __func__);
     156           0 :                })
     157           0 :         ->Track(mDecodeRequest);
     158             :     }
     159             :   }
     160             : 
     161           0 :   RefPtr<FlushPromise> Flush() override
     162             :   {
     163           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     164           0 :     MOZ_ASSERT(!mIsShutdown);
     165           0 :     mKeyRequest.DisconnectIfExists();
     166           0 :     mThrottleRequest.DisconnectIfExists();
     167           0 :     mDecodeRequest.DisconnectIfExists();
     168           0 :     mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
     169           0 :     mThroughputLimiter.Flush();
     170           0 :     for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) {
     171           0 :       nsAutoPtr<DecryptPromiseRequestHolder>& holder = iter.Data();
     172           0 :       holder->DisconnectIfExists();
     173           0 :       iter.Remove();
     174             :     }
     175           0 :     RefPtr<SamplesWaitingForKey> k = mSamplesWaitingForKey;
     176           0 :     return mDecoder->Flush()->Then(
     177             :       mTaskQueue, __func__,
     178           0 :       [k]() {
     179           0 :         k->Flush();
     180           0 :         return FlushPromise::CreateAndResolve(true, __func__);
     181           0 :       });
     182             :   }
     183             : 
     184           0 :   RefPtr<DecodePromise> Drain() override
     185             :   {
     186           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     187           0 :     MOZ_ASSERT(!mIsShutdown);
     188           0 :     MOZ_ASSERT(mDecodePromise.IsEmpty() && !mDecodeRequest.Exists(),
     189             :                "Must wait for decoding to complete");
     190           0 :     for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) {
     191           0 :       nsAutoPtr<DecryptPromiseRequestHolder>& holder = iter.Data();
     192           0 :       holder->DisconnectIfExists();
     193           0 :       iter.Remove();
     194             :     }
     195           0 :     return mDecoder->Drain();
     196             :   }
     197             : 
     198           0 :   RefPtr<ShutdownPromise> Shutdown() override
     199             :   {
     200           0 :     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
     201           0 :     MOZ_ASSERT(!mIsShutdown);
     202           0 :     mIsShutdown = true;
     203           0 :     mSamplesWaitingForKey = nullptr;
     204           0 :     RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
     205           0 :     mProxy = nullptr;
     206           0 :     return decoder->Shutdown();
     207             :   }
     208             : 
     209           0 :   const char* GetDescriptionName() const override
     210             :   {
     211           0 :     return mDecoder->GetDescriptionName();
     212             :   }
     213             : 
     214           0 :   ConversionRequired NeedsConversion() const override
     215             :   {
     216           0 :     return mDecoder->NeedsConversion();
     217             :   }
     218             : 
     219             : private:
     220             :   RefPtr<MediaDataDecoder> mDecoder;
     221             :   RefPtr<TaskQueue> mTaskQueue;
     222             :   RefPtr<CDMProxy> mProxy;
     223             :   nsClassHashtable<nsRefPtrHashKey<MediaRawData>, DecryptPromiseRequestHolder>
     224             :     mDecrypts;
     225             :   RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
     226             :   MozPromiseRequestHolder<SamplesWaitingForKey::WaitForKeyPromise> mKeyRequest;
     227             :   DecryptThroughputLimit mThroughputLimiter;
     228             :   MozPromiseRequestHolder<DecryptThroughputLimit::ThrottlePromise> mThrottleRequest;
     229             :   MozPromiseHolder<DecodePromise> mDecodePromise;
     230             :   MozPromiseHolder<DecodePromise> mDrainPromise;
     231             :   MozPromiseHolder<FlushPromise> mFlushPromise;
     232             :   MozPromiseRequestHolder<DecodePromise> mDecodeRequest;
     233             : 
     234             :   bool mIsShutdown;
     235             : };
     236             : 
     237           0 : EMEMediaDataDecoderProxy::EMEMediaDataDecoderProxy(
     238             :   already_AddRefed<AbstractThread> aProxyThread,
     239             :   CDMProxy* aProxy,
     240           0 :   const CreateDecoderParams& aParams)
     241           0 :   : MediaDataDecoderProxy(Move(aProxyThread))
     242           0 :   , mTaskQueue(AbstractThread::GetCurrent()->AsTaskQueue())
     243             :   , mSamplesWaitingForKey(
     244             :       new SamplesWaitingForKey(aProxy,
     245           0 :                                aParams.mType,
     246           0 :                                aParams.mOnWaitingForKeyEvent))
     247           0 :   , mProxy(aProxy)
     248             : {
     249           0 : }
     250             : 
     251           0 : EMEMediaDataDecoderProxy::EMEMediaDataDecoderProxy(
     252             :   const CreateDecoderParams& aParams,
     253             :   already_AddRefed<MediaDataDecoder> aProxyDecoder,
     254           0 :   CDMProxy* aProxy)
     255           0 :   : MediaDataDecoderProxy(Move(aProxyDecoder))
     256           0 :   , mTaskQueue(AbstractThread::GetCurrent()->AsTaskQueue())
     257             :   , mSamplesWaitingForKey(
     258             :       new SamplesWaitingForKey(aProxy,
     259           0 :                                aParams.mType,
     260           0 :                                aParams.mOnWaitingForKeyEvent))
     261           0 :   , mProxy(aProxy)
     262             : {
     263           0 : }
     264             : 
     265             : RefPtr<MediaDataDecoder::DecodePromise>
     266           0 : EMEMediaDataDecoderProxy::Decode(MediaRawData* aSample)
     267             : {
     268           0 :   RefPtr<DecodePromise> p = mDecodePromise.Ensure(__func__);
     269             : 
     270           0 :   RefPtr<EMEMediaDataDecoderProxy> self = this;
     271           0 :   mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)
     272           0 :     ->Then(mTaskQueue, __func__,
     273           0 :            [self, this](RefPtr<MediaRawData> aSample) {
     274           0 :              mKeyRequest.Complete();
     275             : 
     276           0 :              nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter());
     277           0 :              mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId,
     278           0 :                                            writer->mCrypto.mSessionIds);
     279           0 :              MediaDataDecoderProxy::Decode(aSample)
     280           0 :                ->Then(mTaskQueue, __func__,
     281           0 :                       [self, this](const DecodedData& aResults) {
     282           0 :                         mDecodeRequest.Complete();
     283           0 :                         mDecodePromise.Resolve(aResults, __func__);
     284           0 :                       },
     285           0 :                       [self, this](const MediaResult& aError) {
     286           0 :                         mDecodeRequest.Complete();
     287           0 :                         mDecodePromise.Reject(aError, __func__);
     288           0 :                       })
     289           0 :                ->Track(mDecodeRequest);
     290           0 :            },
     291           0 :            [self, this]() {
     292           0 :              mKeyRequest.Complete();
     293           0 :              MOZ_CRASH("Should never get here");
     294           0 :            })
     295           0 :     ->Track(mKeyRequest);
     296             : 
     297           0 :   return p;
     298             : }
     299             : 
     300             : RefPtr<MediaDataDecoder::FlushPromise>
     301           0 : EMEMediaDataDecoderProxy::Flush()
     302             : {
     303           0 :   mKeyRequest.DisconnectIfExists();
     304           0 :   mDecodeRequest.DisconnectIfExists();
     305           0 :   mDecodePromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
     306           0 :   return MediaDataDecoderProxy::Flush();
     307             : }
     308             : 
     309             : RefPtr<ShutdownPromise>
     310           0 : EMEMediaDataDecoderProxy::Shutdown()
     311             : {
     312           0 :   mSamplesWaitingForKey = nullptr;
     313           0 :   mProxy = nullptr;
     314           0 :   return MediaDataDecoderProxy::Shutdown();
     315             : }
     316             : 
     317           0 : EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM)
     318             :   : mProxy(aProxy)
     319           0 :   , mPDM(aPDM)
     320             : {
     321           0 : }
     322             : 
     323           0 : EMEDecoderModule::~EMEDecoderModule()
     324             : {
     325           0 : }
     326             : 
     327             : static already_AddRefed<MediaDataDecoderProxy>
     328           0 : CreateDecoderWrapper(CDMProxy* aProxy, const CreateDecoderParams& aParams)
     329             : {
     330             :   RefPtr<gmp::GeckoMediaPluginService> s(
     331           0 :     gmp::GeckoMediaPluginService::GetGeckoMediaPluginService());
     332           0 :   if (!s) {
     333           0 :     return nullptr;
     334             :   }
     335           0 :   RefPtr<AbstractThread> thread(s->GetAbstractGMPThread());
     336           0 :   if (!thread) {
     337           0 :     return nullptr;
     338             :   }
     339             :   RefPtr<MediaDataDecoderProxy> decoder(new EMEMediaDataDecoderProxy(
     340           0 :     thread.forget(), aProxy, aParams));
     341           0 :   return decoder.forget();
     342             : }
     343             : 
     344             : already_AddRefed<MediaDataDecoder>
     345           0 : EMEDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
     346             : {
     347           0 :   MOZ_ASSERT(aParams.mConfig.mCrypto.mValid);
     348             : 
     349           0 :   if (MediaPrefs::EMEBlankVideo()) {
     350           0 :     EME_LOG("EMEDecoderModule::CreateVideoDecoder() creating a blank decoder.");
     351           0 :     RefPtr<PlatformDecoderModule> m(CreateBlankDecoderModule());
     352           0 :     return m->CreateVideoDecoder(aParams);
     353             :   }
     354             : 
     355           0 :   if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) {
     356             :     // GMP decodes. Assume that means it can decrypt too.
     357             :     RefPtr<MediaDataDecoderProxy> wrapper =
     358           0 :       CreateDecoderWrapper(mProxy, aParams);
     359           0 :     auto params = GMPVideoDecoderParams(aParams);
     360           0 :     if (MediaPrefs::EMEChromiumAPIEnabled()) {
     361           0 :       wrapper->SetProxyTarget(new ChromiumCDMVideoDecoder(params, mProxy));
     362             :     } else {
     363           0 :       wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy, params));
     364             :     }
     365           0 :     return wrapper.forget();
     366             :   }
     367             : 
     368           0 :   MOZ_ASSERT(mPDM);
     369           0 :   RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams));
     370           0 :   if (!decoder) {
     371           0 :     return nullptr;
     372             :   }
     373             : 
     374             :   RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(
     375           0 :     decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue(),
     376           0 :     aParams.mType, aParams.mOnWaitingForKeyEvent));
     377           0 :   return emeDecoder.forget();
     378             : }
     379             : 
     380             : already_AddRefed<MediaDataDecoder>
     381           0 : EMEDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
     382             : {
     383           0 :   MOZ_ASSERT(aParams.mConfig.mCrypto.mValid);
     384             : 
     385             :   // We don't support using the GMP to decode audio.
     386           0 :   MOZ_ASSERT(!SupportsMimeType(aParams.mConfig.mMimeType, nullptr));
     387           0 :   MOZ_ASSERT(mPDM);
     388             : 
     389           0 :   if (MediaPrefs::EMEBlankAudio()) {
     390           0 :     EME_LOG("EMEDecoderModule::CreateAudioDecoder() creating a blank decoder.");
     391           0 :     RefPtr<PlatformDecoderModule> m(CreateBlankDecoderModule());
     392           0 :     return m->CreateAudioDecoder(aParams);
     393             :   }
     394             : 
     395           0 :   RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams));
     396           0 :   if (!decoder) {
     397           0 :     return nullptr;
     398             :   }
     399             : 
     400             :   RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(
     401           0 :     decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue(),
     402           0 :     aParams.mType, aParams.mOnWaitingForKeyEvent));
     403           0 :   return emeDecoder.forget();
     404             : }
     405             : 
     406             : bool
     407           0 : EMEDecoderModule::SupportsMimeType(const nsACString& aMimeType,
     408             :                                    DecoderDoctorDiagnostics* aDiagnostics) const
     409             : {
     410           0 :   Maybe<nsCString> gmp;
     411           0 :   gmp.emplace(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
     412           0 :   return GMPDecoderModule::SupportsMimeType(aMimeType, gmp);
     413             : }
     414             : 
     415             : } // namespace mozilla

Generated by: LCOV version 1.13