From 0cf79ef5401ca8522d162e6dde3c55418c1f1d00 Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Wed, 29 May 2024 02:15:25 +0300 Subject: [PATCH] Backed out 5 changesets (bug 1898588) for bustages on MediaData.cpp . CLOSED TREE Backed out changeset d23ba62a5165 (bug 1898588) Backed out changeset dd7a777b034f (bug 1898588) Backed out changeset 62c4a3361e00 (bug 1898588) Backed out changeset 2643cfcd1ba7 (bug 1898588) Backed out changeset 940fca861f93 (bug 1898588) --- dom/media/MediaData.cpp | 48 +--- dom/media/MediaData.h | 6 - dom/media/eme/EMEUtils.cpp | 29 ++- dom/media/eme/EMEUtils.h | 2 + dom/media/eme/KeySystemConfig.cpp | 14 ++ dom/media/eme/KeySystemConfig.h | 94 ++------ dom/media/eme/MediaKeySystemAccess.cpp | 67 +++--- dom/media/eme/mediafoundation/WMFCDMImpl.cpp | 18 +- dom/media/eme/mediafoundation/WMFCDMProxy.cpp | 11 +- dom/media/gmp/ChromiumCDMParent.cpp | 1 - dom/media/ipc/MFCDMParent.cpp | 206 +++++++++--------- dom/media/ipc/MFCDMSerializers.h | 6 +- dom/media/ipc/PMFCDM.ipdl | 2 +- .../agnostic/eme/ChromiumCDMVideoDecoder.cpp | 1 - .../platforms/android/RemoteDataDecoder.cpp | 5 +- .../platforms/wmf/MFMediaEngineStream.cpp | 3 +- ipc/glue/UtilityAudioDecoderChild.cpp | 18 +- toolkit/content/aboutSupport.js | 1 + 18 files changed, 229 insertions(+), 303 deletions(-) diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index cc3acddc045b..15774ec53369 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -597,53 +597,15 @@ void MediaRawDataWriter::PopFront(size_t aSize) { const char* CryptoSchemeToString(const CryptoScheme& aScheme) { switch (aScheme) { case CryptoScheme::None: - return "none"; + return "None"; case CryptoScheme::Cenc: - return "cenc"; + return "Cenc"; case CryptoScheme::Cbcs: - return "cbcs"; - case CryptoScheme::Cbcs_1_9: - return "cbcs-1-9"; + return "Cbcs"; default: - MOZ_ASSERT_UNREACHABLE("not supported scheme!"); - return "not supported scheme!"; + MOZ_ASSERT_UNREACHABLE(); + return ""; } } -nsCString CryptoSchemeSetToString(const CryptoSchemeSet& aSchemes) { - nsAutoCString rv; - if (aSchemes.contains(CryptoScheme::Cenc)) { - rv.AppendLiteral("cenc"); - } - if (aSchemes.contains(CryptoScheme::Cbcs)) { - if (!rv.IsEmpty()) { - rv.AppendLiteral("/"); - } - rv.AppendLiteral("cbcs"); - } - if (aSchemes.contains(CryptoScheme::Cbcs_1_9)) { - if (!rv.IsEmpty()) { - rv.AppendLiteral("/"); - } - rv.AppendLiteral("cbcs-1-9"); - } - if (rv.IsEmpty()) { - rv.AppendLiteral("none"); - } - return rv; -} - -CryptoScheme StringToCryptoScheme(const nsAString& aString) { - if (aString.EqualsLiteral("cenc")) { - return CryptoScheme::Cenc; - } - if (aString.EqualsLiteral("cbcs")) { - return CryptoScheme::Cbcs; - } - if (aString.EqualsLiteral("cbcs-1-9")) { - return CryptoScheme::Cbcs_1_9; - } - return CryptoScheme::None; -} - } // namespace mozilla diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index 237bd838a6ec..f9f1aad2f1ca 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -13,7 +13,6 @@ # include "SharedBuffer.h" # include "TimeUnits.h" # include "mozilla/CheckedInt.h" -# include "mozilla/EnumSet.h" # include "mozilla/Maybe.h" # include "mozilla/PodOperations.h" # include "mozilla/RefPtr.h" @@ -582,18 +581,13 @@ class VideoData : public MediaData { media::TimeUnit mNextKeyFrameTime; }; -// See https://w3c.github.io/encrypted-media/#scheme-cenc enum class CryptoScheme : uint8_t { None, Cenc, Cbcs, - Cbcs_1_9, }; -using CryptoSchemeSet = EnumSet; const char* CryptoSchemeToString(const CryptoScheme& aScheme); -nsCString CryptoSchemeSetToString(const CryptoSchemeSet& aSchemes); -CryptoScheme StringToCryptoScheme(const nsAString& aString); class CryptoTrack { public: diff --git a/dom/media/eme/EMEUtils.cpp b/dom/media/eme/EMEUtils.cpp index 08443f4ae6a7..19639388dab9 100644 --- a/dom/media/eme/EMEUtils.cpp +++ b/dom/media/eme/EMEUtils.cpp @@ -152,6 +152,19 @@ bool IsHardwareDecryptionSupported(const KeySystemConfig& aConfig) { return false; } +const char* EncryptionSchemeStr(const CryptoScheme& aScheme) { + switch (aScheme) { + case CryptoScheme::None: + return "none"; + case CryptoScheme::Cenc: + return "cenc"; + case CryptoScheme::Cbcs: + return "cbcs"; + default: + return "not-defined!"; + } +} + #ifdef MOZ_WMF_CDM void MFCDMCapabilitiesIPDLToKeySystemConfig( const MFCDMCapabilitiesIPDL& aCDMConfig, @@ -171,27 +184,23 @@ void MFCDMCapabilitiesIPDLToKeySystemConfig( !aKeySystemConfig.mVideoRobustness.Contains(c.robustness())) { aKeySystemConfig.mVideoRobustness.AppendElement(c.robustness()); } - CryptoSchemeSet schemes; - for (const auto& scheme : c.encryptionSchemes()) { - schemes += scheme; - } aKeySystemConfig.mMP4.SetCanDecryptAndDecode( - NS_ConvertUTF16toUTF8(c.contentType()), Some(schemes)); + NS_ConvertUTF16toUTF8(c.contentType())); } for (const auto& c : aCDMConfig.audioCapabilities()) { if (!c.robustness().IsEmpty() && !aKeySystemConfig.mAudioRobustness.Contains(c.robustness())) { aKeySystemConfig.mAudioRobustness.AppendElement(c.robustness()); } - CryptoSchemeSet schemes; - for (const auto& scheme : c.encryptionSchemes()) { - schemes += scheme; - } aKeySystemConfig.mMP4.SetCanDecryptAndDecode( - NS_ConvertUTF16toUTF8(c.contentType()), Some(schemes)); + NS_ConvertUTF16toUTF8(c.contentType())); } aKeySystemConfig.mPersistentState = aCDMConfig.persistentState(); aKeySystemConfig.mDistinctiveIdentifier = aCDMConfig.distinctiveID(); + for (const auto& scheme : aCDMConfig.encryptionSchemes()) { + aKeySystemConfig.mEncryptionSchemes.AppendElement( + NS_ConvertUTF8toUTF16(EncryptionSchemeStr(scheme))); + } aKeySystemConfig.mIsHDCP22Compatible = aCDMConfig.isHDCP22Compatible() ? *aCDMConfig.isHDCP22Compatible() : false; diff --git a/dom/media/eme/EMEUtils.h b/dom/media/eme/EMEUtils.h index 376f42de2f8d..424346645cfd 100644 --- a/dom/media/eme/EMEUtils.h +++ b/dom/media/eme/EMEUtils.h @@ -92,6 +92,8 @@ bool IsHardwareDecryptionSupported( const dom::MediaKeySystemConfiguration& aConfig); bool IsHardwareDecryptionSupported(const KeySystemConfig& aConfig); +const char* EncryptionSchemeStr(const CryptoScheme& aScheme); + #ifdef MOZ_WMF_CDM void MFCDMCapabilitiesIPDLToKeySystemConfig( const MFCDMCapabilitiesIPDL& aCDMConfig, KeySystemConfig& aKeySystemConfig); diff --git a/dom/media/eme/KeySystemConfig.cpp b/dom/media/eme/KeySystemConfig.cpp index b6aed96738e4..a1b6f9b2b08d 100644 --- a/dom/media/eme/KeySystemConfig.cpp +++ b/dom/media/eme/KeySystemConfig.cpp @@ -79,6 +79,9 @@ bool KeySystemConfig::Supports(const nsAString& aKeySystem) { config->mPersistentState = Requirement::Optional; config->mDistinctiveIdentifier = Requirement::NotAllowed; config->mSessionTypes.AppendElement(SessionType::Temporary); + config->mEncryptionSchemes.AppendElement(u"cenc"_ns); + config->mEncryptionSchemes.AppendElement(u"cbcs"_ns); + config->mEncryptionSchemes.AppendElement(u"cbcs-1-9"_ns); if (StaticPrefs::media_clearkey_persistent_license_enabled()) { config->mSessionTypes.AppendElement(SessionType::PersistentLicense); } @@ -134,6 +137,9 @@ bool KeySystemConfig::Supports(const nsAString& aKeySystem) { config->mAudioRobustness.AppendElement(u"SW_SECURE_CRYPTO"_ns); config->mVideoRobustness.AppendElement(u"SW_SECURE_CRYPTO"_ns); config->mVideoRobustness.AppendElement(u"SW_SECURE_DECODE"_ns); + config->mEncryptionSchemes.AppendElement(u"cenc"_ns); + config->mEncryptionSchemes.AppendElement(u"cbcs"_ns); + config->mEncryptionSchemes.AppendElement(u"cbcs-1-9"_ns); #if defined(MOZ_WIDGET_ANDROID) // MediaDrm.isCryptoSchemeSupported only allows passing @@ -362,6 +368,14 @@ nsString KeySystemConfig::GetDebugInfo() const { debugInfo.AppendLiteral(","); } } + debugInfo.AppendLiteral(" scheme=["); + for (size_t idx = 0; idx < mEncryptionSchemes.Length(); idx++) { + debugInfo.Append(mEncryptionSchemes[idx]); + if (idx + 1 < mEncryptionSchemes.Length()) { + debugInfo.AppendLiteral(","); + } + } + debugInfo.AppendLiteral("]"); debugInfo.AppendLiteral(" MP4={"); debugInfo.Append(NS_ConvertUTF8toUTF16(mMP4.GetDebugInfo())); debugInfo.AppendLiteral("}"); diff --git a/dom/media/eme/KeySystemConfig.h b/dom/media/eme/KeySystemConfig.h index 277e012db1ad..3bc274af9b96 100644 --- a/dom/media/eme/KeySystemConfig.h +++ b/dom/media/eme/KeySystemConfig.h @@ -7,7 +7,6 @@ #ifndef DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_ #define DOM_MEDIA_EME_KEYSYSTEMCONFIG_H_ -#include "MediaData.h" #include "nsString.h" #include "nsTArray.h" #include "mozilla/MozPromise.h" @@ -81,52 +80,38 @@ struct KeySystemConfig { return !mCodecsDecoded.IsEmpty() || !mCodecsDecrypted.IsEmpty(); } - // True if a codec and scheme pair can be decrypted and decoded - bool DecryptsAndDecodes( - const EMECodecString& aCodec, - const Maybe& aScheme = Nothing()) const { - return CheckCodecAndSchemePair(mCodecsDecoded, aCodec, aScheme); + // CDM decrypts and decodes using a DRM robust decoder, and passes decoded + // samples back to Gecko for rendering. + bool DecryptsAndDecodes(const EMECodecString& aCodec) const { + return mCodecsDecoded.Contains(aCodec); } - // True if a codec and scheme pair can be decrypted - bool Decrypts(const EMECodecString& aCodec, - const Maybe& aScheme = Nothing()) const { - return CheckCodecAndSchemePair(mCodecsDecrypted, aCodec, aScheme); + // CDM decrypts and passes the decrypted samples back to Gecko for decoding. + bool Decrypts(const EMECodecString& aCodec) const { + return mCodecsDecrypted.Contains(aCodec); } - void SetCanDecryptAndDecode( - const EMECodecString& aCodec, - const Maybe& aSchemes = Nothing{}) { + void SetCanDecryptAndDecode(const EMECodecString& aCodec) { // Can't both decrypt and decrypt-and-decode a codec. - MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec)); + MOZ_ASSERT(!Decrypts(aCodec)); // Prevent duplicates. - MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec)); - - mCodecsDecoded.AppendElement(CodecSchemePair{aCodec, aSchemes}); + MOZ_ASSERT(!DecryptsAndDecodes(aCodec)); + mCodecsDecoded.AppendElement(aCodec); } - void SetCanDecrypt(const EMECodecString& aCodec, - const Maybe& aSchemes = Nothing{}) { + void SetCanDecrypt(const EMECodecString& aCodec) { // Prevent duplicates. - MOZ_ASSERT(!ContainsDecryptedOnlyCodec(aCodec)); + MOZ_ASSERT(!Decrypts(aCodec)); // Can't both decrypt and decrypt-and-decode a codec. - MOZ_ASSERT(!ContainsDecryptedAndDecodedCodec(aCodec)); - mCodecsDecrypted.AppendElement(CodecSchemePair{aCodec, aSchemes}); + MOZ_ASSERT(!DecryptsAndDecodes(aCodec)); + mCodecsDecrypted.AppendElement(aCodec); } EMECodecString GetDebugInfo() const { EMECodecString info; info.AppendLiteral("decoding-and-decrypting:["); for (size_t idx = 0; idx < mCodecsDecoded.Length(); idx++) { - const auto& cur = mCodecsDecoded[idx]; - info.Append(cur.first); - if (cur.second) { - info.AppendLiteral("("); - info.Append(CryptoSchemeSetToString(*cur.second)); - info.AppendLiteral(")"); - } else { - info.AppendLiteral("(all)"); - } + info.Append(mCodecsDecoded[idx]); if (idx + 1 < mCodecsDecoded.Length()) { info.AppendLiteral(","); } @@ -134,15 +119,7 @@ struct KeySystemConfig { info.AppendLiteral("],"); info.AppendLiteral("decrypting-only:["); for (size_t idx = 0; idx < mCodecsDecrypted.Length(); idx++) { - const auto& cur = mCodecsDecrypted[idx]; - info.Append(cur.first); - if (cur.second) { - info.AppendLiteral("("); - info.Append(CryptoSchemeSetToString(*cur.second)); - info.AppendLiteral(")"); - } else { - info.AppendLiteral("(all)"); - } + info.Append(mCodecsDecrypted[idx]); if (idx + 1 < mCodecsDecrypted.Length()) { info.AppendLiteral(","); } @@ -152,38 +129,8 @@ struct KeySystemConfig { } private: - using CodecSchemePair = std::pair>; - // These two arrays are exclusive, the codec in one array can't appear on - // another array. If CryptoSchemeSet is nothing, that means the codec has - // support for all schemes, which is our default. Setting CryptoSchemeSet - // explicitly can restrict avaiable schemes for a codec. - nsTArray mCodecsDecoded; - nsTArray mCodecsDecrypted; - - bool ContainsDecryptedOnlyCodec(const EMECodecString& aCodec) const { - return std::any_of( - mCodecsDecrypted.begin(), mCodecsDecrypted.end(), - [&](const auto& aPair) { return aPair.first.Equals(aCodec); }); - } - bool ContainsDecryptedAndDecodedCodec(const EMECodecString& aCodec) const { - return std::any_of( - mCodecsDecoded.begin(), mCodecsDecoded.end(), - [&](const auto& aPair) { return aPair.first.Equals(aCodec); }); - } - bool CheckCodecAndSchemePair(const nsTArray& aArray, - const EMECodecString& aCodec, - const Maybe& aScheme) const { - return std::any_of(aArray.begin(), aArray.end(), [&](const auto& aPair) { - if (!aPair.first.Equals(aCodec)) { - return false; - } - // No scheme is specified, which means accepting all schemes. - if (!aPair.second || !aScheme) { - return true; - } - return aPair.second->contains(*aScheme); - }); - } + nsTArray mCodecsDecoded; + nsTArray mCodecsDecrypted; }; // Return true if given key system is supported on the current device. @@ -207,6 +154,7 @@ struct KeySystemConfig { mSessionTypes = aOther.mSessionTypes.Clone(); mVideoRobustness = aOther.mVideoRobustness.Clone(); mAudioRobustness = aOther.mAudioRobustness.Clone(); + mEncryptionSchemes = aOther.mEncryptionSchemes.Clone(); mMP4 = aOther.mMP4; mWebM = aOther.mWebM; } @@ -221,6 +169,7 @@ struct KeySystemConfig { mSessionTypes = aOther.mSessionTypes.Clone(); mVideoRobustness = aOther.mVideoRobustness.Clone(); mAudioRobustness = aOther.mAudioRobustness.Clone(); + mEncryptionSchemes = aOther.mEncryptionSchemes.Clone(); mMP4 = aOther.mMP4; mWebM = aOther.mWebM; return *this; @@ -237,6 +186,7 @@ struct KeySystemConfig { nsTArray mSessionTypes; nsTArray mVideoRobustness; nsTArray mAudioRobustness; + nsTArray mEncryptionSchemes; ContainerSupport mMP4; ContainerSupport mWebM; bool mIsHDCP22Compatible = false; diff --git a/dom/media/eme/MediaKeySystemAccess.cpp b/dom/media/eme/MediaKeySystemAccess.cpp index fa967e987fbf..106373579f06 100644 --- a/dom/media/eme/MediaKeySystemAccess.cpp +++ b/dom/media/eme/MediaKeySystemAccess.cpp @@ -319,18 +319,17 @@ static bool CanDecryptAndDecode( CodecType aCodecType, const KeySystemConfig::ContainerSupport& aContainerSupport, const nsTArray& aCodecs, - const Maybe& aScheme, DecoderDoctorDiagnostics* aDiagnostics) { MOZ_ASSERT(aCodecType != Invalid); for (const KeySystemConfig::EMECodecString& codec : aCodecs) { MOZ_ASSERT(!codec.IsEmpty()); - if (aContainerSupport.DecryptsAndDecodes(codec, aScheme)) { + if (aContainerSupport.DecryptsAndDecodes(codec)) { // GMP can decrypt-and-decode this codec. continue; } - if (aContainerSupport.Decrypts(codec, aScheme)) { + if (aContainerSupport.Decrypts(codec)) { IgnoredErrorResult rv; MediaSource::IsTypeSupported(aContentType, aDiagnostics, rv); if (!rv.Failed()) { @@ -362,18 +361,29 @@ static bool CanDecryptAndDecode( return true; } -// https://w3c.github.io/encrypted-media/#dom-mediakeysystemmediacapability-encryptionscheme -// This convert `encryptionScheme` to the type of CryptoScheme, so that we can -// further check whether the scheme is supported or not in our media pipeline. -Maybe ConvertEncryptionSchemeStrToScheme( - const nsString& aEncryptionScheme) { +// Returns if an encryption scheme is supported per: +// https://github.com/WICG/encrypted-media-encryption-scheme/blob/master/explainer.md +// To be supported the scheme should be one of: +// - null +// - missing (which will result in the nsString being set to void and thus null) +// - one of the schemes supported by the CDM +// If the pref to enable this behavior is not set, then the value should be +// empty/null, as the dict member will not be exposed. In this case we will +// always report support as we would before this feature was implemented. +static bool SupportsEncryptionScheme( + const nsString& aEncryptionScheme, + const nsTArray& aSupportedEncryptionSchemes) { + MOZ_ASSERT( + DOMStringIsNull(aEncryptionScheme) || + StaticPrefs::media_eme_encrypted_media_encryption_scheme_enabled(), + "Encryption scheme checking support must be preffed on for " + "encryptionScheme to be a non-null string"); if (DOMStringIsNull(aEncryptionScheme)) { // "A missing or null value indicates that any encryption scheme is // acceptable." - return Nothing(); + return true; } - auto scheme = StringToCryptoScheme(aEncryptionScheme); - return Some(scheme); + return aSupportedEncryptionSchemes.Contains(aEncryptionScheme); } static bool ToSessionType(const nsAString& aSessionType, @@ -468,8 +478,7 @@ static bool IsParameterUnrecognized(const nsAString& aContentType) { return false; } -// 3.2.2.3 Get Supported Capabilities for Audio/Video Type -// https://w3c.github.io/encrypted-media/#get-supported-capabilities-for-audio-video-type +// 3.1.1.3 Get Supported Capabilities for Audio/Video Type static Sequence GetSupportedCapabilities( const CodecType aCodecType, const nsTArray& aRequestedCapabilities, @@ -658,20 +667,6 @@ static Sequence GetSupportedCapabilities( NS_ConvertUTF16toUTF8(encryptionScheme).get()); continue; } - // If encryption scheme is non-null and is not recognized or not supported - // by implementation, continue to the next iteration. - const auto scheme = ConvertEncryptionSchemeStrToScheme(encryptionScheme); - if (scheme && *scheme == CryptoScheme::None) { - EME_LOG( - "MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s','%s') unsupported; " - "unsupported scheme string.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentTypeString).get(), - NS_ConvertUTF16toUTF8(robustness).get(), - NS_ConvertUTF16toUTF8(encryptionScheme).get()); - continue; - } // If robustness is not the empty string and contains an unrecognized // value or a value not supported by implementation, continue to the // next iteration. String comparison is case-sensitive. @@ -703,6 +698,22 @@ static Sequence GetSupportedCapabilities( // Note: specified robustness requirements are satisfied. } + // If preffed on: "In the Get Supported Capabilities for Audio/Video Type + // algorithm, implementations must skip capabilities specifying unsupported + // encryption schemes." + if (!SupportsEncryptionScheme(encryptionScheme, + aKeySystem.mEncryptionSchemes)) { + EME_LOG( + "MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s','%s') unsupported; " + "encryption scheme unsupported by CDM requested.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentTypeString).get(), + NS_ConvertUTF16toUTF8(robustness).get(), + NS_ConvertUTF16toUTF8(encryptionScheme).get()); + continue; + } + // If the user agent and implementation definitely support playback of // encrypted media data for the combination of container, media types, // robustness and local accumulated configuration in combination with @@ -710,7 +721,7 @@ static Sequence GetSupportedCapabilities( const auto& containerSupport = supportedInMP4 ? aKeySystem.mMP4 : aKeySystem.mWebM; if (!CanDecryptAndDecode(aKeySystem.mKeySystem, contentTypeString, - majorType, containerSupport, codecs, scheme, + majorType, containerSupport, codecs, aDiagnostics)) { EME_LOG( "MediaKeySystemConfiguration (label='%s') " diff --git a/dom/media/eme/mediafoundation/WMFCDMImpl.cpp b/dom/media/eme/mediafoundation/WMFCDMImpl.cpp index 3ef842312d0e..c30e353764ec 100644 --- a/dom/media/eme/mediafoundation/WMFCDMImpl.cpp +++ b/dom/media/eme/mediafoundation/WMFCDMImpl.cpp @@ -92,18 +92,16 @@ WMFCDMCapabilites::GetCapabilities( NS_ConvertUTF16toUTF8(capabilities.keySystem()).get(), capabilities.isHardwareDecryption()); for (const auto& v : capabilities.videoCapabilities()) { - for (const auto& scheme : v.encryptionSchemes()) { - EME_LOG("capabilities: video=%s, scheme=%s", - NS_ConvertUTF16toUTF8(v.contentType()).get(), - CryptoSchemeToString(scheme)); - } + EME_LOG("capabilities: video=%s", + NS_ConvertUTF16toUTF8(v.contentType()).get()); } for (const auto& a : capabilities.audioCapabilities()) { - for (const auto& scheme : a.encryptionSchemes()) { - EME_LOG("capabilities: audio=%s, scheme=%s", - NS_ConvertUTF16toUTF8(a.contentType()).get(), - CryptoSchemeToString(scheme)); - } + EME_LOG("capabilities: audio=%s", + NS_ConvertUTF16toUTF8(a.contentType()).get()); + } + for (const auto& v : capabilities.encryptionSchemes()) { + EME_LOG("capabilities: encryptionScheme=%s", + EncryptionSchemeStr(v)); } KeySystemConfig* config = outConfigs.AppendElement(); MFCDMCapabilitiesIPDLToKeySystemConfig(capabilities, *config); diff --git a/dom/media/eme/mediafoundation/WMFCDMProxy.cpp b/dom/media/eme/mediafoundation/WMFCDMProxy.cpp index 7f1a931bdee0..5fd73c2dcfaf 100644 --- a/dom/media/eme/mediafoundation/WMFCDMProxy.cpp +++ b/dom/media/eme/mediafoundation/WMFCDMProxy.cpp @@ -6,7 +6,6 @@ #include "WMFCDMProxy.h" -#include "MediaData.h" #include "mozilla/dom/MediaKeysBinding.h" #include "mozilla/dom/MediaKeySession.h" #include "mozilla/dom/MediaKeySystemAccessBinding.h" @@ -123,16 +122,12 @@ WMFCDMProxy::GenerateMFCDMMediaCapabilities( EME_LOG("WMFCDMProxy::Init %p, robustness=%s", this, NS_ConvertUTF16toUTF8(capabilities.mRobustness).get()); outCapabilites.AppendElement(MFCDMMediaCapability{ - capabilities.mContentType, - {StringToCryptoScheme(capabilities.mEncryptionScheme)}, - capabilities.mRobustness}); + capabilities.mContentType, capabilities.mRobustness}); } else { EME_LOG("WMFCDMProxy::Init %p, force to robustness=%s", this, NS_ConvertUTF16toUTF8(*forcedRobustness).get()); - outCapabilites.AppendElement(MFCDMMediaCapability{ - capabilities.mContentType, - {StringToCryptoScheme(capabilities.mEncryptionScheme)}, - *forcedRobustness}); + outCapabilites.AppendElement( + MFCDMMediaCapability{capabilities.mContentType, *forcedRobustness}); } } return outCapabilites; diff --git a/dom/media/gmp/ChromiumCDMParent.cpp b/dom/media/gmp/ChromiumCDMParent.cpp index d2cff5d4887e..b2465f611e98 100644 --- a/dom/media/gmp/ChromiumCDMParent.cpp +++ b/dom/media/gmp/ChromiumCDMParent.cpp @@ -341,7 +341,6 @@ bool ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, encryptionScheme = cdm::EncryptionScheme::kCenc; break; case CryptoScheme::Cbcs: - case CryptoScheme::Cbcs_1_9: encryptionScheme = cdm::EncryptionScheme::kCbcs; break; default: diff --git a/dom/media/ipc/MFCDMParent.cpp b/dom/media/ipc/MFCDMParent.cpp index 0ae93eb46f34..cd8d24f9053d 100644 --- a/dom/media/ipc/MFCDMParent.cpp +++ b/dom/media/ipc/MFCDMParent.cpp @@ -848,113 +848,27 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, KeySystemConfig::EME_CODEC_VP9, KeySystemConfig::EME_CODEC_HEVC, KeySystemConfig::EME_CODEC_AV1}); - // Collect schemes supported by all video codecs. - static nsTArray kSchemes({ - CryptoScheme::Cenc, - CryptoScheme::Cbcs, - }); - - // Remember supported video codecs, which will be used when collecting audio - // codec support. + // Remember supported video codecs. + // It will be used when collecting audio codec and encryption scheme + // support. nsTArray supportedVideoCodecs; - - if (aFlags.contains(CapabilitesFlag::NeedClearLeadCheck)) { - for (const auto& codec : kVideoCodecs) { - if (codec == KeySystemConfig::EME_CODEC_HEVC && - !StaticPrefs::media_wmf_hevc_enabled()) { - continue; - } - CryptoSchemeSet supportedScheme; - for (const auto& scheme : kSchemes) { - nsAutoString additionalFeature(u"encryption-type="); - // If we don't specify 'encryption-iv-size', it would use 8 bytes IV as - // default [1]. If it's not supported, then we will try 16 bytes later. - // Since PlayReady 4.0 [2], 8 and 16 bytes IV are both supported. But - // We're not sure if Widevine supports both or not. - // [1] - // https://learn.microsoft.com/en-us/windows/win32/api/mfmediaengine/nf-mfmediaengine-imfextendeddrmtypesupport-istypesupportedex - // [2] - // https://learn.microsoft.com/en-us/playready/packaging/content-encryption-modes#initialization-vectors-ivs - if (scheme == CryptoScheme::Cenc) { - additionalFeature.AppendLiteral(u"cenc-clearlead,"); - } else { - additionalFeature.AppendLiteral(u"cbcs-clearlead,"); - } - 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"); - if (rv) { - supportedScheme += scheme; - break; - } - // Try 16 bytes IV. - additionalFeature.AppendLiteral(u"encryption-iv-size=16,"); - rv = FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), - nsCString(""), additionalFeature, - isHardwareDecryption); - MFCDM_PARENT_SLOG("clearlead %s IV 16 bytes %s %s", - CryptoSchemeToString(scheme), codec.get(), - rv ? "supported" : "not supported"); - - if (rv) { - supportedScheme += scheme; - break; - } - } - // Add a capability if supported scheme exists - if (!supportedScheme.isEmpty()) { - MFCDMMediaCapability* c = - aCapabilitiesOut.videoCapabilities().AppendElement(); - c->contentType() = NS_ConvertUTF8toUTF16(codec); - c->robustness() = - GetRobustnessStringForKeySystem(aKeySystem, isHardwareDecryption); - if (supportedScheme.contains(CryptoScheme::Cenc)) { - c->encryptionSchemes().AppendElement(CryptoScheme::Cenc); - MFCDM_PARENT_SLOG("%s: +video:%s (cenc)", __func__, codec.get()); - } - if (supportedScheme.contains(CryptoScheme::Cbcs)) { - c->encryptionSchemes().AppendElement(CryptoScheme::Cbcs); - MFCDM_PARENT_SLOG("%s: +video:%s (cbcs)", __func__, codec.get()); - } - supportedVideoCodecs.AppendElement(codec); - } + for (const auto& codec : kVideoCodecs) { + if (codec == KeySystemConfig::EME_CODEC_HEVC && + !StaticPrefs::media_wmf_hevc_enabled()) { + continue; } - } else { - // Non clearlead situation for video codecs - for (const auto& codec : kVideoCodecs) { - if (codec == KeySystemConfig::EME_CODEC_HEVC && - !StaticPrefs::media_wmf_hevc_enabled()) { - continue; - } - if (FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), - KeySystemConfig::EMECodecString(""), nsString(u""), - isHardwareDecryption)) { - MFCDMMediaCapability* c = - aCapabilitiesOut.videoCapabilities().AppendElement(); - c->contentType() = NS_ConvertUTF8toUTF16(codec); - c->robustness() = - GetRobustnessStringForKeySystem(aKeySystem, isHardwareDecryption); - // '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 - c->encryptionSchemes().AppendElement(CryptoScheme::Cenc); - MFCDM_PARENT_SLOG("%s: +video:%s (cenc)", __func__, codec.get()); - // Check cbcs scheme support - if (FactorySupports( - factory, aKeySystem, convertCodecToFourCC(codec), - KeySystemConfig::EMECodecString(""), - nsString(u"encryption-type=cbcs,encryption-iv-size=16,"), - isHardwareDecryption)) { - c->encryptionSchemes().AppendElement(CryptoScheme::Cbcs); - MFCDM_PARENT_SLOG("%s: +video:%s (cbcs)", __func__, codec.get()); - } - supportedVideoCodecs.AppendElement(codec); - } + if (FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), + KeySystemConfig::EMECodecString(""), nsString(u""), + isHardwareDecryption)) { + MFCDMMediaCapability* c = + aCapabilitiesOut.videoCapabilities().AppendElement(); + c->contentType() = NS_ConvertUTF8toUTF16(codec); + c->robustness() = + GetRobustnessStringForKeySystem(aKeySystem, isHardwareDecryption); + MFCDM_PARENT_SLOG("%s: +video:%s", __func__, codec.get()); + supportedVideoCodecs.AppendElement(codec); } } - if (supportedVideoCodecs.IsEmpty()) { // Return a capabilities with no codec supported. return; @@ -980,11 +894,95 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem, c->contentType() = NS_ConvertUTF8toUTF16(codec); c->robustness() = GetRobustnessStringForKeySystem( aKeySystem, false /* aIsHWSecure */, false /* isVideo */); - c->encryptionSchemes().AppendElement(CryptoScheme::Cenc); MFCDM_PARENT_SLOG("%s: +audio:%s", __func__, codec.get()); } } + // '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__); + } + + // Check another scheme "cbcs" + static std::pair kCbcs = + std::pair( + 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; + } + } + 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 (aFlags.contains(CapabilitesFlag::NeedClearLeadCheck)) { + nsTArray noClearLeadCodecs; + for (const auto& codec : supportedVideoCodecs) { + bool foundSupportedScheme = false; + for (const auto& scheme : aCapabilitiesOut.encryptionSchemes()) { + nsAutoString additionalFeature(u"encryption-type="); + // If we don't specify 'encryption-iv-size', it would use 8 bytes IV as + // default [1]. If it's not supported, then we will try 16 bytes later. + // Since PlayReady 4.0 [2], 8 and 16 bytes IV are both supported. But + // We're not sure if Widevine supports both or not. + // [1] + // https://learn.microsoft.com/en-us/windows/win32/api/mfmediaengine/nf-mfmediaengine-imfextendeddrmtypesupport-istypesupportedex + // [2] + // https://learn.microsoft.com/en-us/playready/packaging/content-encryption-modes#initialization-vectors-ivs + if (scheme == CryptoScheme::Cenc) { + additionalFeature.AppendLiteral(u"cenc-clearlead,"); + } else { + additionalFeature.AppendLiteral(u"cbcs-clearlead,"); + } + 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"); + if (rv) { + foundSupportedScheme = true; + break; + } + // Try 16 bytes IV. + additionalFeature.AppendLiteral(u"encryption-iv-size=16,"); + rv = FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec), + nsCString(""), additionalFeature, + isHardwareDecryption); + MFCDM_PARENT_SLOG("clearlead %s IV 16 bytes %s %s", + CryptoSchemeToString(scheme), codec.get(), + rv ? "supported" : "not supported"); + + if (rv) { + foundSupportedScheme = true; + break; + } + } + // Failed on all schemes, add the codec to the list and remove it later. + if (!foundSupportedScheme) { + noClearLeadCodecs.AppendElement(codec); + } + } + for (const auto& codec : noClearLeadCodecs) { + MFCDM_PARENT_SLOG("%s: -video:%s", __func__, codec.get()); + aCapabilitiesOut.videoCapabilities().RemoveElementsBy( + [&codec](const MFCDMMediaCapability& aCapbilities) { + return aCapbilities.contentType() == NS_ConvertUTF8toUTF16(codec); + }); + supportedVideoCodecs.RemoveElement(codec); + } + } + // 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 diff --git a/dom/media/ipc/MFCDMSerializers.h b/dom/media/ipc/MFCDMSerializers.h index 00417bd58b2f..64867f4dbb73 100644 --- a/dom/media/ipc/MFCDMSerializers.h +++ b/dom/media/ipc/MFCDMSerializers.h @@ -29,9 +29,9 @@ struct ParamTraits template <> struct ParamTraits - : public ContiguousEnumSerializerInclusive< - mozilla::CryptoScheme, mozilla::CryptoScheme::None, - mozilla::CryptoScheme::Cbcs_1_9> {}; + : public ContiguousEnumSerializerInclusive {}; template <> struct ParamTraits diff --git a/dom/media/ipc/PMFCDM.ipdl b/dom/media/ipc/PMFCDM.ipdl index c9f68f187fe6..aa58679e7f0d 100644 --- a/dom/media/ipc/PMFCDM.ipdl +++ b/dom/media/ipc/PMFCDM.ipdl @@ -46,7 +46,6 @@ struct MFCDMKeyExpiration { // For GetCapabilities() struct MFCDMMediaCapability { nsString contentType; - CryptoScheme[] encryptionSchemes; nsString robustness; }; @@ -56,6 +55,7 @@ struct MFCDMCapabilitiesIPDL { MFCDMMediaCapability[] audioCapabilities; MFCDMMediaCapability[] videoCapabilities; SessionType[] sessionTypes; + CryptoScheme[] encryptionSchemes; Requirement distinctiveID; Requirement persistentState; bool? isHDCP22Compatible; diff --git a/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp b/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp index 2ee570633939..4c74fa8723c8 100644 --- a/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp +++ b/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp @@ -108,7 +108,6 @@ RefPtr ChromiumCDMVideoDecoder::Init() { config.mEncryptionScheme() = cdm::EncryptionScheme::kCenc; break; case CryptoScheme::Cbcs: - case CryptoScheme::Cbcs_1_9: config.mEncryptionScheme() = cdm::EncryptionScheme::kCbcs; break; default: diff --git a/dom/media/platforms/android/RemoteDataDecoder.cpp b/dom/media/platforms/android/RemoteDataDecoder.cpp index 72cce0974ac9..4653f3c80c80 100644 --- a/dom/media/platforms/android/RemoteDataDecoder.cpp +++ b/dom/media/platforms/android/RemoteDataDecoder.cpp @@ -967,9 +967,7 @@ static CryptoInfoResult GetCryptoInfoFromSample(const MediaRawData* aSample) { } static bool supportsCBCS = java::CodecProxy::SupportsCBCS(); - if ((cryptoObj.mCryptoScheme == CryptoScheme::Cbcs || - cryptoObj.mCryptoScheme == CryptoScheme::Cbcs_1_9) && - !supportsCBCS) { + if (cryptoObj.mCryptoScheme == CryptoScheme::Cbcs && !supportsCBCS) { return CryptoInfoResult(NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR); } @@ -1016,7 +1014,6 @@ static CryptoInfoResult GetCryptoInfoFromSample(const MediaRawData* aSample) { tempIV.AppendElements(cryptoObj.mIV); break; case CryptoScheme::Cbcs: - case CryptoScheme::Cbcs_1_9: mode = java::sdk::MediaCodec::CRYPTO_MODE_AES_CBC; MOZ_ASSERT(cryptoObj.mConstantIV.Length() <= kExpectedIVLength); tempIV.AppendElements(cryptoObj.mConstantIV); diff --git a/dom/media/platforms/wmf/MFMediaEngineStream.cpp b/dom/media/platforms/wmf/MFMediaEngineStream.cpp index cfd2769c98ce..5875b5a17ca1 100644 --- a/dom/media/platforms/wmf/MFMediaEngineStream.cpp +++ b/dom/media/platforms/wmf/MFMediaEngineStream.cpp @@ -400,8 +400,7 @@ HRESULT MFMediaEngineStream::AddEncryptAttributes( if (aCryptoConfig.mCryptoScheme == CryptoScheme::Cenc) { protectionScheme = MFSampleEncryptionProtectionScheme:: MF_SAMPLE_ENCRYPTION_PROTECTION_SCHEME_AES_CTR; - } else if (aCryptoConfig.mCryptoScheme == CryptoScheme::Cbcs || - aCryptoConfig.mCryptoScheme == CryptoScheme::Cbcs_1_9) { + } else if (aCryptoConfig.mCryptoScheme == CryptoScheme::Cbcs) { protectionScheme = MFSampleEncryptionProtectionScheme:: MF_SAMPLE_ENCRYPTION_PROTECTION_SCHEME_AES_CBC; } else { diff --git a/ipc/glue/UtilityAudioDecoderChild.cpp b/ipc/glue/UtilityAudioDecoderChild.cpp index 56db4b68bbb6..ec4692787096 100644 --- a/ipc/glue/UtilityAudioDecoderChild.cpp +++ b/ipc/glue/UtilityAudioDecoderChild.cpp @@ -222,18 +222,16 @@ void UtilityAudioDecoderChild::GetKeySystemCapabilities( EME_LOG("Received capabilities for %s", NS_ConvertUTF16toUTF8(capabilities.keySystem()).get()); for (const auto& v : capabilities.videoCapabilities()) { - for (const auto& scheme : v.encryptionSchemes()) { - EME_LOG(" capabilities: video=%s, scheme=%s", - NS_ConvertUTF16toUTF8(v.contentType()).get(), - CryptoSchemeToString(scheme)); - } + EME_LOG(" capabilities: video=%s", + NS_ConvertUTF16toUTF8(v.contentType()).get()); } for (const auto& a : capabilities.audioCapabilities()) { - for (const auto& scheme : a.encryptionSchemes()) { - EME_LOG(" capabilities: audio=%s, scheme=%s", - NS_ConvertUTF16toUTF8(a.contentType()).get(), - CryptoSchemeToString(scheme)); - } + EME_LOG(" capabilities: audio=%s", + NS_ConvertUTF16toUTF8(a.contentType()).get()); + } + for (const auto& e : capabilities.encryptionSchemes()) { + EME_LOG(" capabilities: encryptionScheme=%s", + EncryptionSchemeStr(e)); } auto* info = cdmInfo.AppendElement(fallible); if (!info) { diff --git a/toolkit/content/aboutSupport.js b/toolkit/content/aboutSupport.js index 282ab5b921e8..6b75776bd67d 100644 --- a/toolkit/content/aboutSupport.js +++ b/toolkit/content/aboutSupport.js @@ -1169,6 +1169,7 @@ var snapshotFormatters = { capabilities.persistent = findElementInArray(array, "persistent"); capabilities.distinctive = findElementInArray(array, "distinctive"); capabilities.sessionType = findElementInArray(array, "sessionType"); + capabilities.scheme = findElementInArray(array, "scheme"); capabilities.codec = getSupportedCodecs(array); return JSON.stringify(capabilities); }