Bug 1288618 - Part 13: Add VideoDecoderManager protocol. r=dvander
☠☠ backed out by 1d54e301b552 ☠ ☠
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 15 Sep 2016 23:18:00 +1200
changeset 355351 f981edef8f81d2f897adc6e6170a9da9c64f9d18
parent 355350 d5c1565d5f7f680b6815fd883ac208f022ceed1b
child 355352 f2da4a56dc4f1ab1a00a6fdef687cb97d6222609
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1288618
milestone51.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 1288618 - Part 13: Add VideoDecoderManager protocol. r=dvander
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/media/ipc/PVideoDecoderManager.ipdl
dom/media/ipc/VideoDecoderManagerChild.cpp
dom/media/ipc/VideoDecoderManagerChild.h
dom/media/ipc/VideoDecoderManagerParent.cpp
dom/media/ipc/VideoDecoderManagerParent.h
dom/media/ipc/moz.build
dom/media/moz.build
gfx/ipc/GPUParent.cpp
gfx/ipc/GPUParent.h
gfx/ipc/GPUProcessManager.cpp
gfx/ipc/GPUProcessManager.h
gfx/ipc/PGPU.ipdl
gfx/layers/client/GPUVideoTextureClient.cpp
gfx/layers/composite/GPUVideoTextureHost.cpp
layout/build/nsLayoutStatics.cpp
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1054,16 +1054,23 @@ ContentParent::RecvFindPlugins(const uin
                                nsresult* aRv,
                                nsTArray<PluginTag>* aPlugins,
                                uint32_t* aNewPluginEpoch)
 {
   *aRv = mozilla::plugins::FindPluginsForContent(aPluginEpoch, aPlugins, aNewPluginEpoch);
   return true;
 }
 
