Bug 1207019 - Remove WMF availability check in MediaKeySystemAccess requests. r=edwin

This commit is contained in:
Chris Pearce 2015-10-05 15:03:48 +13:00
Родитель 93999bd66d
Коммит d4ed7efef9
6 изменённых файлов: 224 добавлений и 79 удалений

Просмотреть файл

@ -567,7 +567,7 @@ nsresult ChannelMediaResource::OpenChannel(nsIStreamListener** aStreamListener)
rv = mChannel->AsyncOpen2(mListener);
NS_ENSURE_SUCCESS(rv, rv);
// Tell the media element that we are fetching data from a channel.
MediaDecoderOwner* owner = mDecoder->GetMediaOwner();
NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE);

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/Base64.h"
#include "mozilla/TaskQueue.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Function.h"
#include "MediaResource.h"
#include "TimeUnits.h"
@ -21,6 +22,8 @@
#include "nsServiceManagerUtils.h"
#include "nsIConsoleService.h"
#include "nsThreadUtils.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsContentTypeParser.h"
#include <stdint.h>
@ -466,4 +469,78 @@ LogToBrowserConsole(const nsAString& aMsg)
console->LogStringMessage(msg.get());
}
bool
ParseCodecsString(const nsAString& aCodecs, nsTArray<nsString>& aOutCodecs)
{
aOutCodecs.Clear();
bool expectMoreTokens = false;
nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
while (tokenizer.hasMoreTokens()) {
const nsSubstring& token = tokenizer.nextToken();
expectMoreTokens = tokenizer.separatorAfterCurrentToken();
aOutCodecs.AppendElement(token);
}
if (expectMoreTokens) {
// Last codec name was empty
return false;
}
return true;
}
static bool
CheckContentType(const nsAString& aContentType,
mozilla::Function<bool(const nsAString&)> aSubtypeFilter,
mozilla::Function<bool(const nsAString&)> aCodecFilter)
{
nsContentTypeParser parser(aContentType);
nsAutoString mimeType;
nsresult rv = parser.GetType(mimeType);
if (NS_FAILED(rv) || !aSubtypeFilter(mimeType)) {
return false;
}
nsString codecsStr;
parser.GetParameter("codecs", codecsStr);
nsTArray<nsString> codecs;
if (!ParseCodecsString(codecsStr, codecs)) {
return false;
}
for (const nsString& codec : codecs) {
if (!aCodecFilter(codec)) {
return false;
}
}
return true;
}
bool
IsH264ContentType(const nsAString& aContentType)
{
return CheckContentType(aContentType,
[](const nsAString& type) {
return type.EqualsLiteral("video/mp4");
},
[](const nsAString& codec) {
int16_t profile = 0;
int16_t level = 0;
return ExtractH264CodecDetails(codec, profile, level);
}
);
}
bool
IsAACContentType(const nsAString& aContentType)
{
return CheckContentType(aContentType,
[](const nsAString& type) {
return type.EqualsLiteral("audio/mp4") ||
type.EqualsLiteral("audio/x-m4a");
},
[](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
});
}
} // end namespace mozilla

Просмотреть файл

@ -329,6 +329,15 @@ private:
void
LogToBrowserConsole(const nsAString& aMsg);
bool
ParseCodecsString(const nsAString& aCodecs, nsTArray<nsString>& aOutCodecs);
bool
IsH264ContentType(const nsAString& aContentType);
bool
IsAACContentType(const nsAString& aContentType);
} // end namespace mozilla
#endif

Просмотреть файл

