From 418fcf0ab20e9cfd0bb542c1d981edd4fb7b95e8 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 26 Jun 2014 15:44:54 +1200 Subject: [PATCH] Bug 1024300 - Allow GMPs to be segregated by origin. r=josh --- content/media/gmp/GMPParent.cpp | 21 +++++++ content/media/gmp/GMPParent.h | 24 ++++++++ content/media/gmp/GMPService.cpp | 60 +++++++++++++++---- content/media/gmp/GMPService.h | 8 ++- content/media/gmp/GMPVideoHost.cpp | 2 +- .../media/gmp/mozIGeckoMediaPluginService.idl | 17 ++++-- .../src/media-conduit/WebrtcGmpVideoCodec.cpp | 15 ++++- 7 files changed, 124 insertions(+), 23 deletions(-) diff --git a/content/media/gmp/GMPParent.cpp b/content/media/gmp/GMPParent.cpp index 23dc12e1a984..2e3a5d228f46 100644 --- a/content/media/gmp/GMPParent.cpp +++ b/content/media/gmp/GMPParent.cpp @@ -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 diff --git a/content/media/gmp/GMPParent.h b/content/media/gmp/GMPParent.h index 7ed3d391e4ca..508af8671ed3 100644 --- a/content/media/gmp/GMPParent.h +++ b/content/media/gmp/GMPParent.h @@ -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 mGMPThread; #endif + // Origin the plugin is assigned to, or empty if the the plugin is not + // assigned to an origin. + nsAutoString mOrigin; }; } // namespace gmp diff --git a/content/media/gmp/GMPService.cpp b/content/media/gmp/GMPService.cpp index 6d21466503aa..9d84b63c9c24 100644 --- a/content/media/gmp/GMPService.cpp +++ b/content/media/gmp/GMPService.cpp @@ -191,16 +191,23 @@ GeckoMediaPluginService::GetThread(nsIThread** aThread) } NS_IMETHODIMP -GeckoMediaPluginService::GetGMPVideoDecoderVP8(GMPVideoHost** aOutVideoHost, GMPVideoDecoder** aGMPVD) +GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray* 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 gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("decode-video"), - NS_LITERAL_CSTRING("vp8")); + nsRefPtr 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* 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 gmp = SelectPluginForAPI(NS_LITERAL_CSTRING("encode-video"), - NS_LITERAL_CSTRING("vp8")); + nsRefPtr 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& 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& 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; } } diff --git a/content/media/gmp/GMPService.h b/content/media/gmp/GMPService.h index f17cf13df578..4e2d5fa9977e 100644 --- a/content/media/gmp/GMPService.h +++ b/content/media/gmp/GMPService.h @@ -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& aTags); + GMPParent* SelectPluginForAPI(const nsAString& aOrigin, + const nsCString& aAPI, + const nsTArray& aTags); void UnloadPlugins(); void RefreshPluginList(); diff --git a/content/media/gmp/GMPVideoHost.cpp b/content/media/gmp/GMPVideoHost.cpp index 657ba51dd690..654431e6a923 100644 --- a/content/media/gmp/GMPVideoHost.cpp +++ b/content/media/gmp/GMPVideoHost.cpp @@ -96,7 +96,7 @@ GMPVideoHostImpl::ActorDestroyed() mEncodedFrames[i - 1]->ActorDestroyed(); mEncodedFrames.RemoveElementAt(i - 1); } - mSharedMemMgr = nullptr; + mSharedMemMgr = nullptr; } void diff --git a/content/media/gmp/mozIGeckoMediaPluginService.idl b/content/media/gmp/mozIGeckoMediaPluginService.idl index 759e3304dc9d..b7ab1d0c4851 100644 --- a/content/media/gmp/mozIGeckoMediaPluginService.idl +++ b/content/media/gmp/mozIGeckoMediaPluginService.idl @@ -16,6 +16,7 @@ class GMPVideoHost; [ptr] native GMPVideoEncoder(GMPVideoEncoder); [ptr] native GMPVideoHost(GMPVideoHost); [ptr] native MessageLoop(MessageLoop); +[ptr] native TagArray(nsTArray); [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); }; diff --git a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp index 6b6c222092f0..080e43828aa5 100644 --- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp +++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp @@ -123,7 +123,12 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings, GMPVideoHost* host = nullptr; GMPVideoEncoder* gmp = nullptr; - nsresult rv = mMPS->GetGMPVideoEncoderVP8(&host, &gmp); + nsTArray 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 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; }