diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:42 +0000 |
commit | da4c7e7ed675c3bf405668739c3012d140856109 (patch) | |
tree | cdd868dba063fecba609a1d819de271f0d51b23e /dom/media/ipc/MFCDMParent.cpp | |
parent | Adding upstream version 125.0.3. (diff) | |
download | firefox-da4c7e7ed675c3bf405668739c3012d140856109.tar.xz firefox-da4c7e7ed675c3bf405668739c3012d140856109.zip |
Adding upstream version 126.0.upstream/126.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/media/ipc/MFCDMParent.cpp')
-rw-r--r-- | dom/media/ipc/MFCDMParent.cpp | 229 |
1 files changed, 145 insertions, 84 deletions
diff --git a/dom/media/ipc/MFCDMParent.cpp b/dom/media/ipc/MFCDMParent.cpp index 2e91048b88..4570fbe838 100644 --- a/dom/media/ipc/MFCDMParent.cpp +++ b/dom/media/ipc/MFCDMParent.cpp @@ -5,6 +5,7 @@ #include "MFCDMParent.h" #include <mfmediaengine.h> +#include <unknwnbase.h> #include <wtypes.h> #define INITGUID // Enable DEFINE_PROPERTYKEY() #include <propkeydef.h> // For DEFINE_PROPERTYKEY() definition @@ -92,6 +93,8 @@ StaticMutex sFactoryMutex; static nsTHashMap<nsStringHashKey, ComPtr<IMFContentDecryptionModuleFactory>> sFactoryMap; static CopyableTArray<MFCDMCapabilitiesIPDL> sCapabilities; +StaticMutex sCapabilitesMutex; +static ComPtr<IUnknown> sMediaEngineClassFactory; // RAIIized PROPVARIANT. See // third_party/libwebrtc/modules/audio_device/win/core_audio_utility_win.h @@ -166,6 +169,11 @@ static nsString GetHdcpPolicy(const dom::HDCPVersion& aMinHdcpVersion) { return nsString(u"hdcp=1"); } +static bool RequireClearLead(const nsString& aKeySystem) { + return aKeySystem.EqualsLiteral(kWidevineExperiment2KeySystemName) || + aKeySystem.EqualsLiteral(kPlayReadyHardwareClearLeadKeySystemName); +} + static void BuildCapabilitiesArray( const nsTArray<MFCDMMediaCapability>& aCapabilities, AutoPropVar& capabilitiesPropOut) { @@ -464,8 +472,10 @@ LPCWSTR MFCDMParent::GetCDMLibraryName(const nsString& aKeySystem) { /* static */ void MFCDMParent::Shutdown() { + StaticMutexAutoLock lock(sCapabilitesMutex); sFactoryMap.Clear(); sCapabilities.Clear(); + sMediaEngineClassFactory.Reset(); } /* static */ @@ -500,10 +510,13 @@ HRESULT MFCDMParent::LoadFactory( NS_ConvertUTF16toUTF8(aKeySystem).get()); ComPtr<IMFContentDecryptionModuleFactory> cdmFactory; if (loadFromPlatform) { + if (!sMediaEngineClassFactory) { + MFCDM_RETURN_IF_FAILED(CoCreateInstance( + CLSID_MFMediaEngineClassFactory, nullptr, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&sMediaEngineClassFactory))); + } ComPtr<IMFMediaEngineClassFactory4> clsFactory; - MFCDM_RETURN_IF_FAILED(CoCreateInstance(CLSID_MFMediaEngineClassFactory, - nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&clsFactory))); + MFCDM_RETURN_IF_FAILED(sMediaEngineClassFactory.As(&clsFactory)); MFCDM_RETURN_IF_FAILED(clsFactory->CreateContentDecryptionModuleFactory( MapKeySystem(aKeySystem).get(), IID_PPV_ARGS(&cdmFactory))); aFactoryOut.Swap(cdmFactory); @@ -617,12 +630,8 @@ static bool FactorySupports(ComPtr<IMFContentDecryptionModuleFactory>& aFactory, // use another way to check the capabilities. if (IsPlayReadyKeySystemAndSupported(aKeySystem) && StaticPrefs::media_eme_playready_istypesupportedex()) { - ComPtr<IMFMediaEngineClassFactory> spFactory; ComPtr<IMFExtendedDRMTypeSupport> spDrmTypeSupport; - MFCDM_RETURN_BOOL_IF_FAILED( - CoCreateInstance(CLSID_MFMediaEngineClassFactory, NULL, - CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&spFactory))); - MFCDM_RETURN_BOOL_IF_FAILED(spFactory.As(&spDrmTypeSupport)); + MFCDM_RETURN_BOOL_IF_FAILED(sMediaEngineClassFactory.As(&spDrmTypeSupport)); BSTR keySystem = aIsHWSecure ? CreateBSTRFromConstChar(kPlayReadyKeySystemHardware) : CreateBSTRFromConstChar(kPlayReadyKeySystemName); @@ -699,46 +708,55 @@ MFCDMParent::GetAllKeySystemsCapabilities() { new CapabilitiesPromise::Private(__func__); Unused << backgroundTaskQueue->Dispatch(NS_NewRunnableFunction(__func__, [p] { MFCDM_PARENT_SLOG("GetAllKeySystemsCapabilities"); - if (sCapabilities.IsEmpty()) { - enum SecureLevel : bool { - Software = false, - Hardware = true, - }; - const nsTArray<std::pair<nsString, SecureLevel>> kKeySystems{ - std::pair<nsString, SecureLevel>( - NS_ConvertUTF8toUTF16(kPlayReadyKeySystemName), - SecureLevel::Software), - std::pair<nsString, SecureLevel>( - NS_ConvertUTF8toUTF16(kPlayReadyKeySystemHardware), - SecureLevel::Hardware), - std::pair<nsString, SecureLevel>( - NS_ConvertUTF8toUTF16(kPlayReadyHardwareClearLeadKeySystemName), - SecureLevel::Hardware), - std::pair<nsString, SecureLevel>( - NS_ConvertUTF8toUTF16(kWidevineExperimentKeySystemName), - SecureLevel::Hardware), - std::pair<nsString, SecureLevel>( - NS_ConvertUTF8toUTF16(kWidevineExperiment2KeySystemName), - SecureLevel::Hardware), - }; - for (const auto& keySystem : kKeySystems) { - // Only check the capabilites if the relative prefs for the key system - // are ON. - if (IsPlayReadyKeySystemAndSupported(keySystem.first) || - IsWidevineExperimentKeySystemAndSupported(keySystem.first)) { - MFCDMCapabilitiesIPDL* c = sCapabilities.AppendElement(); - GetCapabilities(keySystem.first, keySystem.second, nullptr, *c); + enum SecureLevel : bool { + Software = false, + Hardware = true, + }; + const nsTArray<std::pair<nsString, SecureLevel>> kKeySystems{ + std::pair<nsString, SecureLevel>( + NS_ConvertUTF8toUTF16(kPlayReadyKeySystemName), + SecureLevel::Software), + std::pair<nsString, SecureLevel>( + NS_ConvertUTF8toUTF16(kPlayReadyKeySystemHardware), + SecureLevel::Hardware), + std::pair<nsString, SecureLevel>( + NS_ConvertUTF8toUTF16(kPlayReadyHardwareClearLeadKeySystemName), + SecureLevel::Hardware), + std::pair<nsString, SecureLevel>( + NS_ConvertUTF8toUTF16(kWidevineExperimentKeySystemName), + SecureLevel::Hardware), + std::pair<nsString, SecureLevel>( + NS_ConvertUTF8toUTF16(kWidevineExperiment2KeySystemName), + SecureLevel::Hardware), + }; + + CopyableTArray<MFCDMCapabilitiesIPDL> capabilitiesArr; + for (const auto& keySystem : kKeySystems) { + // Only check the capabilites if the relative prefs for the key system + // are ON. + if (IsPlayReadyKeySystemAndSupported(keySystem.first) || + IsWidevineExperimentKeySystemAndSupported(keySystem.first)) { + MFCDMCapabilitiesIPDL* c = capabilitiesArr.AppendElement(); + CapabilitesFlagSet flags; + if (keySystem.second == SecureLevel::Hardware) { + flags += CapabilitesFlag::HarewareDecryption; + } + flags += CapabilitesFlag::NeedHDCPCheck; + if (RequireClearLead(keySystem.first)) { + flags += CapabilitesFlag::NeedClearLeadCheck; } + GetCapabilities(keySystem.first, flags, nullptr, *c); } } - p->Resolve(sCapabilities, __func__); + + p->Resolve(std::move(capabilitiesArr), __func__); })); return p; } /* static */ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, - const bool aIsHWSecure, + const CapabilitesFlagSet& aFlags, IMFContentDecryptionModuleFactory* aFactory, MFCDMCapabilitiesIPDL& aCapabilitiesOut) { aCapabilitiesOut.keySystem() = aKeySystem; @@ -747,9 +765,12 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, aCapabilitiesOut.persistentState() = KeySystemConfig::Requirement::Required; aCapabilitiesOut.distinctiveID() = KeySystemConfig::Requirement::Required; + const bool isHardwareDecryption = + aFlags.contains(CapabilitesFlag::HarewareDecryption); + aCapabilitiesOut.isHardwareDecryption() = isHardwareDecryption; // Return empty capabilites for SWDRM on Windows 10 because it has the process // leaking problem. - if (!IsWin11OrLater() && !aIsHWSecure) { + if (!IsWin11OrLater() && !isHardwareDecryption) { return; } @@ -758,6 +779,30 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, RETURN_VOID_IF_FAILED(GetOrCreateFactory(aKeySystem, factory)); } + StaticMutexAutoLock lock(sCapabilitesMutex); + for (auto& capabilities : sCapabilities) { + if (capabilities.keySystem().Equals(aKeySystem) && + capabilities.isHardwareDecryption() == isHardwareDecryption) { + MFCDM_PARENT_SLOG( + "Return cached capabilities for %s (hardwareDecryption=%d)", + NS_ConvertUTF16toUTF8(aKeySystem).get(), isHardwareDecryption); + if (capabilities.isHDCP22Compatible().isNothing() && + aFlags.contains(CapabilitesFlag::NeedHDCPCheck)) { + const bool rv = IsHDCPVersionSupported(factory, aKeySystem, + dom::HDCPVersion::_2_2) == NS_OK; + MFCDM_PARENT_SLOG( + "Check HDCP 2.2 compatible (%d) for the cached capabilites", rv); + capabilities.isHDCP22Compatible() = Some(rv); + } + aCapabilitiesOut = capabilities; + return; + } + } + + MFCDM_PARENT_SLOG( + "Query capabilities for %s from the factory (hardwareDecryption=%d)", + NS_ConvertUTF16toUTF8(aKeySystem).get(), isHardwareDecryption); + // Widevine requires codec type to be four CC, PlayReady is fine with both. static auto convertCodecToFourCC = [](const KeySystemConfig::EMECodecString& aCodec) { @@ -809,12 +854,12 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, } if (FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), KeySystemConfig::EMECodecString(""), nsString(u""), - aIsHWSecure)) { + isHardwareDecryption)) { MFCDMMediaCapability* c = aCapabilitiesOut.videoCapabilities().AppendElement(); c->contentType() = NS_ConvertUTF8toUTF16(codec); c->robustness() = - GetRobustnessStringForKeySystem(aKeySystem, aIsHWSecure); + GetRobustnessStringForKeySystem(aKeySystem, isHardwareDecryption); MFCDM_PARENT_SLOG("%s: +video:%s", __func__, codec.get()); supportedVideoCodecs.AppendElement(codec); } @@ -831,52 +876,51 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, KeySystemConfig::EME_CODEC_VORBIS, }); for (const auto& codec : kAudioCodecs) { - if (FactorySupports( - factory, aKeySystem, convertCodecToFourCC(supportedVideoCodecs[0]), - convertCodecToFourCC(codec), nsString(u""), aIsHWSecure)) { + // Hardware decryption is usually only used for video, so we can just check + // the software capabilities for audio in order to save some time. As the + // media foundation would create a new D3D device everytime when we check + // hardware decryption, which takes way longer time. + if (FactorySupports(factory, aKeySystem, + convertCodecToFourCC(supportedVideoCodecs[0]), + convertCodecToFourCC(codec), nsString(u""), + false /* aIsHWSecure */)) { MFCDMMediaCapability* c = aCapabilitiesOut.audioCapabilities().AppendElement(); c->contentType() = NS_ConvertUTF8toUTF16(codec); - c->robustness() = GetRobustnessStringForKeySystem(aKeySystem, aIsHWSecure, - false /* isVideo */); + c->robustness() = GetRobustnessStringForKeySystem( + aKeySystem, false /* aIsHWSecure */, false /* isVideo */); MFCDM_PARENT_SLOG("%s: +audio:%s", __func__, codec.get()); } } - // Collect schemes supported by all video codecs. - static nsTArray<std::pair<CryptoScheme, nsDependentString>> kSchemes = { - std::pair<CryptoScheme, nsDependentString>( - CryptoScheme::Cenc, u"encryption-type=cenc,encryption-iv-size=8,"), - std::pair<CryptoScheme, nsDependentString>( - CryptoScheme::Cbcs, u"encryption-type=cbcs,encryption-iv-size=16,")}; - for (auto& scheme : kSchemes) { - bool ok = true; - for (auto& codec : supportedVideoCodecs) { - ok &= FactorySupports( - factory, aKeySystem, convertCodecToFourCC(codec), nsCString(""), - scheme.second /* additional feature */, aIsHWSecure); - if (!ok) { - break; - } - } - if (ok) { - aCapabilitiesOut.encryptionSchemes().AppendElement(scheme.first); - MFCDM_PARENT_SLOG("%s: +scheme:%s", __func__, - scheme.first == CryptoScheme::Cenc ? "cenc" : "cbcs"); - } + // 'If value is unspecified, default value of "cenc" is used.' See + // https://learn.microsoft.com/en-us/windows/win32/api/mfmediaengine/nf-mfmediaengine-imfextendeddrmtypesupport-istypesupportedex + if (!supportedVideoCodecs.IsEmpty()) { + aCapabilitiesOut.encryptionSchemes().AppendElement(CryptoScheme::Cenc); + MFCDM_PARENT_SLOG("%s: +scheme:cenc", __func__); } - static auto RequireClearLead = [](const nsString& aKeySystem) { - if (aKeySystem.EqualsLiteral(kWidevineExperiment2KeySystemName) || - aKeySystem.EqualsLiteral(kPlayReadyHardwareClearLeadKeySystemName)) { - return true; + // Check another scheme "cbcs" + static std::pair<CryptoScheme, nsDependentString> kCbcs = + std::pair<CryptoScheme, nsDependentString>( + CryptoScheme::Cbcs, u"encryption-type=cbcs,encryption-iv-size=16,"); + bool ok = true; + for (const auto& codec : supportedVideoCodecs) { + ok &= FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), + nsCString(""), kCbcs.second /* additional feature */, + isHardwareDecryption); + if (!ok) { + break; } - return false; - }; + } + if (ok) { + aCapabilitiesOut.encryptionSchemes().AppendElement(kCbcs.first); + MFCDM_PARENT_SLOG("%s: +scheme:cbcs", __func__); + } // For key system requires clearlead, every codec needs to have clear support. // If not, then we will remove the codec from supported codec. - if (RequireClearLead(aKeySystem)) { + if (aFlags.contains(CapabilitesFlag::NeedClearLeadCheck)) { for (const auto& scheme : aCapabilitiesOut.encryptionSchemes()) { nsTArray<KeySystemConfig::EMECodecString> noClearLeadCodecs; for (const auto& codec : supportedVideoCodecs) { @@ -894,9 +938,9 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, } else { additionalFeature.AppendLiteral(u"cbcs-clearlead,"); } - bool rv = - FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), - nsCString(""), additionalFeature, aIsHWSecure); + bool rv = FactorySupports(factory, aKeySystem, + convertCodecToFourCC(codec), nsCString(""), + additionalFeature, isHardwareDecryption); MFCDM_PARENT_SLOG("clearlead %s IV 8 bytes %s %s", CryptoSchemeToString(scheme), codec.get(), rv ? "supported" : "not supported"); @@ -906,7 +950,8 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, // Try 16 bytes IV. additionalFeature.AppendLiteral(u"encryption-iv-size=16,"); rv = FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), - nsCString(""), additionalFeature, aIsHWSecure); + nsCString(""), additionalFeature, + isHardwareDecryption); MFCDM_PARENT_SLOG("clearlead %s IV 16 bytes %s %s", CryptoSchemeToString(scheme), codec.get(), rv ? "supported" : "not supported"); @@ -926,9 +971,14 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, } } - if (IsHDCPVersionSupported(factory, aKeySystem, dom::HDCPVersion::_2_2) == - NS_OK) { - aCapabilitiesOut.isHDCP22Compatible() = true; + // Only perform HDCP if necessary, "The hdcp query (item 4) has a + // computationally expensive first invocation cost". See + // https://learn.microsoft.com/en-us/windows/win32/api/mfmediaengine/nf-mfmediaengine-imfextendeddrmtypesupport-istypesupportedex + if (aFlags.contains(CapabilitesFlag::NeedHDCPCheck) && + IsHDCPVersionSupported(factory, aKeySystem, dom::HDCPVersion::_2_2) == + NS_OK) { + MFCDM_PARENT_SLOG("Capabilites is compatible with HDCP 2.2"); + aCapabilitiesOut.isHDCP22Compatible() = Some(true); } // TODO: don't hardcode @@ -938,13 +988,24 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, KeySystemConfig::SessionType::Temporary); aCapabilitiesOut.sessionTypes().AppendElement( KeySystemConfig::SessionType::PersistentLicense); + + // Cache capabilities for reuse. + sCapabilities.AppendElement(aCapabilitiesOut); } mozilla::ipc::IPCResult MFCDMParent::RecvGetCapabilities( - const bool aIsHWSecure, GetCapabilitiesResolver&& aResolver) { + const MFCDMCapabilitiesRequest& aRequest, + GetCapabilitiesResolver&& aResolver) { MFCDM_REJECT_IF(!mFactory, NS_ERROR_DOM_NOT_SUPPORTED_ERR); MFCDMCapabilitiesIPDL capabilities; - GetCapabilities(mKeySystem, aIsHWSecure, mFactory.Get(), capabilities); + CapabilitesFlagSet flags; + if (aRequest.isHardwareDecryption()) { + flags += CapabilitesFlag::HarewareDecryption; + } + if (RequireClearLead(aRequest.keySystem())) { + flags += CapabilitesFlag::NeedClearLeadCheck; + } + GetCapabilities(aRequest.keySystem(), flags, mFactory.Get(), capabilities); aResolver(std::move(capabilities)); return IPC_OK(); } |