Bug 1024300 - Allow GMPs to be segregated by origin. r=josh

This commit is contained in:
Chris Pearce 2014-06-26 15:44:54 +12:00
Родитель 711b5f3c6f
Коммит 418fcf0ab2
7 изменённых файлов: 124 добавлений и 23 удалений

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

@ -420,5 +420,26 @@ GMPParent::ReadGMPMetaData()
return NS_OK;
}
bool
GMPParent::CanBeSharedCrossOrigin() const
{
return mOrigin.IsEmpty();
}
bool
GMPParent::CanBeUsedFrom(const nsAString& aOrigin) const
{
return (mOrigin.IsEmpty() && State() == GMPStateNotLoaded) ||
mOrigin.Equals(aOrigin);
}
void
GMPParent::SetOrigin(const nsAString& aOrigin)
{
MOZ_ASSERT(!aOrigin.IsEmpty());
MOZ_ASSERT(CanBeUsedFrom(aOrigin));
mOrigin = aOrigin;
}
} // namespace gmp
} // namespace mozilla

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

@ -56,6 +56,27 @@ public:
nsIThread* GMPThread();
#endif
// A GMP can either be a single instance shared across all origins (like
// in the OpenH264 case), or we can require a new plugin instance for every
// origin running the plugin (as in the EME plugin case).
//
// Plugins are associated with an origin by calling SetOrigin() before
// loading.
//
// If a plugin has no origin specified and it is loaded, it is assumed to
// be shared across origins.
// Specifies that a GMP can only work with the specified origin.
void SetOrigin(const nsAString& aOrigin);
// Returns true if a plugin can be or is being used across multiple origins.
bool CanBeSharedCrossOrigin() const;
// A GMP can be used from an origin if it's already been set to work with
// that origin, or if it's not been set to work with any origin and has
// not yet been loaded (i.e. it's not shared across origins).
bool CanBeUsedFrom(const nsAString& aOrigin) const;
private:
~GMPParent();
bool EnsureProcessLoaded();
@ -80,6 +101,9 @@ private:
#ifdef DEBUG
nsCOMPtr<nsIThread> mGMPThread;
#endif
// Origin the plugin is assigned to, or empty if the the plugin is not
// assigned to an origin.
nsAutoString mOrigin;
};
} // namespace gmp

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

@ -191,16 +191,23 @@ GeckoMediaPluginService::GetThread(nsIThread** aThread)
}
NS_IMETHODIMP
GeckoMediaPluginService::GetGMPVideoDecoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoDecoder** aGMPVD)
GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
const nsAString& aOrigin,
GMPVideoHost** aOutVideoHost,
GMPVideoDecoder** aGMPVD)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aOutVideoHost);
NS_ENSURE_ARG(aGMPVD);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("decode-video"),
NS_LITERAL_CSTRING("vp8"));
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
NS_LITERAL_CSTRING("decode-video"),
*aTags);
if (!gmp) {
return NS_ERROR_FAILURE;
}
@ -218,16 +225,23 @@ GeckoMediaPluginService::GetGMPVideoDecoderVP8(GMPVideoHost** aOutVideoHost, GMP
}
NS_IMETHODIMP
GeckoMediaPluginService::GetGMPVideoEncoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoEncoder** aGMPVE)
GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
const nsAString& aOrigin,
GMPVideoHost** aOutVideoHost,
GMPVideoEncoder** aGMPVE)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
NS_ENSURE_ARG(aTags && aTags->Length() > 0);
NS_ENSURE_ARG(aOutVideoHost);
NS_ENSURE_ARG(aGMPVE);
if (mShuttingDownOnGMPThread) {
return NS_ERROR_FAILURE;
}
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("encode-video"),
NS_LITERAL_CSTRING("vp8"));
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
NS_LITERAL_CSTRING("encode-video"),
*aTags);
if (!gmp) {
return NS_ERROR_FAILURE;
}
@ -259,30 +273,50 @@ GeckoMediaPluginService::UnloadPlugins()
}
GMPParent*
GeckoMediaPluginService::SelectPluginForAPI(const nsCString& aAPI,
const nsCString& aTag)
GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
GMPParent* gmp = SelectPluginFromListForAPI(aAPI, aTag);
GMPParent* gmp = SelectPluginFromListForAPI(aOrigin, aAPI, aTags);
if (gmp) {
return gmp;
}
RefreshPluginList();
return SelectPluginFromListForAPI(aAPI, aTag);
return SelectPluginFromListForAPI(aOrigin, aAPI, aTags);
}
GMPParent*
GeckoMediaPluginService::SelectPluginFromListForAPI(const nsCString& aAPI,
const nsCString& aTag)
GeckoMediaPluginService::SelectPluginFromListForAPI(const nsAString& aOrigin,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
for (uint32_t i = 0; i < mPlugins.Length(); i++) {
GMPParent* gmp = mPlugins[i];
if (gmp->SupportsAPI(aAPI, aTag)) {
bool supportsAllTags = true;
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 (aOrigin.IsEmpty()) {
if (gmp->CanBeSharedCrossOrigin()) {
return gmp;
}
} else if (gmp->CanBeUsedFrom(aOrigin)) {
if (!aOrigin.IsEmpty()) {
gmp->SetOrigin(aOrigin);
}
return gmp;
}
}

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

@ -38,8 +38,12 @@ public:
private:
~GeckoMediaPluginService();
GMPParent* SelectPluginFromListForAPI(const nsCString& aAPI, const nsCString& aTag);
GMPParent* SelectPluginForAPI(const nsCString& aAPI, const nsCString& aTag);
GMPParent* SelectPluginFromListForAPI(const nsAString& aOrigin,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags);
GMPParent* SelectPluginForAPI(const nsAString& aOrigin,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags);
void UnloadPlugins();
void RefreshPluginList();

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

@ -96,7 +96,7 @@ GMPVideoHostImpl::ActorDestroyed()
mEncodedFrames[i - 1]->ActorDestroyed();
mEncodedFrames.RemoveElementAt(i - 1);
}
mSharedMemMgr = nullptr;
mSharedMemMgr = nullptr;
}
void

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

