Bug 1245789 - Parse Chrome CDM manifest in GMPService.addPluginDir. r=gerald
authorChris Pearce <cpearce@mozilla.com>
Tue, 12 Apr 2016 16:12:21 +1200
changeset 292722 82dd58ddc0e6c0ab0549c34ced000b4423485a70
parent 292721 40d6d4f042f9f819fabb0467068eab9d834a9fd7
child 292723 e46009d07dbc6195f2762717e52ddeea5218cc24
push id74962
push usercpearce@mozilla.com
push dateTue, 12 Apr 2016 04:14:58 +0000
treeherdermozilla-inbound@85a28619dd12 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1245789
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1245789 - Parse Chrome CDM manifest in GMPService.addPluginDir. r=gerald This has to happen on the main thread, as WebIDL parsing only happens there. So it has to be async. MozReview-Commit-ID: AfAoSkQAhl3
dom/media/gmp/GMPParent.cpp
dom/media/gmp/GMPParent.h
dom/media/gmp/GMPUtils.cpp
dom/media/gmp/GMPUtils.h
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -17,28 +17,30 @@
 #include "mozilla/unused.h"
 #include "nsIObserverService.h"
 #include "GMPTimerParent.h"
 #include "runnable_utils.h"
 #if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
 #include "mozilla/SandboxInfo.h"
 #endif
 #include "GMPContentParent.h"
+#include "widevine-adapter/WidevineAdapter.h"
 
 #include "mozilla/dom/CrashReporterParent.h"
 using mozilla::dom::CrashReporterParent;
 using mozilla::ipc::GeckoChildProcessHost;
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsPrintfCString.h"
 using CrashReporter::AnnotationTable;
 using CrashReporter::GetIDFromMinidump;
 #endif
 
 #include "mozilla/Telemetry.h"
+#include "mozilla/dom/WidevineCDMManifestBinding.h"
 
 namespace mozilla {
 
 #undef LOG
 #undef LOGD
 
 extern LogModule* GetGMPLog();
 #define LOG(level, x, ...) MOZ_LOG(GetGMPLog(), (level), (x, ##__VA_ARGS__))
@@ -777,17 +779,24 @@ GMPParent::ReadGMPMetaData()
     return InitPromise::CreateAndReject(rv, __func__);
   }
   infoFile->AppendRelativePath(mName + NS_LITERAL_STRING(".info"));
 
   if (FileExists(infoFile)) {
     return ReadGMPInfoFile(infoFile);
   }
 