@ -31,6 +31,8 @@
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsXULAppAPI.h"
#include "gmp-audio-decode.h"
#include "gmp-video-decode.h"
#if defined(XP_WIN) || defined(XP_MACOSX)
#define PRIMETIME_EME_SUPPORTED 1
@ -297,52 +299,107 @@ MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
}
static bool
IsPlayableWithGMP(mozIGeckoMediaPluginService* aGMPS,
const nsAString& aKeySystem,
const nsAString& aContentType)
GMPDecryptsAndDecodesAAC(mozIGeckoMediaPluginService* aGMPS,
const nsAString& aKeySystem)
{
#ifdef MOZ_FMP4
nsContentTypeParser parser(aContentType);
nsAutoString mimeType;
nsresult rv = parser.GetType(mimeType);
if (NS_FAILED(rv)) {
return false;
}
MOZ_ASSERT(HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
return HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
NS_LITERAL_CSTRING("aac"));
}
if (!mimeType.EqualsLiteral("audio/mp4") &&
!mimeType.EqualsLiteral("audio/x-m4a") &&
!mimeType.EqualsLiteral("video/mp4")) {
return false;
}
static bool
GMPDecryptsAndDecodesH264(mozIGeckoMediaPluginService* aGMPS,
const nsAString& aKeySystem)
{
MOZ_ASSERT(HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
return HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
NS_LITERAL_CSTRING("aac"));
}
nsAutoString codecs;
parser.GetParameter("codecs", codecs);
NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
bool hasAAC = false;
bool hasH264 = false;
bool hasMP3 = false;
if (!MP4Decoder::CanHandleMediaType(mimeTypeUTF8,
codecs,
hasAAC,
hasH264,
hasMP3) ||
hasMP3) {
return false;
}
return (!hasAAC ||
!HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
NS_LITERAL_CSTRING("aac"))) &&
(!hasH264 ||
!HaveGMPFor(aGMPS,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
NS_LITERAL_CSTRING("h264")));
#else
return false;
// If this keysystem's CDM explicitly says it doesn't support decoding,
// that means it's OK with passing the decrypted samples back to Gecko
// for decoding. Note we special case Clearkey on Windows, where we need
// to check for whether WMF is usable because the CDM uses that
// to decode.
static bool
GMPDecryptsAndGeckoDecodesH264(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const nsAString& aContentType)
{
MOZ_ASSERT(HaveGMPFor(aGMPService,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
MOZ_ASSERT(IsH264ContentType(aContentType));
return
(!HaveGMPFor(aGMPService,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER),
NS_LITERAL_CSTRING("h264"))
#ifdef XP_WIN
// Clearkey on Windows XP can't decode, but advertises that it can
// in its GMP info file.
|| (aKeySystem.EqualsLiteral("org.w3.clearkey") && !IsVistaOrLater())
#endif
) && MP4Decoder::CanHandleMediaType(aContentType);
}
static bool
GMPDecryptsAndGeckoDecodesAAC(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const nsAString& aContentType)
{
MOZ_ASSERT(HaveGMPFor(aGMPService,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
MOZ_ASSERT(IsAACContentType(aContentType));
return
(!HaveGMPFor(aGMPService,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
NS_LITERAL_CSTRING("aac"))
#ifdef XP_WIN
// Clearkey on Windows XP can't decode, but advertises that it can
// in its GMP info file.
|| (aKeySystem.EqualsLiteral("org.w3.clearkey") && !IsVistaOrLater())
#endif
) && MP4Decoder::CanHandleMediaType(aContentType);
}
static bool
IsSupported(mozIGeckoMediaPluginService* aGMPService,
const nsAString& aKeySystem,
const MediaKeySystemOptions& aConfig)
{
if (!aConfig.mInitDataType.EqualsLiteral("cenc")) {
return false;
}
if (!aConfig.mAudioCapability.IsEmpty() ||
!aConfig.mVideoCapability.IsEmpty()) {
// Don't support any capabilities until we know we have a CDM with
// capabilities...
return false;
}
if (!aConfig.mAudioType.IsEmpty() &&
(!IsAACContentType(aConfig.mAudioType) ||
(!GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem) &&
!GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aConfig.mAudioType)))) {
return false;
}
if (!aConfig.mVideoType.IsEmpty() &&
(!IsH264ContentType(aConfig.mVideoType) ||
(!GMPDecryptsAndDecodesH264(aGMPService, aKeySystem) &&
!GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aConfig.mVideoType)))) {
return false;
}
return true;
}
/* static */
@ -356,32 +413,16 @@ MediaKeySystemAccess::IsSupported(const nsAString& aKeySystem,
return false;
}
for (size_t i = 0; i < aOptions.Length(); i++) {
const MediaKeySystemOptions& options = aOptions[i];
if (!options.mInitDataType.EqualsLiteral("cenc")) {
continue;
}
if (!options.mAudioCapability.IsEmpty() ||
!options.mVideoCapability.IsEmpty()) {
// Don't support any capabilites until we know we have a CDM with
// capabilities...
continue;
}
if (!options.mAudioType.IsEmpty() &&
!IsPlayableWithGMP(mps, aKeySystem, options.mAudioType)) {
continue;
}
if (!options.mVideoType.IsEmpty() &&
!IsPlayableWithGMP(mps, aKeySystem, options.mVideoType)) {
continue;
}
if (!HaveGMPFor(mps,
NS_ConvertUTF16toUTF8(aKeySystem),
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
return false;
}
// Our sandbox provides an origin specific unique identifier, and the
// ability to persist data. We don't yet have a way to turn those off
// and on for specific GMPs/CDMs, so we don't check the uniqueidentifier
// and stateful attributes here.
return true;
for (const MediaKeySystemOptions& config : aOptions) {
if (mozilla::dom::IsSupported(mps, aKeySystem, config)) {
return true;
}
}
return false;
}

Просмотреть файл

@ -15,6 +15,7 @@
#endif
#include "mozilla/Logging.h"
#include "nsMimeTypes.h"
#include "nsContentTypeParser.h"
#ifdef XP_WIN
#include "mozilla/WindowsVersion.h"
@ -139,30 +140,45 @@ MP4Decoder::CanHandleMediaType(const nsACString& aType,
// Verify that all the codecs specifed are ones that we expect that
// we can play.
nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
bool expectMoreTokens = false;
while (tokenizer.hasMoreTokens()) {
const nsSubstring& token = tokenizer.nextToken();
expectMoreTokens = tokenizer.separatorAfterCurrentToken();
if (IsSupportedAudioCodec(token,
nsTArray<nsString> codecs;
if (!ParseCodecsString(aCodecs, codecs)) {
return false;
}
for (const nsString& codec : codecs) {
if (IsSupportedAudioCodec(codec,
aOutContainsAAC,
aOutContainsMP3)) {
continue;
}
if (IsSupportedH264Codec(token)) {
if (IsSupportedH264Codec(codec)) {
aOutContainsH264 = true;
continue;
}
return false;
}
if (expectMoreTokens) {
// Last codec name was empty
// Some unsupported codec.
return false;
}
return true;
}
/* static */ bool
MP4Decoder::CanHandleMediaType(const nsAString& aContentType)
{
nsContentTypeParser parser(aContentType);
nsAutoString mimeType;
nsresult rv = parser.GetType(mimeType);
if (NS_FAILED(rv)) {
return false;
}
nsString codecs;
parser.GetParameter("codecs", codecs);
bool ignoreAAC, ignoreH264, ignoreMP3;
return CanHandleMediaType(NS_ConvertUTF16toUTF8(mimeType),
codecs,
ignoreAAC, ignoreH264, ignoreMP3);
}
static bool
IsFFmpegAvailable()
{

Просмотреть файл

@ -35,6 +35,8 @@ public:
bool& aOutContainsH264,
bool& aOutContainsMP3);
static bool CanHandleMediaType(const nsAString& aMIMEType);
// Returns true if the MP4 backend is preffed on.
static bool IsEnabled();