LCOV - code coverage report
Current view: top level - dom/media/platforms - PDMFactory.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 179 1.1 %
Date: 2017-07-14 16:53:18 Functions: 0 27 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 "PDMFactory.h"
       8             : 
       9             : #ifdef XP_WIN
      10             : #include "WMFDecoderModule.h"
      11             : #endif
      12             : #ifdef MOZ_FFVPX
      13             : #include "FFVPXRuntimeLinker.h"
      14             : #endif
      15             : #ifdef MOZ_FFMPEG
      16             : #include "FFmpegRuntimeLinker.h"
      17             : #endif
      18             : #ifdef MOZ_APPLEMEDIA
      19             : #include "AppleDecoderModule.h"
      20             : #endif
      21             : #ifdef MOZ_GONK_MEDIACODEC
      22             : #include "GonkDecoderModule.h"
      23             : #endif
      24             : #ifdef MOZ_WIDGET_ANDROID
      25             : #include "AndroidDecoderModule.h"
      26             : #endif
      27             : #include "GMPDecoderModule.h"
      28             : 
      29             : #include "mozilla/CDMProxy.h"
      30             : #include "mozilla/ClearOnShutdown.h"
      31             : #include "mozilla/SharedThreadPool.h"
      32             : #include "mozilla/StaticPtr.h"
      33             : #include "mozilla/SyncRunnable.h"
      34             : #include "mozilla/TaskQueue.h"
      35             : 
      36             : #include "MediaInfo.h"
      37             : #include "MediaPrefs.h"
      38             : #include "H264Converter.h"
      39             : 
      40             : #include "AgnosticDecoderModule.h"
      41             : #include "EMEDecoderModule.h"
      42             : 
      43             : #include "DecoderDoctorDiagnostics.h"
      44             : 
      45             : #include "MP4Decoder.h"
      46             : #include "mozilla/dom/RemoteVideoDecoder.h"
      47             : 
      48             : #include "mp4_demuxer/H264.h"
      49             : 
      50             : #include <functional>
      51             : 
      52             : namespace mozilla {
      53             : 
      54             : extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
      55             : extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
      56             : extern already_AddRefed<PlatformDecoderModule> CreateNullDecoderModule();
      57             : 
      58             : class PDMFactoryImpl final
      59             : {
      60             : public:
      61           0 :   PDMFactoryImpl()
      62             :   {
      63             : #ifdef XP_WIN
      64             :     WMFDecoderModule::Init();
      65             : #endif
      66             : #ifdef MOZ_APPLEMEDIA
      67             :     AppleDecoderModule::Init();
      68             : #endif
      69             : #ifdef MOZ_FFVPX
      70           0 :     FFVPXRuntimeLinker::Init();
      71             : #endif
      72             : #ifdef MOZ_FFMPEG
      73           0 :     FFmpegRuntimeLinker::Init();
      74             : #endif
      75           0 :   }
      76             : };
      77             : 
      78           3 : StaticAutoPtr<PDMFactoryImpl> PDMFactory::sInstance;
      79           3 : StaticMutex PDMFactory::sMonitor;
      80             : 
      81           0 : class SupportChecker
      82             : {
      83             : public:
      84             :   enum class Reason : uint8_t
      85             :   {
      86             :     kSupported,
      87             :     kVideoFormatNotSupported,
      88             :     kAudioFormatNotSupported,
      89             :     kUnknown,
      90             :   };
      91             : 
      92           0 :   struct CheckResult
      93             :   {
      94           0 :     explicit CheckResult(Reason aReason,
      95             :                          MediaResult aResult = MediaResult(NS_OK))
      96           0 :       : mReason(aReason),
      97           0 :         mMediaResult(mozilla::Move(aResult))
      98             :     {
      99           0 :     }
     100             :     CheckResult(const CheckResult& aOther) = default;
     101           0 :     CheckResult(CheckResult&& aOther) = default;
     102             :     CheckResult& operator=(const CheckResult& aOther) = default;
     103             :     CheckResult& operator=(CheckResult&& aOther) = default;
     104             : 
     105             :     Reason mReason;
     106             :     MediaResult mMediaResult;
     107             :   };
     108             : 
     109             :   template<class Func>
     110             :   void
     111           0 :   AddToCheckList(Func&& aChecker)
     112             :   {
     113           0 :     mCheckerList.AppendElement(mozilla::Forward<Func>(aChecker));
     114           0 :   }
     115             : 
     116             :   void
     117           0 :   AddMediaFormatChecker(const TrackInfo& aTrackConfig)
     118             :   {
     119           0 :     if (aTrackConfig.IsVideo()) {
     120           0 :       auto mimeType = aTrackConfig.GetAsVideoInfo()->mMimeType;
     121             :       RefPtr<MediaByteBuffer> extraData =
     122           0 :         aTrackConfig.GetAsVideoInfo()->mExtraData;
     123           0 :       AddToCheckList([mimeType, extraData]() {
     124           0 :         if (MP4Decoder::IsH264(mimeType)) {
     125           0 :           mp4_demuxer::SPSData spsdata;
     126             :           // WMF H.264 Video Decoder and Apple ATDecoder
     127             :           // do not support YUV444 format.
     128             :           // For consistency, all decoders should be checked.
     129           0 :           if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata)
     130           0 :               && (spsdata.profile_idc == 244 /* Hi444PP */
     131           0 :                   || spsdata.chroma_format_idc == PDMFactory::kYUV444)) {
     132             :             return CheckResult(
     133             :               SupportChecker::Reason::kVideoFormatNotSupported,
     134           0 :               MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
     135           0 :                           RESULT_DETAIL("Decoder may not have the capability "
     136             :                                         "to handle the requested video format "
     137           0 :                                         "with YUV444 chroma subsampling.")));
     138             :           }
     139             :         }
     140           0 :         return CheckResult(SupportChecker::Reason::kSupported);
     141           0 :       });
     142             :     }
     143           0 :   }
     144             : 
     145             :   SupportChecker::CheckResult
     146           0 :   Check()
     147             :   {
     148           0 :     for (auto& checker : mCheckerList) {
     149           0 :       auto result = checker();
     150           0 :         if (result.mReason != SupportChecker::Reason::kSupported) {
     151           0 :           return result;
     152             :       }
     153             :     }
     154           0 :     return CheckResult(SupportChecker::Reason::kSupported);
     155             :   }
     156             : 
     157             :   void Clear() { mCheckerList.Clear(); }
     158             : 
     159             : private:
     160             :   nsTArray<std::function<CheckResult()>> mCheckerList;
     161             : }; // SupportChecker
     162             : 
     163           0 : PDMFactory::PDMFactory()
     164             : {
     165           0 :   EnsureInit();
     166           0 :   CreatePDMs();
     167           0 :   CreateNullPDM();
     168           0 : }
     169             : 
     170           0 : PDMFactory::~PDMFactory()
     171             : {
     172           0 : }
     173             : 
     174             : void
     175           0 : PDMFactory::EnsureInit() const
     176             : {
     177             :   {
     178           0 :     StaticMutexAutoLock mon(sMonitor);
     179           0 :     if (sInstance) {
     180             :       // Quick exit if we already have an instance.
     181           0 :       return;
     182             :     }
     183           0 :     if (NS_IsMainThread()) {
     184             :       // On the main thread and holding the lock -> Create instance.
     185           0 :       sInstance = new PDMFactoryImpl();
     186           0 :       ClearOnShutdown(&sInstance);
     187           0 :       return;
     188             :     }
     189             :   }
     190             : 
     191             :   // Not on the main thread -> Sync-dispatch creation to main thread.
     192           0 :   nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadEventTarget();
     193             :   nsCOMPtr<nsIRunnable> runnable =
     194           0 :     NS_NewRunnableFunction("PDMFactory::EnsureInit", []() {
     195           0 :       StaticMutexAutoLock mon(sMonitor);
     196           0 :       if (!sInstance) {
     197           0 :         sInstance = new PDMFactoryImpl();
     198           0 :         ClearOnShutdown(&sInstance);
     199             :       }
     200           0 :     });
     201           0 :   SyncRunnable::DispatchToThread(mainTarget, runnable);
     202             : }
     203             : 
     204             : already_AddRefed<MediaDataDecoder>
     205           0 : PDMFactory::CreateDecoder(const CreateDecoderParams& aParams)
     206             : {
     207           0 :   if (aParams.mUseNullDecoder) {
     208           0 :     MOZ_ASSERT(mNullPDM);
     209           0 :     return CreateDecoderWithPDM(mNullPDM, aParams);
     210             :   }
     211             : 
     212           0 :   const TrackInfo& config = aParams.mConfig;
     213           0 :   bool isEncrypted = mEMEPDM && config.mCrypto.mValid;
     214             : 
     215           0 :   if (isEncrypted) {
     216           0 :     return CreateDecoderWithPDM(mEMEPDM, aParams);
     217             :   }
     218             : 
     219           0 :   DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
     220           0 :   if (diagnostics) {
     221             :     // If libraries failed to load, the following loop over mCurrentPDMs
     222             :     // will not even try to use them. So we record failures now.
     223           0 :     if (mWMFFailedToLoad) {
     224           0 :       diagnostics->SetWMFFailedToLoad();
     225             :     }
     226           0 :     if (mFFmpegFailedToLoad) {
     227           0 :       diagnostics->SetFFmpegFailedToLoad();
     228             :     }
     229           0 :     if (mGMPPDMFailedToStartup) {
     230           0 :       diagnostics->SetGMPPDMFailedToStartup();
     231             :     }
     232             :   }
     233             : 
     234           0 :   for (auto& current : mCurrentPDMs) {
     235           0 :     if (!current->SupportsMimeType(config.mMimeType, diagnostics)) {
     236           0 :       continue;
     237             :     }
     238           0 :     RefPtr<MediaDataDecoder> m = CreateDecoderWithPDM(current, aParams);
     239           0 :     if (m) {
     240           0 :       return m.forget();
     241             :     }
     242             :   }
     243           0 :   NS_WARNING("Unable to create a decoder, no platform found.");
     244           0 :   return nullptr;
     245             : }
     246             : 
     247             : already_AddRefed<MediaDataDecoder>
     248           0 : PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
     249             :                                  const CreateDecoderParams& aParams)
     250             : {
     251           0 :   MOZ_ASSERT(aPDM);
     252           0 :   RefPtr<MediaDataDecoder> m;
     253           0 :   MediaResult* result = aParams.mError;
     254             : 
     255           0 :   SupportChecker supportChecker;
     256           0 :   const TrackInfo& config = aParams.mConfig;
     257           0 :   supportChecker.AddMediaFormatChecker(config);
     258             : 
     259           0 :   auto checkResult = supportChecker.Check();
     260           0 :   if (checkResult.mReason != SupportChecker::Reason::kSupported) {
     261           0 :     DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics;
     262           0 :     if (checkResult.mReason
     263             :         == SupportChecker::Reason::kVideoFormatNotSupported) {
     264           0 :       if (diagnostics) {
     265           0 :         diagnostics->SetVideoNotSupported();
     266             :       }
     267           0 :       if (result) {
     268           0 :         *result = checkResult.mMediaResult;
     269             :       }
     270           0 :     } else if (checkResult.mReason
     271             :                == SupportChecker::Reason::kAudioFormatNotSupported) {
     272           0 :       if (diagnostics) {
     273           0 :         diagnostics->SetAudioNotSupported();
     274             :       }
     275           0 :       if (result) {
     276           0 :         *result = checkResult.mMediaResult;
     277             :       }
     278             :     }
     279           0 :     return nullptr;
     280             :   }
     281             : 
     282           0 :   if (config.IsAudio()) {
     283           0 :     m = aPDM->CreateAudioDecoder(aParams);
     284           0 :     return m.forget();
     285             :   }
     286             : 
     287           0 :   if (!config.IsVideo()) {
     288           0 :     *result = MediaResult(
     289             :       NS_ERROR_DOM_MEDIA_FATAL_ERR,
     290           0 :       RESULT_DETAIL("Decoder configuration error, expected audio or video."));
     291           0 :     return nullptr;
     292             :   }
     293             : 
     294           0 :   if (MP4Decoder::IsH264(config.mMimeType) && !aParams.mUseNullDecoder) {
     295           0 :     RefPtr<H264Converter> h = new H264Converter(aPDM, aParams);
     296           0 :     const nsresult rv = h->GetLastError();
     297           0 :     if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) {
     298             :       // The H264Converter either successfully created the wrapped decoder,
     299             :       // or there wasn't enough AVCC data to do so. Otherwise, there was some
     300             :       // problem, for example WMF DLLs were missing.
     301           0 :       m = h.forget();
     302             :     }
     303             :   } else {
     304           0 :     m = aPDM->CreateVideoDecoder(aParams);
     305             :   }
     306             : 
     307           0 :   return m.forget();
     308             : }
     309             : 
     310             : bool
     311           0 : PDMFactory::SupportsMimeType(const nsACString& aMimeType,
     312             :                              DecoderDoctorDiagnostics* aDiagnostics) const
     313             : {
     314           0 :   UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
     315           0 :   if (!trackInfo) {
     316           0 :     return false;
     317             :   }
     318           0 :   return Supports(*trackInfo, aDiagnostics);
     319             : }
     320             : 
     321             : bool
     322           0 : PDMFactory::Supports(const TrackInfo& aTrackInfo,
     323             :                      DecoderDoctorDiagnostics* aDiagnostics) const
     324             : {
     325           0 :   if (mEMEPDM) {
     326           0 :     return mEMEPDM->Supports(aTrackInfo, aDiagnostics);
     327             :   }
     328           0 :   RefPtr<PlatformDecoderModule> current = GetDecoder(aTrackInfo, aDiagnostics);
     329           0 :   return !!current;
     330             : }
     331             : 
     332             : void
     333           0 : PDMFactory::CreatePDMs()
     334             : {
     335           0 :   RefPtr<PlatformDecoderModule> m;
     336             : 
     337           0 :   if (MediaPrefs::PDMUseBlankDecoder()) {
     338           0 :     m = CreateBlankDecoderModule();
     339           0 :     StartupPDM(m);
     340             :     // The Blank PDM SupportsMimeType reports true for all codecs; the creation
     341             :     // of its decoder is infallible. As such it will be used for all media, we
     342             :     // can stop creating more PDM from this point.
     343           0 :     return;
     344             :   }
     345             : 
     346             : #ifdef XP_WIN
     347             :   if (MediaPrefs::PDMWMFEnabled()) {
     348             :     m = new WMFDecoderModule();
     349             :     RefPtr<PlatformDecoderModule> remote = new dom::RemoteDecoderModule(m);
     350             :     StartupPDM(remote);
     351             :     mWMFFailedToLoad = !StartupPDM(m);
     352             :   } else {
     353             :     mWMFFailedToLoad = MediaPrefs::DecoderDoctorWMFDisabledIsFailure();
     354             :   }
     355             : #endif
     356             : #ifdef MOZ_FFVPX
     357           0 :   if (MediaPrefs::PDMFFVPXEnabled()) {
     358           0 :     m = FFVPXRuntimeLinker::CreateDecoderModule();
     359           0 :     StartupPDM(m);
     360             :   }
     361             : #endif
     362             : #ifdef MOZ_FFMPEG
     363           0 :   if (MediaPrefs::PDMFFmpegEnabled()) {
     364           0 :     m = FFmpegRuntimeLinker::CreateDecoderModule();
     365           0 :     mFFmpegFailedToLoad = !StartupPDM(m);
     366             :   } else {
     367           0 :     mFFmpegFailedToLoad = false;
     368             :   }
     369             : #endif
     370             : #ifdef MOZ_APPLEMEDIA
     371             :   m = new AppleDecoderModule();
     372             :   StartupPDM(m);
     373             : #endif
     374             : #ifdef MOZ_GONK_MEDIACODEC
     375             :   if (MediaPrefs::PDMGonkDecoderEnabled()) {
     376             :     m = new GonkDecoderModule();
     377             :     StartupPDM(m);
     378             :   }
     379             : #endif
     380             : #ifdef MOZ_WIDGET_ANDROID
     381             :   if(MediaPrefs::PDMAndroidMediaCodecEnabled()){
     382             :     m = new AndroidDecoderModule();
     383             :     StartupPDM(m, MediaPrefs::PDMAndroidMediaCodecPreferred());
     384             :   }
     385             : #endif
     386             : 
     387           0 :   m = new AgnosticDecoderModule();
     388           0 :   StartupPDM(m);
     389             : 
     390           0 :   if (MediaPrefs::PDMGMPEnabled()) {
     391           0 :     m = new GMPDecoderModule();
     392           0 :     mGMPPDMFailedToStartup = !StartupPDM(m);
     393             :   } else {
     394           0 :     mGMPPDMFailedToStartup = false;
     395             :   }
     396             : }
     397             : 
     398             : void
     399           0 : PDMFactory::CreateNullPDM()
     400             : {
     401           0 :   mNullPDM = CreateNullDecoderModule();
     402           0 :   MOZ_ASSERT(mNullPDM && NS_SUCCEEDED(mNullPDM->Startup()));
     403           0 : }
     404             : 
     405             : bool
     406           0 : PDMFactory::StartupPDM(PlatformDecoderModule* aPDM, bool aInsertAtBeginning)
     407             : {
     408           0 :   if (aPDM && NS_SUCCEEDED(aPDM->Startup())) {
     409           0 :     if (aInsertAtBeginning) {
     410           0 :       mCurrentPDMs.InsertElementAt(0, aPDM);
     411             :     } else {
     412           0 :       mCurrentPDMs.AppendElement(aPDM);
     413             :     }
     414           0 :     return true;
     415             :   }
     416           0 :   return false;
     417             : }
     418             : 
     419             : already_AddRefed<PlatformDecoderModule>
     420           0 : PDMFactory::GetDecoder(const TrackInfo& aTrackInfo,
     421             :                        DecoderDoctorDiagnostics* aDiagnostics) const
     422             : {
     423           0 :   if (aDiagnostics) {
     424             :     // If libraries failed to load, the following loop over mCurrentPDMs
     425             :     // will not even try to use them. So we record failures now.
     426           0 :     if (mWMFFailedToLoad) {
     427           0 :       aDiagnostics->SetWMFFailedToLoad();
     428             :     }
     429           0 :     if (mFFmpegFailedToLoad) {
     430           0 :       aDiagnostics->SetFFmpegFailedToLoad();
     431             :     }
     432           0 :     if (mGMPPDMFailedToStartup) {
     433           0 :       aDiagnostics->SetGMPPDMFailedToStartup();
     434             :     }
     435             :   }
     436             : 
     437           0 :   RefPtr<PlatformDecoderModule> pdm;
     438           0 :   for (auto& current : mCurrentPDMs) {
     439           0 :     if (current->Supports(aTrackInfo, aDiagnostics)) {
     440           0 :       pdm = current;
     441           0 :       break;
     442             :     }
     443             :   }
     444           0 :   return pdm.forget();
     445             : }
     446             : 
     447             : void
     448           0 : PDMFactory::SetCDMProxy(CDMProxy* aProxy)
     449             : {
     450           0 :   MOZ_ASSERT(aProxy);
     451             : 
     452             : #ifdef MOZ_WIDGET_ANDROID
     453             :   if (IsWidevineKeySystem(aProxy->KeySystem())) {
     454             :     mEMEPDM = new AndroidDecoderModule(aProxy);
     455             :     return;
     456             :   }
     457             : #endif
     458           0 :   RefPtr<PDMFactory> m = new PDMFactory();
     459           0 :   mEMEPDM = new EMEDecoderModule(aProxy, m);
     460           0 : }
     461             : 
     462             : }  // namespace mozilla

Generated by: LCOV version 1.13