mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1067216 - Make MediaKeys.isTypeSupported() more accurate. r=edwin,jesup
This commit is contained in:
parent
5ac2fe1151
commit
d0653badc3
@ -16,9 +16,16 @@
|
|||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsIScriptObjectPrincipal.h"
|
#include "nsIScriptObjectPrincipal.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
#include "nsContentTypeParser.h"
|
||||||
|
#ifdef MOZ_FMP4
|
||||||
|
#include "MP4Decoder.h"
|
||||||
|
#endif
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
#include "mozilla/WindowsVersion.h"
|
#include "mozilla/WindowsVersion.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "nsContentCID.h"
|
||||||
|
#include "nsServiceManagerUtils.h"
|
||||||
|
#include "mozIGeckoMediaPluginService.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
@ -107,15 +114,86 @@ MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, Error
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
IsSupportedKeySystem(const nsAString& aKeySystem)
|
HaveGMPFor(const nsCString& aKeySystem,
|
||||||
|
const nsCString& aAPI,
|
||||||
|
const nsCString& aTag = EmptyCString())
|
||||||
{
|
{
|
||||||
return aKeySystem.EqualsASCII("org.w3.clearkey") ||
|
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||||
#ifdef XP_WIN
|
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||||
(aKeySystem.EqualsASCII("com.adobe.access") &&
|
if (NS_WARN_IF(!mps)) {
|
||||||
IsVistaOrLater() &&
|
return false;
|
||||||
Preferences::GetBool("media.eme.adobe-access.enabled", false)) ||
|
}
|
||||||
|
|
||||||
|
nsTArray<nsCString> tags;
|
||||||
|
tags.AppendElement(aKeySystem);
|
||||||
|
if (!aTag.IsEmpty()) {
|
||||||
|
tags.AppendElement(aTag);
|
||||||
|
}
|
||||||
|
// Note: EME plugins need a non-null nodeId here, as they must
|
||||||
|
// not be shared across origins.
|
||||||
|
bool hasPlugin = false;
|
||||||
|
if (NS_FAILED(mps->HasPluginForAPI(aAPI,
|
||||||
|
&tags,
|
||||||
|
&hasPlugin))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return hasPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsPlayableMP4Type(const nsAString& aContentType)
|
||||||
|
{
|
||||||
|
#ifdef MOZ_FMP4
|
||||||
|
nsContentTypeParser parser(aContentType);
|
||||||
|
nsAutoString mimeType;
|
||||||
|
nsresult rv = parser.GetType(mimeType);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nsAutoString codecs;
|
||||||
|
parser.GetParameter("codecs", codecs);
|
||||||
|
|
||||||
|
NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
|
||||||
|
return MP4Decoder::CanHandleMediaType(mimeTypeUTF8, codecs);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
false;
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MediaKeys::IsTypeSupported(const nsAString& aKeySystem,
|
||||||
|
const Optional<nsAString>& aInitDataType,
|
||||||
|
const Optional<nsAString>& aContentType)
|
||||||
|
{
|
||||||
|
if (aKeySystem.EqualsLiteral("org.w3.clearkey") &&
|
||||||
|
(!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
|
||||||
|
(!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
|
||||||
|
HaveGMPFor(NS_LITERAL_CSTRING("org.w3.clearkey"),
|
||||||
|
NS_LITERAL_CSTRING("eme-decrypt"))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef XP_WIN
|
||||||
|
// Note: Adobe Access's GMP uses WMF to decode, so anything our MP4Reader
|
||||||
|
// thinks it can play on Windows, the Access GMP should be able to play.
|
||||||
|
if (aKeySystem.EqualsLiteral("com.adobe.access") &&
|
||||||
|
Preferences::GetBool("media.eme.adobe-access.enabled", false) &&
|
||||||
|
IsVistaOrLater() && // Win Vista and later only.
|
||||||
|
(!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
|
||||||
|
(!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
|
||||||
|
HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
|
||||||
|
NS_LITERAL_CSTRING("eme-decrypt")) &&
|
||||||
|
HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
|
||||||
|
NS_LITERAL_CSTRING("decode-video"),
|
||||||
|
NS_LITERAL_CSTRING("h264")) &&
|
||||||
|
HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
|
||||||
|
NS_LITERAL_CSTRING("decode-audio"),
|
||||||
|
NS_LITERAL_CSTRING("aac"))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
@ -128,8 +206,16 @@ MediaKeys::IsTypeSupported(const GlobalObject& aGlobal,
|
|||||||
{
|
{
|
||||||
// TODO: Should really get spec changed to this is async, so we can wait
|
// TODO: Should really get spec changed to this is async, so we can wait
|
||||||
// for user to consent to running plugin.
|
// for user to consent to running plugin.
|
||||||
return IsSupportedKeySystem(aKeySystem) ? IsTypeSupportedResult::Maybe
|
bool supported = IsTypeSupported(aKeySystem, aInitDataType, aContentType);
|
||||||
: IsTypeSupportedResult::_empty;
|
|
||||||
|
EME_LOG("MediaKeys::IsTypeSupported keySystem='%s' initDataType='%s' contentType='%s' supported=%d",
|
||||||
|
NS_ConvertUTF16toUTF8(aKeySystem).get(),
|
||||||
|
(aInitDataType.WasPassed() ? NS_ConvertUTF16toUTF8(aInitDataType.Value()).get() : ""),
|
||||||
|
(aContentType.WasPassed() ? NS_ConvertUTF16toUTF8(aContentType.Value()).get() : ""),
|
||||||
|
supported);
|
||||||
|
|
||||||
|
return supported ? IsTypeSupportedResult::Probably
|
||||||
|
: IsTypeSupportedResult::_empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
@ -242,7 +328,7 @@ MediaKeys::Init(ErrorResult& aRv)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsSupportedKeySystem(mKeySystem)) {
|
if (!IsTypeSupported(mKeySystem)) {
|
||||||
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
@ -271,7 +357,7 @@ MediaKeys::Init(ErrorResult& aRv)
|
|||||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
|
mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
|
||||||
|
|
||||||
if (!mPrincipal || !mTopLevelPrincipal) {
|
if (!mPrincipal || !mTopLevelPrincipal) {
|
||||||
|
@ -124,6 +124,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
static bool IsTypeSupported(const nsAString& aKeySystem,
|
||||||
|
const Optional<nsAString>& aInitDataType = Optional<nsAString>(),
|
||||||
|
const Optional<nsAString>& aContentType = Optional<nsAString>());
|
||||||
|
|
||||||
bool IsInPrivateBrowsing();
|
bool IsInPrivateBrowsing();
|
||||||
already_AddRefed<Promise> Init(ErrorResult& aRv);
|
already_AddRefed<Promise> Init(ErrorResult& aRv);
|
||||||
|
|
||||||
|
@ -143,6 +143,7 @@ GeckoMediaPluginService::GeckoMediaPluginService()
|
|||||||
: mMutex("GeckoMediaPluginService::mMutex")
|
: mMutex("GeckoMediaPluginService::mMutex")
|
||||||
, mShuttingDown(false)
|
, mShuttingDown(false)
|
||||||
, mShuttingDownOnGMPThread(false)
|
, mShuttingDownOnGMPThread(false)
|
||||||
|
, mScannedPluginOnDisk(false)
|
||||||
, mWaitingForPluginsAsyncShutdown(false)
|
, mWaitingForPluginsAsyncShutdown(false)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
@ -590,7 +591,7 @@ GeckoMediaPluginService::UnloadPlugins()
|
|||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
// Note: CloseActive is async; it will actually finish
|
// Note: CloseActive is async; it will actually finish
|
||||||
// shutting down when all the plugins have unloaded.
|
// shutting down when all the plugins have unloaded.
|
||||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
for (size_t i = 0; i < mPlugins.Length(); i++) {
|
||||||
mPlugins[i]->CloseActive(true);
|
mPlugins[i]->CloseActive(true);
|
||||||
}
|
}
|
||||||
mPlugins.Clear();
|
mPlugins.Clear();
|
||||||
@ -619,7 +620,7 @@ GeckoMediaPluginService::CrashPlugins()
|
|||||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||||
|
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
for (size_t i = 0; i < mPlugins.Length(); i++) {
|
||||||
mPlugins[i]->Crash();
|
mPlugins[i]->Crash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -652,6 +653,8 @@ GeckoMediaPluginService::LoadFromEnvironment()
|
|||||||
pos = next + 1;
|
pos = next + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mScannedPluginOnDisk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
@ -693,47 +696,88 @@ GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DummyRunnable : public nsRunnable {
|
||||||
|
public:
|
||||||
|
NS_IMETHOD Run() { return NS_OK; }
|
||||||
|
};
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
GeckoMediaPluginService::HasPluginForAPI(const nsACString& aNodeId,
|
GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
|
||||||
const nsACString& aAPI,
|
|
||||||
nsTArray<nsCString>* aTags,
|
nsTArray<nsCString>* aTags,
|
||||||
bool* aResult)
|
bool* aResult)
|
||||||
{
|
{
|
||||||
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
|
||||||
NS_ENSURE_ARG(aResult);
|
NS_ENSURE_ARG(aResult);
|
||||||
|
|
||||||
nsCString temp(aAPI);
|
const char* env = nullptr;
|
||||||
GMPParent *parent = SelectPluginForAPI(aNodeId, temp, *aTags, false);
|
if (!mScannedPluginOnDisk && (env = PR_GetEnv("MOZ_GMP_PATH")) && *env) {
|
||||||
*aResult = !!parent;
|
// We have a MOZ_GMP_PATH environment variable which may specify the
|
||||||
|
// location of plugins to load, and we haven't yet scanned the disk to
|
||||||
|
// see if there are plugins there. Get the GMP thread, which will
|
||||||
|
// cause an event to be dispatched to which scans for plugins. We
|
||||||
|
// dispatch a sync event to the GMP thread here in order to wait until
|
||||||
|
// after the GMP thread has scanned any paths in MOZ_GMP_PATH.
|
||||||
|
nsCOMPtr<nsIThread> thread;
|
||||||
|
nsresult rv = GetThread(getter_AddRefs(thread));
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
thread->Dispatch(new DummyRunnable(), NS_DISPATCH_SYNC);
|
||||||
|
MOZ_ASSERT(mScannedPluginOnDisk, "Should have scanned MOZ_GMP_PATH by now");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
MutexAutoLock lock(mMutex);
|
||||||
|
nsCString api(aAPI);
|
||||||
|
GMPParent* gmp = FindPluginForAPIFrom(0, api, *aTags, nullptr);
|
||||||
|
*aResult = (gmp != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GMPParent*
|
||||||
|
GeckoMediaPluginService::FindPluginForAPIFrom(size_t aSearchStartIndex,
|
||||||
|
const nsCString& aAPI,
|
||||||
|
const nsTArray<nsCString>& aTags,
|
||||||
|
size_t* aOutPluginIndex)
|
||||||
|
{
|
||||||
|
mMutex.AssertCurrentThreadOwns();
|
||||||
|
for (size_t i = aSearchStartIndex; i < mPlugins.Length(); i++) {
|
||||||
|
GMPParent* gmp = mPlugins[i];
|
||||||
|
bool supportsAllTags = true;
|
||||||
|
for (size_t t = 0; t < aTags.Length(); t++) {
|
||||||
|
const nsCString& tag = aTags.ElementAt(t);
|
||||||
|
if (!gmp->SupportsAPI(aAPI, tag)) {
|
||||||
|
supportsAllTags = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!supportsAllTags) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (aOutPluginIndex) {
|
||||||
|
*aOutPluginIndex = i;
|
||||||
|
}
|
||||||
|
return gmp;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
GMPParent*
|
GMPParent*
|
||||||
GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
|
GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
|
||||||
const nsCString& aAPI,
|
const nsCString& aAPI,
|
||||||
const nsTArray<nsCString>& aTags,
|
const nsTArray<nsCString>& aTags)
|
||||||
bool aCloneCrossNodeIds)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossNodeIds,
|
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread,
|
||||||
"Can't clone GMP plugins on non-GMP threads.");
|
"Can't clone GMP plugins on non-GMP threads.");
|
||||||
|
|
||||||
GMPParent* gmpToClone = nullptr;
|
GMPParent* gmpToClone = nullptr;
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
|
size_t index = 0;
|
||||||
GMPParent* gmp = mPlugins[i];
|
GMPParent* gmp = nullptr;
|
||||||
bool supportsAllTags = true;
|
while ((gmp = FindPluginForAPIFrom(index, aAPI, aTags, &index))) {
|
||||||
for (uint32_t t = 0; t < aTags.Length(); t++) {
|
|
||||||
const nsCString& tag = aTags[t];
|
|
||||||
if (!gmp->SupportsAPI(aAPI, tag)) {
|
|
||||||
supportsAllTags = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!supportsAllTags) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (aNodeId.IsEmpty()) {
|
if (aNodeId.IsEmpty()) {
|
||||||
if (gmp->CanBeSharedCrossNodeIds()) {
|
if (gmp->CanBeSharedCrossNodeIds()) {
|
||||||
return gmp;
|
return gmp;
|
||||||
@ -744,15 +788,17 @@ GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
|
|||||||
return gmp;
|
return gmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This GMP has the correct type but has the wrong origin; hold on to it
|
// This GMP has the correct type but has the wrong nodeId; hold on to it
|
||||||
// in case we need to clone it.
|
// in case we need to clone it.
|
||||||
gmpToClone = gmp;
|
gmpToClone = gmp;
|
||||||
|
// Loop around and try the next plugin; it may be usable from aNodeId.
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plugin exists, but we can't use it due to cross-origin separation. Create a
|
// Plugin exists, but we can't use it due to cross-origin separation. Create a
|
||||||
// new one.
|
// new one.
|
||||||
if (aCloneCrossNodeIds && gmpToClone) {
|
if (gmpToClone) {
|
||||||
GMPParent* clone = ClonePlugin(gmpToClone);
|
GMPParent* clone = ClonePlugin(gmpToClone);
|
||||||
if (!aNodeId.IsEmpty()) {
|
if (!aNodeId.IsEmpty()) {
|
||||||
clone->SetNodeId(aNodeId);
|
clone->SetNodeId(aNodeId);
|
||||||
@ -847,7 +893,7 @@ GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MutexAutoLock lock(mMutex);
|
MutexAutoLock lock(mMutex);
|
||||||
for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
|
for (size_t i = 0; i < mPlugins.Length(); ++i) {
|
||||||
nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
|
nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
|
||||||
bool equals;
|
bool equals;
|
||||||
if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
|
if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "nsITimer.h"
|
#include "nsITimer.h"
|
||||||
#include "nsClassHashtable.h"
|
#include "nsClassHashtable.h"
|
||||||
#include "nsDataHashtable.h"
|
#include "nsDataHashtable.h"
|
||||||
|
#include "mozilla/Atomics.h"
|
||||||
|
|
||||||
template <class> struct already_AddRefed;
|
template <class> struct already_AddRefed;
|
||||||
|
|
||||||
@ -49,8 +50,11 @@ private:
|
|||||||
|
|
||||||
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
|
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
|
||||||
const nsCString& aAPI,
|
const nsCString& aAPI,
|
||||||
const nsTArray<nsCString>& aTags,
|
const nsTArray<nsCString>& aTags);
|
||||||
bool aCloneCrossNodeIds = true);
|
GMPParent* FindPluginForAPIFrom(size_t aSearchStartIndex,
|
||||||
|
const nsCString& aAPI,
|
||||||
|
const nsTArray<nsCString>& aTags,
|
||||||
|
size_t* aOutPluginIndex);
|
||||||
|
|
||||||
void UnloadPlugins();
|
void UnloadPlugins();
|
||||||
void CrashPlugins();
|
void CrashPlugins();
|
||||||
@ -94,6 +98,10 @@ private:
|
|||||||
bool mShuttingDown;
|
bool mShuttingDown;
|
||||||
bool mShuttingDownOnGMPThread;
|
bool mShuttingDownOnGMPThread;
|
||||||
|
|
||||||
|
// True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
|
||||||
|
// plugins found there into mPlugins.
|
||||||
|
Atomic<bool> mScannedPluginOnDisk;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class MainThreadOnly {
|
class MainThreadOnly {
|
||||||
public:
|
public:
|
||||||
|
@ -26,7 +26,7 @@ class GMPVideoHost;
|
|||||||
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
|
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
|
||||||
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
|
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
|
||||||
|
|
||||||
[scriptable, uuid(b350d3b6-00c9-4602-bdfe-84c2be8d1e7a)]
|
[scriptable, uuid(657443a4-6b5d-4181-98b0-56997b35bd57)]
|
||||||
interface mozIGeckoMediaPluginService : nsISupports
|
interface mozIGeckoMediaPluginService : nsISupports
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -40,9 +40,7 @@ interface mozIGeckoMediaPluginService : nsISupports
|
|||||||
* Callable on any thread
|
* Callable on any thread
|
||||||
*/
|
*/
|
||||||
[noscript]
|
[noscript]
|
||||||
boolean hasPluginForAPI([optional] in ACString nodeId,
|
boolean hasPluginForAPI(in ACString api, in TagArray tags);
|
||||||
in ACString api,
|
|
||||||
in TagArray tags);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a video decoder that supports the specified tags.
|
* Get a video decoder that supports the specified tags.
|
||||||
|
@ -174,6 +174,9 @@ function startTest(test, token)
|
|||||||
}, bail("failed to create MediaKeys object")).then(function() {
|
}, bail("failed to create MediaKeys object")).then(function() {
|
||||||
info(token + " set MediaKeys on <video> element ok");
|
info(token + " set MediaKeys on <video> element ok");
|
||||||
|
|
||||||
|
ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
|
||||||
|
"MediaKeys should still support keysystem after CDM created...");
|
||||||
|
|
||||||
var session = v.mediaKeys.createSession(test.sessionType);
|
var session = v.mediaKeys.createSession(test.sessionType);
|
||||||
session.addEventListener("message", UpdateSessionFunc(test));
|
session.addEventListener("message", UpdateSessionFunc(test));
|
||||||
session.generateRequest(ev.initDataType, ev.initData).then(function() {
|
session.generateRequest(ev.initDataType, ev.initData).then(function() {
|
||||||
@ -202,7 +205,23 @@ function startTest(test, token)
|
|||||||
PlayTest(test, v);
|
PlayTest(test, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testIsTypeSupported()
|
||||||
|
{
|
||||||
|
var t = MediaKeys.isTypeSupported;
|
||||||
|
const clearkey = "org.w3.clearkey";
|
||||||
|
ok(!t("bogus", "bogon", "video/bogus"), "Invalid type.");
|
||||||
|
ok(t(clearkey), "ClearKey supported.");
|
||||||
|
ok(!t(clearkey, "bogus"), "ClearKey bogus initDataType not supported.");
|
||||||
|
ok(t(clearkey, "cenc"), "ClearKey/cenc should be supported.");
|
||||||
|
ok(!t(clearkey, "cenc", "bogus"), "ClearKey/cenc bogus content type should be supported.");
|
||||||
|
ok(t(clearkey, "cenc", 'video/mp4'), "ClearKey/cenc video/mp4 supported.");
|
||||||
|
ok(t(clearkey, "cenc", 'video/mp4; codecs="avc1.4d4015,mp4a.40.2"'), "ClearKey/cenc H.264/AAC supported.");
|
||||||
|
ok(t(clearkey, "cenc", 'audio/mp4'), "ClearKey/cenc audio/mp4 supported.");
|
||||||
|
ok(t(clearkey, "cenc", 'audio/mp4; codecs="mp4a.40.2"'), "ClearKey/cenc AAC LC supported.");
|
||||||
|
}
|
||||||
|
|
||||||
function beginTest() {
|
function beginTest() {
|
||||||
|
testIsTypeSupported();
|
||||||
manager.runTests(gEMETests, startTest);
|
manager.runTests(gEMETests, startTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,16 +203,14 @@ int VcmSIPCCBinding::getVideoCodecsGmp()
|
|||||||
// H.264 only for now
|
// H.264 only for now
|
||||||
bool has_gmp;
|
bool has_gmp;
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
|
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING("encode-video"),
|
||||||
NS_LITERAL_CSTRING("encode-video"),
|
|
||||||
&tags,
|
&tags,
|
||||||
&has_gmp);
|
&has_gmp);
|
||||||
if (NS_FAILED(rv) || !has_gmp) {
|
if (NS_FAILED(rv) || !has_gmp) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
|
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING("decode-video"),
|
||||||
NS_LITERAL_CSTRING("decode-video"),
|
|
||||||
&tags,
|
&tags,
|
||||||
&has_gmp);
|
&has_gmp);
|
||||||
if (NS_FAILED(rv) || !has_gmp) {
|
if (NS_FAILED(rv) || !has_gmp) {
|
||||||
|
Loading…
Reference in New Issue
Block a user