Bug 1257716 - Handle clearkey encrypted WebMs. r=cpearce
Handle encrypted WebM streams for the clearkey case. Add checking for the
widevine case, though these should currently fail, as not all of the plumping
is in place for widevine.
MozReview-Commit-ID: 5d9fvc5IkZF
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -335,17 +335,17 @@ MediaFormatReader::OnDemuxerInitDone(nsr
mIsEncrypted = crypto && crypto->IsEncrypted();
if (mDecoder && crypto && crypto->IsEncrypted()) {
#ifdef MOZ_EME
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
NS_DispatchToMainThread(
- new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, NS_LITERAL_STRING("cenc")));
+ new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType));
}
#endif // MOZ_EME
mInfo.mCrypto = *crypto;
}
int64_t videoDuration = HasVideo() ? mInfo.mVideo.mDuration : 0;
int64_t audioDuration = HasAudio() ? mInfo.mAudio.mDuration : 0;
--- a/dom/media/VideoUtils.cpp
+++ b/dom/media/VideoUtils.cpp
@@ -485,9 +485,46 @@ IsAACContentType(const nsAString& aConte
},
[](const nsAString& codec) {
return codec.EqualsLiteral("mp4a.40.2") || // MPEG4 AAC-LC
codec.EqualsLiteral("mp4a.40.5") || // MPEG4 HE-AAC
codec.EqualsLiteral("mp4a.67"); // MPEG2 AAC-LC
});
}
+bool
+IsVorbisContentType(const nsAString& aContentType)
+{
+ return CheckContentType(aContentType,
+ [](const nsAString& type) {
+ return type.EqualsLiteral("audio/webm") ||
+ type.EqualsLiteral("audio/ogg");
+ },
+ [](const nsAString& codec) {
+ return codec.EqualsLiteral("vorbis");
+ });
+}
+
+bool
+IsVP8ContentType(const nsAString& aContentType)
+{
+ return CheckContentType(aContentType,
+ [](const nsAString& type) {
+ return type.EqualsLiteral("video/webm");
+ },
+ [](const nsAString& codec) {
+ return codec.EqualsLiteral("vp8");
+ });
+}
+
+bool
+IsVP9ContentType(const nsAString& aContentType)
+{
+ return CheckContentType(aContentType,
+ [](const nsAString& type) {
+ return type.EqualsLiteral("video/webm");
+ },
+ [](const nsAString& codec) {
+ return codec.EqualsLiteral("vp9");
+ });
+}
+
} // end namespace mozilla
--- a/dom/media/VideoUtils.h
+++ b/dom/media/VideoUtils.h
@@ -442,11 +442,20 @@ StringListContains(const ListString& aLi
for (const auto& listItem : MakeStringListRange(aList)) {
if (listItem.Equals(aItem)) {
return true;
}
}
return false;
}
+bool
+IsVorbisContentType(const nsAString& aContentType);
+
+bool
+IsVP8ContentType(const nsAString& aContentType);
+
+bool
+IsVP9ContentType(const nsAString& aContentType);
+
} // end namespace mozilla
#endif
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -30,16 +30,17 @@
#include "GMPUtils.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsXULAppAPI.h"
#include "gmp-audio-decode.h"
#include "gmp-video-decode.h"
#include "DecoderDoctorDiagnostics.h"
+#include "WebMDecoder.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess,
mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
@@ -407,35 +408,100 @@ GMPDecryptsAndGeckoDecodesAAC(mozIGeckoM
}
return false;
}
#endif
return MP4Decoder::CanHandleMediaType(aContentType, aDiagnostics);
}
static bool
+GMPDecryptsAndGeckoDecodesVorbis(mozIGeckoMediaPluginService* aGMPService,
+ const nsAString& aKeySystem,
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ MOZ_ASSERT(IsVorbisContentType(aContentType));
+ return !HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
+ NS_LITERAL_CSTRING("vorbis")) &&
+ WebMDecoder::CanHandleMediaType(aContentType);
+}
+
+static bool
+GMPDecryptsAndGeckoDecodesVP8(mozIGeckoMediaPluginService* aGMPService,
+ const nsAString& aKeySystem,
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ MOZ_ASSERT(IsVP8ContentType(aContentType));
+ return !HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp8")) &&
+ WebMDecoder::CanHandleMediaType(aContentType);
+}
+
+static bool
+GMPDecryptsAndGeckoDecodesVP9(mozIGeckoMediaPluginService* aGMPService,
+ const nsAString& aKeySystem,
+ const nsAString& aContentType,
+ DecoderDoctorDiagnostics* aDiagnostics)
+{
+ MOZ_ASSERT(HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
+ MOZ_ASSERT(IsVP9ContentType(aContentType));
+ return !HaveGMPFor(aGMPService,
+ NS_ConvertUTF16toUTF8(aKeySystem),
+ NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
+ NS_LITERAL_CSTRING("vp9")) &&
+ WebMDecoder::CanHandleMediaType(aContentType);
+}
+
+static bool
IsSupportedAudio(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const nsAString& aAudioType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- return IsAACContentType(aAudioType) &&
- (GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem, aDiagnostics) ||
- GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aAudioType, aDiagnostics));
+ if (IsAACContentType(aAudioType)) {
+ return GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aAudioType, aDiagnostics);
+ }
+ if (IsVorbisContentType(aAudioType) && aKeySystem.EqualsLiteral("org.w3.clearkey")) {
+ // GMP does not decode Vorbis, so don't bother checking
+ return GMPDecryptsAndGeckoDecodesVorbis(aGMPService, aKeySystem, aAudioType, aDiagnostics);
+ }
+ return false;
}
static bool
IsSupportedVideo(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const nsAString& aVideoType,
DecoderDoctorDiagnostics* aDiagnostics)
{
- return IsH264ContentType(aVideoType) &&
- (GMPDecryptsAndDecodesH264(aGMPService, aKeySystem, aDiagnostics) ||
- GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aVideoType, aDiagnostics));
+ if (IsH264ContentType(aVideoType)) {
+ return GMPDecryptsAndDecodesH264(aGMPService, aKeySystem, aDiagnostics) ||
+ GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aVideoType, aDiagnostics);
+ }
+ if (IsVP8ContentType(aVideoType) && aKeySystem.EqualsLiteral("org.w3.clearkey")) {
+ return GMPDecryptsAndGeckoDecodesVP8(aGMPService, aKeySystem, aVideoType, aDiagnostics);
+ }
+ if (IsVP9ContentType(aVideoType) && aKeySystem.EqualsLiteral("org.w3.clearkey")) {
+ return GMPDecryptsAndGeckoDecodesVP9(aGMPService, aKeySystem, aVideoType, aDiagnostics);
+ }
+ return false;
}
static bool
IsSupported(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const MediaKeySystemConfiguration& aConfig,
DecoderDoctorDiagnostics* aDiagnostics)
{
@@ -469,17 +535,17 @@ IsSupportedInitDataType(const nsString&
// All supported keySystems can handle "cenc" initDataType.
// ClearKey also supports "keyids" and "webm" initDataTypes.
return aCandidate.EqualsLiteral("cenc") ||
((aKeySystem.EqualsLiteral("org.w3.clearkey")
#ifdef MOZ_WIDEVINE_EME
|| aKeySystem.EqualsLiteral("com.widevine.alpha")
#endif
) &&
- (aCandidate.EqualsLiteral("keyids") || aCandidate.EqualsLiteral("webm)")));
+ (aCandidate.EqualsLiteral("keyids") || aCandidate.EqualsLiteral("webm")));
}
static bool
GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const MediaKeySystemConfiguration& aCandidate,
MediaKeySystemConfiguration& aOutConfig,
DecoderDoctorDiagnostics* aDiagnostics)
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -1045,17 +1045,18 @@ TrackBuffersManager::OnDemuxerInitDone(n
}
UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto();
if (crypto && crypto->IsEncrypted()) {
#ifdef MOZ_EME
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
NS_DispatchToMainThread(
- new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData, NS_LITERAL_STRING("cenc")));
+ new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData,
+ crypto->mInitDatas[i].mType));
}
#endif // MOZ_EME
info.mCrypto = *crypto;
// We clear our crypto init data array, so the MediaFormatReader will
// not emit an encrypted event for the same init data again.
info.mCrypto.mInitDatas.Clear();
mEncrypted = true;
}