-  return InitPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  // Maybe this is the Widevine adapted plugin?
+  nsCOMPtr<nsIFile> manifestFile;
+  rv = mDirectory->Clone(getter_AddRefs(manifestFile));
+  if (NS_FAILED(rv)) {
+    return InitPromise::CreateAndReject(rv, __func__);
+  }
+  manifestFile->AppendRelativePath(NS_LITERAL_STRING("manifest.json"));
+  return ReadChromiumManifestFile(manifestFile);
 }
 
 RefPtr<GMPParent::InitPromise>
 GMPParent::ReadGMPInfoFile(nsIFile* aFile)
 {
   GMPInfoFileParser parser;
   if (!parser.Init(aFile)) {
     return InitPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
@@ -877,16 +886,73 @@ GMPParent::ReadGMPInfoFile(nsIFile* aFil
 
   if (mCapabilities.IsEmpty()) {
     return InitPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
   }
 
   return InitPromise::CreateAndResolve(NS_OK, __func__);
 }
 
+RefPtr<GMPParent::InitPromise>
+GMPParent::ReadChromiumManifestFile(nsIFile* aFile)
+{
+  nsAutoCString json;
+  if (!ReadIntoString(aFile, json, 5 * 1024)) {
+    return InitPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+
+  // DOM JSON parsing needs to run on the main thread.
+  return InvokeAsync(AbstractThread::MainThread(), this, __func__,
+    &GMPParent::ParseChromiumManifest, NS_ConvertUTF8toUTF16(json));
+}
+
+RefPtr<GMPParent::InitPromise>
+GMPParent::ParseChromiumManifest(nsString aJSON)
+{
+  LOGD("%s: for '%s'", __FUNCTION__, NS_LossyConvertUTF16toASCII(aJSON).get());
+
+  MOZ_ASSERT(NS_IsMainThread());
+  mozilla::dom::WidevineCDMManifest m;
+  if (!m.Init(aJSON)) {
+    return InitPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+
+  nsresult ignored; // Note: ToInteger returns 0 on failure.
+  if (!WidevineAdapter::Supports(m.mX_cdm_module_versions.ToInteger(&ignored),
+                                 m.mX_cdm_interface_versions.ToInteger(&ignored),
+                                 m.mX_cdm_host_versions.ToInteger(&ignored))) {
+    return InitPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
+  }
+
+  mDisplayName = NS_ConvertUTF16toUTF8(m.mName);
+  mDescription = NS_ConvertUTF16toUTF8(m.mDescription);
+  mVersion = NS_ConvertUTF16toUTF8(m.mVersion);
+
+  GMPCapability audio(NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER));
+  audio.mAPITags.AppendElement(NS_LITERAL_CSTRING("aac"));
+  audio.mAPITags.AppendElement(NS_LITERAL_CSTRING("com.widevine.alpha"));
+  mCapabilities.AppendElement(Move(audio));
+
+  GMPCapability video(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER));
+  video.mAPITags.AppendElement(NS_LITERAL_CSTRING("h264"));
+  video.mAPITags.AppendElement(NS_LITERAL_CSTRING("com.widevine.alpha"));
+  mCapabilities.AppendElement(Move(video));
+
+  GMPCapability decrypt(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR));
+  decrypt.mAPITags.AppendElement(NS_LITERAL_CSTRING("com.widevine.alpha"));
+  mCapabilities.AppendElement(Move(decrypt));
+
+  MOZ_ASSERT(mName.EqualsLiteral("widevinecdm"));
+#ifdef XP_WIN
+  mLibs = NS_LITERAL_CSTRING("dxva2.dll");
+#endif
+
+  return InitPromise::CreateAndResolve(NS_OK, __func__);
+}
+
 bool
 GMPParent::CanBeSharedCrossNodeIds() const
 {
   return !mAsyncShutdownInProgress &&
          mNodeId.IsEmpty() &&
          // XXX bug 1159300 hack -- maybe remove after openh264 1.4
          // We don't want to use CDM decoders for non-encrypted playback
          // just yet; especially not for WebRTC. Don't allow CDMs to be used
--- a/dom/media/gmp/GMPParent.h
+++ b/dom/media/gmp/GMPParent.h
@@ -159,20 +159,23 @@ public:
   already_AddRefed<GMPContentParent> ForgetGMPContentParent();
 
   bool EnsureProcessLoaded(base::ProcessId* aID);
 
   bool Bridge(GMPServiceParent* aGMPServiceParent);
 
 private:
   ~GMPParent();
+
   RefPtr<GeckoMediaPluginServiceParent> mService;
   bool EnsureProcessLoaded();
   RefPtr<InitPromise> ReadGMPMetaData();
   RefPtr<InitPromise> ReadGMPInfoFile(nsIFile* aFile);
+  RefPtr<InitPromise> ReadChromiumManifestFile(nsIFile* aFile);
+  RefPtr<InitPromise> ParseChromiumManifest(nsString aJSON); // Main thread.
 #ifdef MOZ_CRASHREPORTER
   void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
   void GetCrashID(nsString& aResult);
 #endif
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   PCrashReporterParent* AllocPCrashReporterParent(const NativeThreadId& aThread) override;
   bool DeallocPCrashReporterParent(PCrashReporterParent* aCrashReporter) override;
--- a/dom/media/gmp/GMPUtils.cpp
+++ b/dom/media/gmp/GMPUtils.cpp
@@ -133,17 +133,17 @@ ReadIntoArray(nsIFile* aFile,
     return false;
   }
   aOutDst.SetLength(length);
   int32_t bytesRead = PR_Read(fd, aOutDst.Elements(), length);
   PR_Close(fd);
   return (bytesRead == length);
 }
 
-static bool
+bool
 ReadIntoString(nsIFile* aFile,
                nsCString& aOutDst,
                size_t aMaxLength)
 {
   nsTArray<uint8_t> buf;
   bool rv = ReadIntoArray(aFile, buf, aMaxLength);
   if (rv) {
     buf.AppendElement(0); // Append null terminator, required by nsC*String.
--- a/dom/media/gmp/GMPUtils.h
+++ b/dom/media/gmp/GMPUtils.h
@@ -70,11 +70,16 @@ private:
   nsClassHashtable<nsCStringHashKey, nsCString> mValues;
 };
 
 bool
 ReadIntoArray(nsIFile* aFile,
               nsTArray<uint8_t>& aOutDst,
               size_t aMaxLength);
 
+bool
+ReadIntoString(nsIFile* aFile,
+               nsCString& aOutDst,
+               size_t aMaxLength);
+
 } // namespace mozilla
 
 #endif