+bool
+ContentParent::RecvInitVideoDecoderManager(Endpoint<PVideoDecoderManagerChild>* aEndpoint)
+{
+  GPUProcessManager::Get()->CreateContentVideoDecoderManager(OtherPid(), aEndpoint);
+  return true;
+}
+
 /*static*/ TabParent*
 ContentParent::CreateBrowserOrApp(const TabContext& aContext,
                                   Element* aFrameElement,
                                   ContentParent* aOpenerContentParent)
 {
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
 
   if (!sCanLaunchSubprocesses) {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -264,16 +264,18 @@ public:
   virtual bool RecvGetBlocklistState(const uint32_t& aPluginId,
                                      uint32_t* aIsBlocklisted) override;
 
   virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
                                nsresult* aRv,
                                nsTArray<PluginTag>* aPlugins,
                                uint32_t* aNewPluginEpoch) override;
 
+  virtual bool RecvInitVideoDecoderManager(Endpoint<PVideoDecoderManagerChild>* endpoint) override;
+
   virtual bool RecvUngrabPointer(const uint32_t& aTime) override;
 
   virtual bool RecvRemovePermission(const IPC::Principal& aPrincipal,
                                     const nsCString& aPermissionType,
                                     nsresult* aRv) override;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -51,16 +51,17 @@ include protocol PTelephony;
 include protocol PTestShell;
 include protocol PVoicemail;
 include protocol PJavaScript;
 include protocol PRemoteSpellcheckEngine;
 include protocol PWebBrowserPersistDocument;
 include protocol PWebrtcGlobal;
 include protocol PPresentation;
 include protocol PVRManager;
+include protocol PVideoDecoderManager;
 include protocol PFlyWebPublishedServer;
 include DOMTypes;
 include JavaScriptTypes;
 include InputStreamParams;
 include PTabContext;
 include URIParams;
 include PluginTypes;
 include ProtocolTypes;
@@ -772,16 +773,18 @@ parent:
 
     async PJavaScript();
 
     async PRemoteSpellcheckEngine();
     async PDeviceStorageRequest(DeviceStorageParams params);
 
     sync PCrashReporter(NativeThreadId tid, uint32_t processType);
 
+    sync InitVideoDecoderManager() returns (Endpoint<PVideoDecoderManagerChild> endpoint);
+
     /**
      * Is this token compatible with the provided version?
      *
      * |version| The offered version to test
      * Returns |True| if the offered version is compatible
      */
     sync NSSU2FTokenIsCompatibleVersion(nsString version)
         returns (bool result);
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/PVideoDecoderManager.ipdl
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include LayersSurfaces;
+include "mozilla/dom/MediaIPCUtils.h";
+
+namespace mozilla {
+namespace dom {
+
+async protocol PVideoDecoderManager
+{
+parent:
+
+  async DeallocateSurfaceDescriptorGPUVideo(SurfaceDescriptorGPUVideo sd);
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/VideoDecoderManagerChild.cpp
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "VideoDecoderManagerChild.h"
+#include "mozilla/dom/ContentChild.h"
+#include "MediaPrefs.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+using namespace ipc;
+using namespace layers;
+using namespace gfx;
+
+StaticRefPtr<nsIThread> sVideoDecoderChildThread;
+static StaticRefPtr<VideoDecoderManagerChild> sDecoderManager;
+
+/* static */ void
+VideoDecoderManagerChild::Initialize()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  MediaPrefs::GetSingleton();
+
+#ifdef XP_WIN
+  if (!MediaPrefs::PDMUseGPUDecoder()) {
+    return;
+  }
+
+  // Can't run remote video decoding in the parent process.
+  if (!ContentChild::GetSingleton()) {
+    return;
+  }
+
+  if (!sVideoDecoderChildThread) {
+    RefPtr<nsIThread> childThread;
+    nsresult rv = NS_NewNamedThread("VideoChild", getter_AddRefs(childThread));
+    NS_ENSURE_SUCCESS_VOID(rv);
+    sVideoDecoderChildThread = childThread;
+  }
+
+  Endpoint<PVideoDecoderManagerChild> endpoint;
+  if (!ContentChild::GetSingleton()->SendInitVideoDecoderManager(&endpoint)) {
+    return;
+  }
+
+  // TODO: The above message should return an empty endpoint if there wasn't a GPU
+  // process. Unfortunately IPDL will assert in this case, so it can't actually
+  // happen. Bug 1302009 is filed for fixing this.
+
+  sDecoderManager = new VideoDecoderManagerChild();
+
+  RefPtr<Runnable> task = NewRunnableMethod<Endpoint<PVideoDecoderManagerChild>&&>(
+    sDecoderManager, &VideoDecoderManagerChild::Open, Move(endpoint));
+  sVideoDecoderChildThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
+#else
+  return;
+#endif
+
+}
+
+/* static */ void
+VideoDecoderManagerChild::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (sVideoDecoderChildThread) {
+    MOZ_ASSERT(sDecoderManager);
+
+    sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([]() {
+      sDecoderManager->Close();
+    }), NS_DISPATCH_SYNC);
+
+    sDecoderManager = nullptr;
+
+    sVideoDecoderChildThread->Shutdown();
+    sVideoDecoderChildThread = nullptr;
+  }
+}
+
+/* static */ VideoDecoderManagerChild*
+VideoDecoderManagerChild::GetSingleton()
+{
+  return sDecoderManager;
+}
+
+void
+VideoDecoderManagerChild::Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint)
+{
+  if (!aEndpoint.Bind(this)) {
+    // We can't recover from this.
+    MOZ_CRASH("Failed to bind VideoDecoderChild to endpoint");
+  }
+  AddRef();
+}
+
+void
+VideoDecoderManagerChild::DeallocPVideoDecoderManagerChild()
+{
+  Release();
+}
+
+void
+VideoDecoderManagerChild::DeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD)
+{
+  RefPtr<VideoDecoderManagerChild> ref = this;
+  SurfaceDescriptorGPUVideo sd = Move(aSD);
+  sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([ref, sd]() {
+    ref->SendDeallocateSurfaceDescriptorGPUVideo(sd);
+  }), NS_DISPATCH_NORMAL);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/VideoDecoderManagerChild.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef include_dom_ipc_VideoDecoderManagerChild_h
+#define include_dom_ipc_VideoDecoderManagerChild_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/PVideoDecoderManagerChild.h"
+
+namespace mozilla {
+namespace dom {
+
+class VideoDecoderManagerChild final : public PVideoDecoderManagerChild
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerChild)
+
+  static VideoDecoderManagerChild* GetSingleton();
+
+  // Can be called from any thread, dispatches the request to the IPDL thread internally.
+  void DeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD);
+
+  void DeallocPVideoDecoderManagerChild() override;
+
+  // Main thread only
+  static void Initialize();
+  static void Shutdown();
+
+private:
+  VideoDecoderManagerChild()
+  {}
+  ~VideoDecoderManagerChild() {}
+
+  void Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // include_dom_ipc_VideoDecoderManagerChild_h
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/VideoDecoderManagerParent.cpp
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "VideoDecoderManagerParent.h"
+#include "base/thread.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Services.h"
+#include "mozilla/Observer.h"
+#include "nsIObserverService.h"
+#include "nsIObserver.h"
+#include "nsIEventTarget.h"
+#include "nsThreadUtils.h"
+#include "ImageContainer.h"
+
+#if XP_WIN
+#include <objbase.h>
+#endif
+
+namespace mozilla {
+namespace dom {
+
+using base::Thread;
+using namespace ipc;
+using namespace layers;
+using namespace gfx;
+
+
+struct ImageMapEntry {
+  ImageMapEntry()
+    : mOwner(nullptr)
+  {}
+  ImageMapEntry(layers::Image* aImage, VideoDecoderManagerParent* aOwner)
+    : mImage(aImage)
+    , mOwner(aOwner)
+  {}
+  ~ImageMapEntry() {}
+
+  RefPtr<layers::Image> mImage;
+  VideoDecoderManagerParent* mOwner;
+};
+std::map<uint64_t, ImageMapEntry> sImageMap;
+StaticMutex sImageMutex;
+
+/* static */ layers::Image*
+VideoDecoderManagerParent::LookupImage(const SurfaceDescriptorGPUVideo& aSD)
+{
+  StaticMutexAutoLock lock(sImageMutex);
+  return sImageMap[aSD.handle()].mImage;
+}
+
+SurfaceDescriptorGPUVideo
+VideoDecoderManagerParent::StoreImage(Image* aImage)
+{
+  StaticMutexAutoLock lock(sImageMutex);
+
+  static uint64_t sImageCount = 0;
+  sImageMap[++sImageCount] = ImageMapEntry(aImage, this);
+
+  return SurfaceDescriptorGPUVideo(sImageCount);
+}
+
+void
+VideoDecoderManagerParent::ClearAllOwnedImages()
+{
+  StaticMutexAutoLock lock(sImageMutex);
+  for (auto it = sImageMap.begin(); it != sImageMap.end();)
+  {
+    if ((*it).second.mOwner == this) {
+      it = sImageMap.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
+StaticRefPtr<nsIThread> sVideoDecoderManagerThread;
+StaticRefPtr<nsIThread> sVideoDecoderTaskThread;
+StaticRefPtr<TaskQueue> sManagerTaskQueue;
+
+class ManagerThreadShutdownObserver : public nsIObserver
+{
+  virtual ~ManagerThreadShutdownObserver() {}
+public:
+  ManagerThreadShutdownObserver() {}
+
+  NS_DECL_ISUPPORTS
+
+  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
+                     const char16_t* aData) override
+  {
+    MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
+
+    VideoDecoderManagerParent::ShutdownThreads();
+    return NS_OK;
+  }
+};
+NS_IMPL_ISUPPORTS(ManagerThreadShutdownObserver, nsIObserver);
+
+void
+VideoDecoderManagerParent::StartupThreads()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (sVideoDecoderManagerThread) {
+    return;
+  }
+
+  nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
+  if (!observerService) {
+    return;
+  }
+
+  RefPtr<nsIThread> managerThread;
+  nsresult rv = NS_NewNamedThread("VideoParent", getter_AddRefs(managerThread));
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  sVideoDecoderManagerThread = managerThread;
+#if XP_WIN
+  sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction([]() {
+    HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+    MOZ_ASSERT(hr == S_OK);
+  }), NS_DISPATCH_NORMAL);
+#endif
+
+  sManagerTaskQueue = new TaskQueue(managerThread.forget());
+
+  RefPtr<nsIThread> taskThread;
+  rv = NS_NewNamedThread("VideoTaskQueue", getter_AddRefs(taskThread));
+  if (NS_FAILED(rv)) {
+    sVideoDecoderManagerThread->Shutdown();
+    sVideoDecoderManagerThread = nullptr;
+    return;
+  }
+  sVideoDecoderTaskThread = taskThread;
+
+#ifdef XP_WIN
+  sVideoDecoderTaskThread->Dispatch(NS_NewRunnableFunction([]() {
+    HRESULT hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+    MOZ_ASSERT(hr == S_OK);
+  }), NS_DISPATCH_NORMAL);
+#endif
+
+  ManagerThreadShutdownObserver* obs = new ManagerThreadShutdownObserver();
+  observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+}
+
+void
+VideoDecoderManagerParent::ShutdownThreads()
+{
+  sManagerTaskQueue->BeginShutdown();
+  sManagerTaskQueue->AwaitShutdownAndIdle();
+  sVideoDecoderTaskThread->Shutdown();
+  sVideoDecoderTaskThread = nullptr;
+  sVideoDecoderManagerThread->Shutdown();
+  sVideoDecoderManagerThread = nullptr;
+}
+
+bool
+VideoDecoderManagerParent::CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint)
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  StartupThreads();
+  if (!sVideoDecoderManagerThread) {
+    return false;
+  }
+
+  RefPtr<VideoDecoderManagerParent> parent = new VideoDecoderManagerParent();
+
+  RefPtr<Runnable> task = NewRunnableMethod<Endpoint<PVideoDecoderManagerParent>&&>(
+    parent, &VideoDecoderManagerParent::Open, Move(aEndpoint));
+  sVideoDecoderManagerThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
+  return true;
+}
+
+VideoDecoderManagerParent::VideoDecoderManagerParent()
+{
+  MOZ_COUNT_CTOR(VideoDecoderManagerParent);
+}
+
+VideoDecoderManagerParent::~VideoDecoderManagerParent()
+{
+  MOZ_COUNT_DTOR(VideoDecoderManagerParent);
+
+  ClearAllOwnedImages();
+}
+
+void
+VideoDecoderManagerParent::Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint)
+{
+  if (!aEndpoint.Bind(this)) {
+    // We can't recover from this.
+    MOZ_CRASH("Failed to bind VideoDecoderManagerParent to endpoint");
+  }
+  AddRef();
+}
+
+void
+VideoDecoderManagerParent::DeallocPVideoDecoderManagerParent()
+{
+  Release();
+}
+
+bool
+VideoDecoderManagerParent::RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD)
+{
+  StaticMutexAutoLock lock(sImageMutex);
+  sImageMap.erase(aSD.handle());
+  return true;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/VideoDecoderManagerParent.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef include_dom_ipc_VideoDecoderManagerParent_h
+#define include_dom_ipc_VideoDecoderManagerParent_h
+
+#include "mozilla/dom/PVideoDecoderManagerParent.h"
+
+namespace mozilla {
+namespace dom {
+
+class VideoDecoderManagerParent final : public PVideoDecoderManagerParent
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerParent)
+
+  static bool CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
+
+  // Can be called from any thread
+  static layers::Image* LookupImage(const SurfaceDescriptorGPUVideo& aSD);
+  SurfaceDescriptorGPUVideo StoreImage(layers::Image* aImage);
+
+  static void StartupThreads();
+  static void ShutdownThreads();
+
+protected:
+  bool RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) override;
+
+  void ActorDestroy(mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason) override {}
+
+  void DeallocPVideoDecoderManagerParent() override;
+
+ private:
+  VideoDecoderManagerParent();
+  ~VideoDecoderManagerParent();
+
+  void ClearAllOwnedImages();
+
+  void Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // include_dom_ipc_VideoDecoderManagerParent_h
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/moz.build
@@ -0,0 +1,26 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+IPDL_SOURCES += [
+    'PVideoDecoderManager.ipdl',
+]
+
+EXPORTS.mozilla.dom += [
+    'MediaIPCUtils.h',
+    'VideoDecoderManagerChild.h',
+    'VideoDecoderManagerParent.h',
+]
+
+SOURCES += [
+    'VideoDecoderManagerChild.cpp',
+    'VideoDecoderManagerParent.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+
+FINAL_LIBRARY = 'xul'
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -21,16 +21,17 @@ with Files('GetUserMedia*'):
 
 DIRS += [
     'encoder',
     'flac',
     'gmp',
     'gmp-plugin',
     'gmp-plugin-openh264',
     'imagecapture',
+    'ipc',
     'mediasink',
     'mediasource',
     'ogg',
     'platforms',
     'systemservices',
     'wave',
     'webaudio',
     'webm',
--- a/gfx/ipc/GPUParent.cpp
+++ b/gfx/ipc/GPUParent.cpp
@@ -12,16 +12,17 @@
 #include "gfxPrefs.h"
 #include "GPUProcessHost.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/dom/VideoDecoderManagerParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/ImageBridgeParent.h"
 #include "nsDebugImpl.h"
 #include "mozilla/layers/LayerTreeOwnerTracker.h"
 #include "ProcessUtils.h"
 #include "prenv.h"
 #include "VRManager.h"
 #include "VRManagerParent.h"
@@ -253,16 +254,22 @@ GPUParent::RecvNewContentImageBridge(End
 
 bool
 GPUParent::RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint)
 {
   return VRManagerParent::CreateForContent(Move(aEndpoint));
 }
 
 bool
+GPUParent::RecvNewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent>&& aEndpoint)
+{
+  return dom::VideoDecoderManagerParent::CreateForContent(Move(aEndpoint));
+}
+
+bool
 GPUParent::RecvDeallocateLayerTreeId(const uint64_t& aLayersId)
 {
   CompositorBridgeParent::DeallocateLayerTreeId(aLayersId);
   return true;
 }
 
 bool
 GPUParent::RecvAddLayerTreeIdMapping(const uint64_t& aLayersId, const ProcessId& aOwnerId)
--- a/gfx/ipc/GPUParent.h
+++ b/gfx/ipc/GPUParent.h
@@ -36,16 +36,17 @@ public:
     Endpoint<PCompositorBridgeParent>&& aEndpoint,
     const CSSToLayoutDeviceScale& aScale,
     const TimeDuration& aVsyncRate,
     const bool& aUseExternalSurface,
     const IntSize& aSurfaceSize) override;
   bool RecvNewContentCompositorBridge(Endpoint<PCompositorBridgeParent>&& aEndpoint) override;
   bool RecvNewContentImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
   bool RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
+  bool RecvNewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent>&& aEndpoint) override;
   bool RecvDeallocateLayerTreeId(const uint64_t& aLayersId) override;
   bool RecvGetDeviceStatus(GPUDeviceData* aOutStatus) override;
   bool RecvAddLayerTreeIdMapping(const uint64_t& aLayersId, const ProcessId& aOwnerId) override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
 private:
   RefPtr<VsyncBridgeParent> mVsyncBridge;
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -21,16 +21,18 @@
 #endif
 #include "nsBaseWidget.h"
 #include "nsContentUtils.h"
 #include "VRManagerChild.h"
 #include "VRManagerParent.h"
 #include "VsyncBridgeChild.h"
 #include "VsyncIOThreadHolder.h"
 #include "VsyncSource.h"
