Bug 1174055 - Load WMF DLLs in MFStartup(), never unload them. r=jya
authorChris Pearce <cpearce@mozilla.com>
Tue, 16 Jun 2015 14:28:01 +1200
changeset 267114 cd221759e418c93f6470ac6ef15501f5af3eacc2
parent 267113 7210dfe7ad781fd39aedea2e78be669c76532c33
child 267115 52813555f5004529f39bbed78ad1940af6632191
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-esr52@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1174055
milestone41.0a1
Bug 1174055 - Load WMF DLLs in MFStartup(), never unload them. r=jya
dom/media/platforms/wmf/WMFDecoderModule.cpp
dom/media/platforms/wmf/WMFDecoderModule.h
dom/media/wmf/WMF.h
dom/media/wmf/WMFDecoder.cpp
dom/media/wmf/WMFUtils.cpp
layout/build/nsLayoutStatics.cpp
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -1,72 +1,70 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WMF.h"
 #include "WMFDecoderModule.h"
-#include "WMFDecoder.h"
 #include "WMFVideoMFTManager.h"
 #include "WMFAudioMFTManager.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/DebugOnly.h"
 #include "WMFMediaDataDecoder.h"
 #include "nsIWindowsRegKey.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIGfxInfo.h"
 #include "GfxDriverInfo.h"
 #include "gfxWindowsPlatform.h"
 #include "MediaInfo.h"
 
 namespace mozilla {
 
-bool WMFDecoderModule::sIsWMFEnabled = false;
-bool WMFDecoderModule::sDXVAEnabled = false;
+static bool sIsWMFEnabled = false;
+static bool sDXVAEnabled = false;
 
 WMFDecoderModule::WMFDecoderModule()
+  : mWMFInitialized(false)
 {
 }
 
 WMFDecoderModule::~WMFDecoderModule()
 {
-  DebugOnly<HRESULT> hr = wmf::MFShutdown();
-  NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
+  if (mWMFInitialized) {
+    DebugOnly<HRESULT> hr = wmf::MFShutdown();
+    NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
+  }
+}
+
+void
+WMFDecoderModule::DisableHardwareAcceleration()
+{
+  sDXVAEnabled = false;
 }
 
 /* static */
 void
 WMFDecoderModule::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   sIsWMFEnabled = Preferences::GetBool("media.windows-media-foundation.enabled", false);
-  if (!sIsWMFEnabled) {
-    return;
-  }
-  if (NS_FAILED(WMFDecoder::LoadDLLs())) {
-    sIsWMFEnabled = false;
-  }
   sDXVAEnabled = !gfxWindowsPlatform::GetPlatform()->IsWARP() &&
                  gfxPlatform::CanUseHardwareVideoDecoding();
 }
 
 nsresult
 WMFDecoderModule::Startup()
 {
-  if (!sIsWMFEnabled) {
-    return NS_ERROR_FAILURE;
+  if (sIsWMFEnabled) {
+    mWMFInitialized = SUCCEEDED(wmf::MFStartup());
   }
-  if (FAILED(wmf::MFStartup())) {
-    NS_WARNING("Failed to initialize Windows Media Foundation");
-    return NS_ERROR_FAILURE;
-  }
-  return NS_OK;
+  return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
 }
 
 already_AddRefed<MediaDataDecoder>
 WMFDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig,
                                      layers::LayersBackend aLayersBackend,
                                      layers::ImageContainer* aImageContainer,
                                      FlushableMediaTaskQueue* aVideoTaskQueue,
                                      MediaDataDecoderCallback* aCallback)
--- a/dom/media/platforms/wmf/WMFDecoderModule.h
+++ b/dom/media/platforms/wmf/WMFDecoderModule.h
@@ -28,37 +28,31 @@ public:
 
   virtual already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const AudioInfo& aConfig,
                      FlushableMediaTaskQueue* aAudioTaskQueue,
                      MediaDataDecoderCallback* aCallback) override;
 
   bool SupportsMimeType(const nsACString& aMimeType) override;
 
