Bug 1898588 - part1 : add encryptionSchemes in MFCDMMediaCapability in order to support scheme per type r=jolin
Currently our implementation is the scheme support per key system, not per content type. As each content type can have different supported scheme, eg. type A only supports cenc, but type B only supports cbcs, only having scheme per key system can't return a precise result. Differential Revision: https://phabricator.services.mozilla.com/D211642
This commit is contained in:
@@ -597,15 +597,26 @@ 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";
|
||||
return "cbcs";
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
CryptoScheme StringToCryptoScheme(const nsAString& aString) {
|
||||
if (aString.EqualsLiteral("cenc")) {
|
||||
return CryptoScheme::Cenc;
|
||||
}
|
||||
if (aString.EqualsLiteral("cbcs")) {
|
||||
return CryptoScheme::Cbcs;
|
||||
}
|
||||
// TODO : support cbcs-1-9?
|
||||
return CryptoScheme::None;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
# 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"
|
||||
@@ -586,8 +587,10 @@ enum class CryptoScheme : uint8_t {
|
||||
Cenc,
|
||||
Cbcs,
|
||||
};
|
||||
using CryptoSchemeSet = EnumSet<CryptoScheme, uint8_t>;
|
||||
|
||||
const char* CryptoSchemeToString(const CryptoScheme& aScheme);
|
||||
CryptoScheme StringToCryptoScheme(const nsAString& aString);
|
||||
|
||||
class CryptoTrack {
|
||||
public:
|
||||
|
||||
@@ -92,12 +92,18 @@ WMFCDMCapabilites::GetCapabilities(
|
||||
NS_ConvertUTF16toUTF8(capabilities.keySystem()).get(),
|
||||
capabilities.isHardwareDecryption());
|
||||
for (const auto& v : capabilities.videoCapabilities()) {
|
||||
EME_LOG("capabilities: video=%s",
|
||||
NS_ConvertUTF16toUTF8(v.contentType()).get());
|
||||
for (const auto& scheme : v.encryptionSchemes()) {
|
||||
EME_LOG("capabilities: video=%s, scheme=%s",
|
||||
NS_ConvertUTF16toUTF8(v.contentType()).get(),
|
||||
CryptoSchemeToString(scheme));
|
||||
}
|
||||
}
|
||||
for (const auto& a : capabilities.audioCapabilities()) {
|
||||
EME_LOG("capabilities: audio=%s",
|
||||
NS_ConvertUTF16toUTF8(a.contentType()).get());
|
||||
for (const auto& scheme : a.encryptionSchemes()) {
|
||||
EME_LOG("capabilities: audio=%s, scheme=%s",
|
||||
NS_ConvertUTF16toUTF8(a.contentType()).get(),
|
||||
CryptoSchemeToString(scheme));
|
||||
}
|
||||
}
|
||||
for (const auto& v : capabilities.encryptionSchemes()) {
|
||||
EME_LOG("capabilities: encryptionScheme=%s",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "WMFCDMProxy.h"
|
||||
|
||||
#include "MediaData.h"
|
||||
#include "mozilla/dom/MediaKeysBinding.h"
|
||||
#include "mozilla/dom/MediaKeySession.h"
|
||||
#include "mozilla/dom/MediaKeySystemAccessBinding.h"
|
||||
@@ -122,12 +123,16 @@ WMFCDMProxy::GenerateMFCDMMediaCapabilities(
|
||||
EME_LOG("WMFCDMProxy::Init %p, robustness=%s", this,
|
||||
NS_ConvertUTF16toUTF8(capabilities.mRobustness).get());
|
||||
outCapabilites.AppendElement(MFCDMMediaCapability{
|
||||
capabilities.mContentType, capabilities.mRobustness});
|
||||
capabilities.mContentType,
|
||||
{StringToCryptoScheme(capabilities.mEncryptionScheme)},
|
||||
capabilities.mRobustness});
|
||||
} else {
|
||||
EME_LOG("WMFCDMProxy::Init %p, force to robustness=%s", this,
|
||||
NS_ConvertUTF16toUTF8(*forcedRobustness).get());
|
||||
outCapabilites.AppendElement(
|
||||
MFCDMMediaCapability{capabilities.mContentType, *forcedRobustness});
|
||||
outCapabilites.AppendElement(MFCDMMediaCapability{
|
||||
capabilities.mContentType,
|
||||
{StringToCryptoScheme(capabilities.mEncryptionScheme)},
|
||||
*forcedRobustness});
|
||||
}
|
||||
}
|
||||
return outCapabilites;
|
||||
|
||||
@@ -848,27 +848,115 @@ 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<CryptoScheme> kSchemes({
|
||||
CryptoScheme::Cenc,
|
||||
CryptoScheme::Cbcs,
|
||||
});
|
||||
|
||||
// Remember supported video codecs.
|
||||
// It will be used when collecting audio codec and encryption scheme
|
||||
// support.
|
||||
// TODO : scheme part should be removed later
|
||||
nsTArray<KeySystemConfig::EMECodecString> supportedVideoCodecs;
|
||||
for (const auto& codec : kVideoCodecs) {
|
||||
if (codec == KeySystemConfig::EME_CODEC_HEVC &&
|
||||
!StaticPrefs::media_wmf_hevc_enabled()) {
|
||||
continue;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
} 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 (supportedVideoCodecs.IsEmpty()) {
|
||||
// Return a capabilities with no codec supported.
|
||||
return;
|
||||
@@ -894,6 +982,7 @@ 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());
|
||||
}
|
||||
}
|
||||
@@ -923,66 +1012,6 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
|
||||
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<KeySystemConfig::EMECodecString> 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
|
||||
|
||||
@@ -46,6 +46,7 @@ struct MFCDMKeyExpiration {
|
||||
// For GetCapabilities()
|
||||
struct MFCDMMediaCapability {
|
||||
nsString contentType;
|
||||
CryptoScheme[] encryptionSchemes;
|
||||
nsString robustness;
|
||||
};
|
||||
|
||||
|
||||
@@ -222,12 +222,18 @@ void UtilityAudioDecoderChild::GetKeySystemCapabilities(
|
||||
EME_LOG("Received capabilities for %s",
|
||||
NS_ConvertUTF16toUTF8(capabilities.keySystem()).get());
|
||||
for (const auto& v : capabilities.videoCapabilities()) {
|
||||
EME_LOG(" capabilities: video=%s",
|
||||
NS_ConvertUTF16toUTF8(v.contentType()).get());
|
||||
for (const auto& scheme : v.encryptionSchemes()) {
|
||||
EME_LOG(" capabilities: video=%s, scheme=%s",
|
||||
NS_ConvertUTF16toUTF8(v.contentType()).get(),
|
||||
CryptoSchemeToString(scheme));
|
||||
}
|
||||
}
|
||||
for (const auto& a : capabilities.audioCapabilities()) {
|
||||
EME_LOG(" capabilities: audio=%s",
|
||||
NS_ConvertUTF16toUTF8(a.contentType()).get());
|
||||
for (const auto& scheme : a.encryptionSchemes()) {
|
||||
EME_LOG(" capabilities: audio=%s, scheme=%s",
|
||||
NS_ConvertUTF16toUTF8(a.contentType()).get(),
|
||||
CryptoSchemeToString(scheme));
|
||||
}
|
||||
}
|
||||
for (const auto& e : capabilities.encryptionSchemes()) {
|
||||
EME_LOG(" capabilities: encryptionScheme=%s",
|
||||
|
||||
Reference in New Issue
Block a user