@ -16,6 +16,7 @@ class GMPVideoHost;
[ptr] native GMPVideoEncoder(GMPVideoEncoder);
[ptr] native GMPVideoHost(GMPVideoHost);
[ptr] native MessageLoop(MessageLoop);
[ptr] native TagArray(nsTArray<nsCString>);
[uuid(BF5A9086-70F5-4D38-832D-1609BBF963CD)]
interface mozIGeckoMediaPluginService : nsISupports
@ -24,11 +25,19 @@ interface mozIGeckoMediaPluginService : nsISupports
// Callable from any thread.
readonly attribute nsIThread thread;
// Returns a video decoder API object that should support VP8.
// Returns a video decoder that supports the specified tags.
// The array of tags should at least contain a codec tag, and optionally
// other tags such as for EME keysystem.
// Callable only on GMP thread.
GMPVideoDecoder getGMPVideoDecoderVP8(out GMPVideoHost outVideoHost);
GMPVideoDecoder getGMPVideoDecoder(in TagArray tags,
[optional] in AString origin,
out GMPVideoHost outVideoHost);
// Returns a video encoder API object that should support VP8.
// Returns a video encoder that supports the specified tags.
// The array of tags should at least contain a codec tag, and optionally
// other tags.
// Callable only on GMP thread.
GMPVideoEncoder getGMPVideoEncoderVP8(out GMPVideoHost outVideoHost);
GMPVideoEncoder getGMPVideoEncoder(in TagArray tags,
[optional] in AString origin,
out GMPVideoHost outVideoHost);
};

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

@ -123,7 +123,12 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
GMPVideoHost* host = nullptr;
GMPVideoEncoder* gmp = nullptr;
nsresult rv = mMPS->GetGMPVideoEncoderVP8(&host, &gmp);
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
nsresult rv = mMPS->GetGMPVideoEncoder(&tags,
NS_LITERAL_STRING(""),
&host,
&gmp);
if (NS_FAILED(rv)) {
return WEBRTC_VIDEO_CODEC_ERROR;
}
@ -458,8 +463,12 @@ WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
GMPVideoHost* host = nullptr;
GMPVideoDecoder* gmp = nullptr;
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoderVP8(&host, &gmp))))
{
nsTArray<nsCString> tags;
tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
NS_LITERAL_STRING(""),
&host,
&gmp)))) {
return WEBRTC_VIDEO_CODEC_ERROR;
}