-  virtual void DisableHardwareAcceleration() override
-  {
-    sDXVAEnabled = false;
-  }
-
+  virtual void DisableHardwareAcceleration() override;
   virtual bool SupportsSharedDecoders(const VideoInfo& aConfig) const override;
 
   virtual ConversionRequired
   DecoderNeedsConversion(const TrackInfo& aConfig) const override;
 
   // Accessors that report whether we have the required MFTs available
   // on the system to play various codecs. Windows Vista doesn't have the
   // H.264/AAC decoders if the "Platform Update Supplement for Windows Vista"
   // is not installed.
   static bool HasAAC();
   static bool HasH264();
 
   // Called on main thread.
   static void Init();
 private:
   bool ShouldUseDXVA(const VideoInfo& aConfig) const;
-
-  static bool sIsWMFEnabled;
-  static bool sDXVAEnabled;
+  bool mWMFInitialized;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/wmf/WMF.h
+++ b/dom/media/wmf/WMF.h
@@ -48,31 +48,28 @@ which makes Windows Media Foundation una
 #ifndef CLSID_CMSAACDecMFT
 extern "C" const CLSID CLSID_CMSAACDecMFT;
 #define WMF_MUST_DEFINE_AAC_MFT_CLSID
 #endif
 
 namespace mozilla {
 namespace wmf {
 
-// Loads/Unloads all the DLLs in which the WMF functions are located.
-// The DLLs must be loaded before any of the WMF functions below will work.
-// All the function definitions below are wrappers which locate the
-// corresponding WMF function in the appropriate DLL (hence why LoadDLL()
-// must be called first...).
-HRESULT LoadDLLs();
-HRESULT UnloadDLLs();
+// If successful, loads all required WMF DLLs and calls the WMF MFStartup()
+// function.
+HRESULT MFStartup();
+
+// Calls the WMF MFShutdown() function. Call this once for every time
+// wmf::MFStartup() succeeds. Note: does not unload the WMF DLLs loaded by
+// MFStartup(); leaves them in memory to save I/O at next MFStartup() call.
+HRESULT MFShutdown();
 
 // All functions below are wrappers around the corresponding WMF function,
 // and automatically locate and call the corresponding function in the WMF DLLs.
 
-HRESULT MFStartup();
-
-HRESULT MFShutdown();
-
 HRESULT MFCreateAsyncResult(IUnknown *aUunkObject,
                             IMFAsyncCallback *aCallback,
                             IUnknown *aUnkState,
                             IMFAsyncResult **aOutAsyncResult);
 
 HRESULT MFInvokeCallback(IMFAsyncResult *aAsyncResult);
 
 HRESULT MFCreateMediaType(IMFMediaType **aOutMFType);
--- a/dom/media/wmf/WMFDecoder.cpp
+++ b/dom/media/wmf/WMFDecoder.cpp
@@ -115,23 +115,23 @@ WMFDecoder::CanPlayType(const nsACString
     return false;
   }
   return true;
 }
 
 nsresult
 WMFDecoder::LoadDLLs()
 {
-  return SUCCEEDED(wmf::LoadDLLs()) ? NS_OK : NS_ERROR_FAILURE;
+  return NS_OK; // Removed in next patch in series.
 }
 
 void
 WMFDecoder::UnloadDLLs()
 {
-  wmf::UnloadDLLs();
+  // Removed in next patch in series.
 }
 
 /* static */
 bool
 WMFDecoder::IsEnabled()
 {
   // We only use WMF on Windows Vista and up
   return IsVistaOrLater() &&
--- a/dom/media/wmf/WMFUtils.cpp
+++ b/dom/media/wmf/WMFUtils.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/RefPtr.h"
 #include "mozilla/WindowsVersion.h"
 #include "mozilla/Logging.h"
 #include "nsThreadUtils.h"
 #include "nsWindowsHelpers.h"
 #include "mozilla/CheckedInt.h"
 #include "VideoUtils.h"
 #include <initguid.h>
+#include "nsTArray.h"
 
 #ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
 // Some SDK versions don't define the AAC decoder CLSID.
 // {32D186A7-218F-4C75-8876-DD77273A8999}
 DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD, 0x77, 0x27, 0x3A, 0x89, 0x99);
 #endif
 
 namespace mozilla {
@@ -349,151 +350,55 @@ GetPictureRegion(IMFMediaType* aMediaTyp
   hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   aOutPictureRegion = nsIntRect(0, 0, width, height);
   return S_OK;
 }
 
 namespace wmf {
 
-static bool
-IsSupportedDecoder(const GUID& aDecoderGUID)
-{
-  return aDecoderGUID == CLSID_CMSH264DecoderMFT ||
-         aDecoderGUID == CLSID_CMSAACDecMFT ||
-         aDecoderGUID == CLSID_CMP3DecMediaObject;
-}
-
-static HRESULT
-DisableBlockedDecoders(IMFPluginControl* aPluginControl,
-                       const GUID& aCategory)
-{
-  HRESULT hr = S_OK;
-
-  UINT32 numMFTs = 0;
-  IMFActivate **ppActivate = nullptr;
-  hr = wmf::MFTEnumEx(aCategory,
-                      MFT_ENUM_FLAG_ALL,
-                      nullptr, // Input type, nullptr -> match all.
-                      nullptr, // Output type, nullptr -> match all.
-                      &ppActivate,
-                      &numMFTs);
-
-  if (SUCCEEDED(hr) && numMFTs == 0) {
-    hr = MF_E_TOPO_CODEC_NOT_FOUND;
-  }
-
-  for (UINT32 i = 0; i < numMFTs; i++) {
-    // Note: We must release all IMFActivate objects in the list, hence
-    // we're putting individual IMFActivate objects in into a smart ptr.
-    RefPtr<IMFActivate> activate = ppActivate[i];
-    GUID guid = GUID_NULL;
-    hr = activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guid);
-    if (FAILED(hr)) {
-      NS_WARNING("FAILED to get IMFActivate clsid");
-      continue;
-    }
-    if (!IsSupportedDecoder(guid)) {
-      hr = aPluginControl->SetDisabled(MF_Plugin_Type_MFT, guid, TRUE);
-      NS_ASSERTION(SUCCEEDED(hr), "Failed to disable plugin!");
-    }
-  }
-  CoTaskMemFree(ppActivate);
-
-  return hr;
-}
-
-static HRESULT
-DisableBlockedDecoders()
-{
-  RefPtr<IMFPluginControl> pluginControl;
-  HRESULT hr = wmf::MFGetPluginControl(byRef(pluginControl));
-  if (SUCCEEDED(hr) && pluginControl) {
-    hr = DisableBlockedDecoders(pluginControl,
-                                MFT_CATEGORY_VIDEO_DECODER);
-    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
-    hr = DisableBlockedDecoders(pluginControl,
-                                MFT_CATEGORY_AUDIO_DECODER);
-    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-  }
-
-  return S_OK;
-}
-
-static bool sDLLsLoaded = false;
-static bool sFailedToLoadDlls = false;
-
-struct WMFModule {
-  const wchar_t* name;
-  HMODULE handle;
-};
-
-static WMFModule sDLLs[] = {
-  { L"mfplat.dll", nullptr },
-  { L"mfreadwrite.dll", nullptr },
-  { L"propsys.dll", nullptr },
-  { L"mf.dll", nullptr },
-  { L"dxva2.dll", nullptr }
+static const wchar_t* sDLLs[] = {
+  L"mfplat.dll",
+  L"propsys.dll",
+  L"mf.dll",
+  L"dxva2.dll",
 };
 
 HRESULT
 LoadDLLs()
 {
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  static bool sDLLsLoaded = false;
+  static bool sFailedToLoadDlls = false;
 
   if (sDLLsLoaded) {
     return S_OK;
   }
   if (sFailedToLoadDlls) {
     return E_FAIL;
   }
 
-  // Try to load all the required DLLs.
-  const uint32_t dllLength = ArrayLength(sDLLs);
-  for (uint32_t i = 0; i < dllLength; i++) {
-    sDLLs[i].handle = LoadLibrarySystem32(sDLLs[i].name);
-    if (!sDLLs[i].handle) {
+  // Try to load all the required DLLs. If we fail to load any dll,
+  // unload the dlls we succeeded in loading.
+  nsTArray<const wchar_t*> loadedDlls;
+  for (const wchar_t* dll : sDLLs) {
+    if (!LoadLibrarySystem32(dll)) {
+      NS_WARNING("Failed to load WMF DLLs");
+      for (const wchar_t* loadedDll : loadedDlls) {
+        FreeLibrary(GetModuleHandleW(loadedDll));
+      }
       sFailedToLoadDlls = true;
-      NS_WARNING("Failed to load WMF DLLs");
-      UnloadDLLs();
       return E_FAIL;
     }
+    loadedDlls.AppendElement(dll);
   }
-
-  // Enumerate all the decoders on the system, and disable the ones except
-  // those which we expect to use, the MP3, AAC and H.264 decoders.
-  if (FAILED(DisableBlockedDecoders())) {
-    sFailedToLoadDlls = true;
-    NS_WARNING("Failed to disable non whitelisted WMF decoders");
-    UnloadDLLs();
-    return E_FAIL;
-  }
-
   sDLLsLoaded = true;
 
   return S_OK;
 }
 
-HRESULT
-UnloadDLLs()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-
-  const uint32_t length = ArrayLength(sDLLs);
-  for (uint32_t i = 0; i < length; i++) {
-    if (sDLLs[i].handle) {
-      FreeLibrary(sDLLs[i].handle);
-      sDLLs[i].handle = nullptr;
-    }
-    sDLLsLoaded = false;
-  }
-  return S_OK;
-}
-
 #define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
   static FunctionType FunctionName##Ptr = nullptr; \
   if (!FunctionName##Ptr) { \
     FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandleW(L ## #DLL), #FunctionName); \
     if (!FunctionName##Ptr) { \
       NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \
       return E_FAIL; \
     } \
@@ -506,16 +411,19 @@ UnloadDLLs()
   ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \
 
 #define DECL_FUNCTION_PTR(FunctionName, ...) \
   typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__)
 
 HRESULT
 MFStartup()
 {
+  HRESULT hr = LoadDLLs();
+  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+
   const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION);
   const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
 
   // decltype is unusable for functions having default parameters
   DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
   ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
   if (!IsWin7OrLater())
     return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -89,20 +89,16 @@
 #ifdef MOZ_WEBSPEECH
 #include "nsSynthVoiceRegistry.h"
 #endif
 
 #ifdef MOZ_ANDROID_OMX
 #include "AndroidMediaPluginHost.h"
 #endif
 
-#ifdef MOZ_WMF
-#include "WMFDecoder.h"
-#endif
-
 #ifdef MOZ_GSTREAMER
 #include "GStreamerFormatHelper.h"
 #endif
 
 #ifdef MOZ_FFMPEG
 #include "FFmpegRuntimeLinker.h"
 #endif
 
@@ -400,20 +396,16 @@ nsLayoutStatics::Shutdown()
 #ifdef MOZ_FFMPEG
   FFmpegRuntimeLinker::Unlink();
 #endif
 
   CubebUtils::ShutdownLibrary();
   AsyncLatencyLogger::ShutdownLogger();
   WebAudioUtils::Shutdown();
 
-#ifdef MOZ_WMF
-  WMFDecoder::UnloadDLLs();
-#endif
-
 #ifdef MOZ_WIDGET_GONK
   nsVolumeService::Shutdown();
   SpeakerManagerService::Shutdown();
 #endif
 
 #ifdef MOZ_WEBSPEECH
   nsSynthVoiceRegistry::Shutdown();
 #endif