+#include "mozilla/dom/VideoDecoderManagerChild.h"
+#include "mozilla/dom/VideoDecoderManagerParent.h"
 
 namespace mozilla {
 namespace gfx {
 
 using namespace mozilla::layers;
 
 static StaticAutoPtr<GPUProcessManager> sSingleton;
 
@@ -511,16 +513,43 @@ GPUProcessManager::CreateContentVRManage
       return false;
     }
   }
 
   *aOutEndpoint = Move(childPipe);
   return true;
 }
 
+bool
+GPUProcessManager::CreateContentVideoDecoderManager(base::ProcessId aOtherProcess,
+                                                    ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndpoint)
+{
+  if (!mGPUChild) {
+    return false;
+  }
+
+  ipc::Endpoint<dom::PVideoDecoderManagerParent> parentPipe;
+  ipc::Endpoint<dom::PVideoDecoderManagerChild> childPipe;
+
+  nsresult rv = dom::PVideoDecoderManager::CreateEndpoints(
+    mGPUChild->OtherPid(),
+    aOtherProcess,
+    &parentPipe,
+    &childPipe);
+  if (NS_FAILED(rv)) {
+    gfxCriticalNote << "Could not create content video decoder: " << hexa(int(rv));
+    return false;
+  }
+
+  mGPUChild->SendNewContentVideoDecoderManager(Move(parentPipe));
+
+  *aOutEndpoint = Move(childPipe);
+  return true;
+}
+
 already_AddRefed<IAPZCTreeManager>
 GPUProcessManager::GetAPZCTreeManagerForLayers(uint64_t aLayersId)
 {
   return CompositorBridgeParent::GetAPZCTreeManager(aLayersId);
 }
 
 void
 GPUProcessManager::MapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId)
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -31,16 +31,17 @@ class PCompositorBridgeChild;
 class PImageBridgeChild;
 } // namespace layers
 namespace widget {
 class CompositorWidget;
 } // namespace widget
 namespace dom {
 class ContentParent;
 class TabParent;
+class PVideoDecoderManagerChild;
 } // namespace dom
 namespace ipc {
 class GeckoChildProcessHost;
 } // namespace ipc
 namespace gfx {
 
 class GPUChild;
 class VsyncBridgeChild;
@@ -83,16 +84,18 @@ public:
     const gfx::IntSize& aSurfaceSize);
 
   bool CreateContentCompositorBridge(base::ProcessId aOtherProcess,
                                      ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint);
   bool CreateContentImageBridge(base::ProcessId aOtherProcess,
                                 ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
   bool CreateContentVRManager(base::ProcessId aOtherProcess,
                               ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
+  bool CreateContentVideoDecoderManager(base::ProcessId aOtherProcess,
+                                        ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint);
 
   // This returns a reference to the APZCTreeManager to which
   // pan/zoom-related events can be sent.
   already_AddRefed<IAPZCTreeManager> GetAPZCTreeManagerForLayers(uint64_t aLayersId);
 
   // Maps the layer tree and process together so that aOwningPID is allowed
   // to access aLayersId across process.
   void MapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId);
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include GraphicsMessages;
 include protocol PCompositorBridge;
 include protocol PImageBridge;
 include protocol PVRManager;
 include protocol PVsyncBridge;
+include protocol PVideoDecoderManager;
 
 using base::ProcessId from "base/process.h";
 using mozilla::TimeDuration from "mozilla/TimeStamp.h";
 using mozilla::CSSToLayoutDeviceScale from "Units.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
 
 namespace mozilla {
 namespace gfx {
@@ -51,16 +52,17 @@ parent:
                             TimeDuration vsyncRate,
                             bool useExternalSurface,
                             IntSize surfaceSize);
 
   // Create a new content-process compositor bridge.
   async NewContentCompositorBridge(Endpoint<PCompositorBridgeParent> endpoint);
   async NewContentImageBridge(Endpoint<PImageBridgeParent> endpoint);
   async NewContentVRManager(Endpoint<PVRManagerParent> endpoint);
+  async NewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent> endpoint);
 
   async DeallocateLayerTreeId(uint64_t layersId);
 
   // Called to notify the GPU process of who owns a layersId.
   sync AddLayerTreeIdMapping(uint64_t layersId, ProcessId ownerId);
 
   // Request the current DeviceStatus from the GPU process. This blocks until
   // one is available (i.e., Init has completed).
--- a/gfx/layers/client/GPUVideoTextureClient.cpp
+++ b/gfx/layers/client/GPUVideoTextureClient.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GPUVideoTextureClient.h"
+#include "mozilla/dom/VideoDecoderManagerChild.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
 
 bool
 GPUVideoTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
@@ -29,16 +30,17 @@ GPUVideoTextureData::FillInfo(TextureDat
   aInfo.hasSynchronization = false;
   aInfo.supportsMoz2D = false;
   aInfo.canExposeMappedData = false;
 }
 
 void
 GPUVideoTextureData::Deallocate(ClientIPCAllocator* aAllocator)
 {
+  dom::VideoDecoderManagerChild::GetSingleton()->DeallocateSurfaceDescriptorGPUVideo(mSD);
   mSD = SurfaceDescriptorGPUVideo();
 }
 
 void
 GPUVideoTextureData::Forget(ClientIPCAllocator* aAllocator)
 {
   // We always need to manually deallocate on the client side.
   // Ideally we'd set up our TextureClient with the DEALLOCATE_CLIENT
--- a/gfx/layers/composite/GPUVideoTextureHost.cpp
+++ b/gfx/layers/composite/GPUVideoTextureHost.cpp
@@ -1,24 +1,26 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GPUVideoTextureHost.h"
+#include "mozilla/dom/VideoDecoderManagerParent.h"
 #include "ImageContainer.h"
 
 namespace mozilla {
 namespace layers {
 
 GPUVideoTextureHost::GPUVideoTextureHost(TextureFlags aFlags,
                                          const SurfaceDescriptorGPUVideo& aDescriptor)
   : TextureHost(aFlags)
 {
   MOZ_COUNT_CTOR(GPUVideoTextureHost);
+  mImage = dom::VideoDecoderManagerParent::LookupImage(aDescriptor);
 }
 
 GPUVideoTextureHost::~GPUVideoTextureHost()
 {
   MOZ_COUNT_DTOR(GPUVideoTextureHost);
 }
 
 bool
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -62,16 +62,17 @@
 #include "DOMStorageObserver.h"
 #include "CacheObserver.h"
 #include "DisplayItemClip.h"
 #include "ActiveLayerTracker.h"
 #include "CounterStyleManager.h"
 #include "FrameLayerBuilder.h"
 #include "AnimationCommon.h"
 #include "LayerAnimationInfo.h"
+#include "mozilla/dom/VideoDecoderManagerChild.h"
 
 #include "AudioChannelService.h"
 #include "mozilla/dom/PromiseDebugging.h"
 #include "mozilla/dom/WebCryptoThreadPool.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #include "nsXULContentUtils.h"
@@ -302,16 +303,18 @@ nsLayoutStatics::Initialize()
 
 #ifdef DEBUG
   nsStyleContext::Initialize();
   mozilla::LayerAnimationInfo::Initialize();
 #endif
 
   MediaDecoder::InitStatics();
 
+  VideoDecoderManagerChild::Initialize();
+
   PromiseDebugging::Init();
 
   mozilla::dom::devicestorage::DeviceStorageStatics::Initialize();
 
   mozilla::dom::WebCryptoThreadPool::Initialize();
 
   // NB: We initialize servo in nsAppRunner.cpp, because we need to do it after
   // creating the hidden DOM window to support some current stylo hacks. We
@@ -385,16 +388,18 @@ nsLayoutStatics::Shutdown()
   nsGlobalWindow::ShutDown();
   nsDOMClassInfo::ShutDown();
   WebIDLGlobalNameHash::Shutdown();
   nsListControlFrame::Shutdown();
   nsXBLService::Shutdown();
   nsAutoCopyListener::Shutdown();
   FrameLayerBuilder::Shutdown();
 
+  VideoDecoderManagerChild::Shutdown();
+
 #ifdef MOZ_ANDROID_OMX
   AndroidMediaPluginHost::Shutdown();
 #endif
 
   CubebUtils::ShutdownLibrary();
   AsyncLatencyLogger::ShutdownLogger();
   WebAudioUtils::Shutdown();