summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/wmf/WMFDecoderModule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/wmf/WMFDecoderModule.cpp')
-rw-r--r--dom/media/platforms/wmf/WMFDecoderModule.cpp257
1 files changed, 257 insertions, 0 deletions
diff --git a/dom/media/platforms/wmf/WMFDecoderModule.cpp b/dom/media/platforms/wmf/WMFDecoderModule.cpp
new file mode 100644
index 000000000..06bf49fa6
--- /dev/null
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -0,0 +1,257 @@
+/* -*- 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 "WMFVideoMFTManager.h"
+#include "WMFAudioMFTManager.h"
+#include "MFTDecoder.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Services.h"
+#include "WMFMediaDataDecoder.h"
+#include "nsAutoPtr.h"
+#include "nsIWindowsRegKey.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIGfxInfo.h"
+#include "nsWindowsHelpers.h"
+#include "GfxDriverInfo.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "MediaInfo.h"
+#include "MediaPrefs.h"
+#include "prsystem.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/WindowsVersion.h"
+#include "MP4Decoder.h"
+#include "VPXDecoder.h"
+
+namespace mozilla {
+
+static Atomic<bool> sDXVAEnabled(false);
+
+WMFDecoderModule::WMFDecoderModule()
+ : mWMFInitialized(false)
+{
+}
+
+WMFDecoderModule::~WMFDecoderModule()
+{
+ if (mWMFInitialized) {
+ DebugOnly<HRESULT> hr = wmf::MFShutdown();
+ NS_ASSERTION(SUCCEEDED(hr), "MFShutdown failed");
+ }
+}
+
+/* static */
+void
+WMFDecoderModule::Init()
+{
+ sDXVAEnabled = gfx::gfxVars::CanUseHardwareVideoDecoding();
+}
+
+/* static */
+int
+WMFDecoderModule::GetNumDecoderThreads()
+{
+ int32_t numCores = PR_GetNumberOfProcessors();
+
+ // If we have more than 4 cores, let the decoder decide how many threads.
+ // On an 8 core machine, WMF chooses 4 decoder threads
+ const int WMF_DECODER_DEFAULT = -1;
+ int32_t prefThreadCount = WMF_DECODER_DEFAULT;
+ if (XRE_GetProcessType() != GeckoProcessType_GPU) {
+ prefThreadCount = MediaPrefs::PDMWMFThreadCount();
+ }
+ if (prefThreadCount != WMF_DECODER_DEFAULT) {
+ return std::max(prefThreadCount, 1);
+ } else if (numCores > 4) {
+ return WMF_DECODER_DEFAULT;
+ }
+ return std::max(numCores - 1, 1);
+}
+
+nsresult
+WMFDecoderModule::Startup()
+{
+ mWMFInitialized = SUCCEEDED(wmf::MFStartup());
+ return mWMFInitialized ? NS_OK : NS_ERROR_FAILURE;
+}
+
+already_AddRefed<MediaDataDecoder>
+WMFDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
+{
+ nsAutoPtr<WMFVideoMFTManager> manager(
+ new WMFVideoMFTManager(aParams.VideoConfig(),
+ aParams.mKnowsCompositor,
+ aParams.mImageContainer,
+ sDXVAEnabled));
+
+ if (!manager->Init()) {
+ return nullptr;
+ }
+
+ RefPtr<MediaDataDecoder> decoder =
+ new WMFMediaDataDecoder(manager.forget(), aParams.mTaskQueue, aParams.mCallback);
+
+ return decoder.forget();
+}
+
+already_AddRefed<MediaDataDecoder>
+WMFDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
+{
+ nsAutoPtr<WMFAudioMFTManager> manager(new WMFAudioMFTManager(aParams.AudioConfig()));
+
+ if (!manager->Init()) {
+ return nullptr;
+ }
+
+ RefPtr<MediaDataDecoder> decoder =
+ new WMFMediaDataDecoder(manager.forget(), aParams.mTaskQueue, aParams.mCallback);
+ return decoder.forget();
+}
+
+static bool
+CanCreateMFTDecoder(const GUID& aGuid)
+{
+ if (FAILED(wmf::MFStartup())) {
+ return false;
+ }
+ bool hasdecoder = false;
+ {
+ RefPtr<MFTDecoder> decoder(new MFTDecoder());
+ hasdecoder = SUCCEEDED(decoder->Create(aGuid));
+ }
+ wmf::MFShutdown();
+ return hasdecoder;
+}
+
+template<const GUID& aGuid>
+static bool
+CanCreateWMFDecoder()
+{
+ static StaticMutex sMutex;
+ StaticMutexAutoLock lock(sMutex);
+ static Maybe<bool> result;
+ if (result.isNothing()) {
+ result.emplace(CanCreateMFTDecoder(aGuid));
+ }
+ return result.value();
+}
+
+static bool
+IsH264DecoderBlacklisted()
+{
+#ifdef BLACKLIST_CRASHY_H264_DECODERS
+ WCHAR systemPath[MAX_PATH + 1];
+ if (!ConstructSystem32Path(L"msmpeg2vdec.dll", systemPath, MAX_PATH + 1)) {
+ // Cannot build path -> Assume it's not the blacklisted DLL.
+ return false;
+ }
+
+ DWORD zero;
+ DWORD infoSize = GetFileVersionInfoSizeW(systemPath, &zero);
+ if (infoSize == 0) {
+ // Can't get file info -> Assume we don't have the blacklisted DLL.
+ return false;
+ }
+ auto infoData = MakeUnique<unsigned char[]>(infoSize);
+ VS_FIXEDFILEINFO *vInfo;
+ UINT vInfoLen;
+ if (GetFileVersionInfoW(systemPath, 0, infoSize, infoData.get()) &&
+ VerQueryValueW(infoData.get(), L"\\", (LPVOID*)&vInfo, &vInfoLen))
+ {
+ if ((vInfo->dwFileVersionMS == ((12u << 16) | 0u))
+ && ((vInfo->dwFileVersionLS == ((9200u << 16) | 16426u))
+ || (vInfo->dwFileVersionLS == ((9200u << 16) | 17037u)))) {
+ // 12.0.9200.16426 & .17037 are blacklisted on Win64, see bug 1242343.
+ return true;
+ }
+ }
+#endif // BLACKLIST_CRASHY_H264_DECODERS
+ return false;
+}
+
+/* static */ bool
+WMFDecoderModule::HasH264()
+{
+ if (IsH264DecoderBlacklisted()) {
+ return false;
+ }
+ return CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>();
+}
+
+/* static */ bool
+WMFDecoderModule::HasAAC()
+{
+ return CanCreateWMFDecoder<CLSID_CMSAACDecMFT>();
+}
+
+bool
+WMFDecoderModule::SupportsMimeType(const nsACString& aMimeType,
+ DecoderDoctorDiagnostics* aDiagnostics) const
+{
+ UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
+ if (!trackInfo) {
+ return false;
+ }
+ return Supports(*trackInfo, aDiagnostics);
+}
+
+bool
+WMFDecoderModule::Supports(const TrackInfo& aTrackInfo,
+ DecoderDoctorDiagnostics* aDiagnostics) const
+{
+ if ((aTrackInfo.mMimeType.EqualsLiteral("audio/mp4a-latm") ||
+ aTrackInfo.mMimeType.EqualsLiteral("audio/mp4")) &&
+ WMFDecoderModule::HasAAC()) {
+ return true;
+ }
+ if (MP4Decoder::IsH264(aTrackInfo.mMimeType) && WMFDecoderModule::HasH264()) {
+ const VideoInfo* videoInfo = aTrackInfo.GetAsVideoInfo();
+ MOZ_ASSERT(videoInfo);
+ // Check Windows format constraints, based on:
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/dd797815(v=vs.85).aspx
+ if (IsWin8OrLater()) {
+ // Windows >7 supports at most 4096x2304.
+ if (videoInfo->mImage.width > 4096 || videoInfo->mImage.height > 2304) {
+ return false;
+ }
+ } else {
+ // Windows <=7 supports at most 1920x1088.
+ if (videoInfo->mImage.width > 1920 || videoInfo->mImage.height > 1088) {
+ return false;
+ }
+ }
+ return true;
+ }
+ if (aTrackInfo.mMimeType.EqualsLiteral("audio/mpeg") &&
+ CanCreateWMFDecoder<CLSID_CMP3DecMediaObject>()) {
+ return true;
+ }
+ if (MediaPrefs::PDMWMFVP9DecoderEnabled() && sDXVAEnabled) {
+ if ((VPXDecoder::IsVP8(aTrackInfo.mMimeType) ||
+ VPXDecoder::IsVP9(aTrackInfo.mMimeType)) &&
+ CanCreateWMFDecoder<CLSID_WebmMfVpxDec>()) {
+ return true;
+ }
+ }
+
+ // Some unsupported codec.
+ return false;
+}
+
+PlatformDecoderModule::ConversionRequired
+WMFDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
+{
+ if (aConfig.IsVideo() && MP4Decoder::IsH264(aConfig.mMimeType)) {
+ return ConversionRequired::kNeedAnnexB;
+ } else {
+ return ConversionRequired::kNeedNone;
+ }
+}
+
+} // namespace mozilla