Bug 1288618 - Part 13: Add VideoDecoderManager protocol. r=dvander

This commit is contained in:
Matt Woodrow 2016-09-21 21:25:33 +12:00
Родитель 9dee8747d7
Коммит 7756c8a512
18 изменённых файлов: 534 добавлений и 0 удалений

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

@ -1059,6 +1059,13 @@ ContentParent::RecvFindPlugins(const uint32_t& aPluginEpoch,
return true;
}
bool
ContentParent::RecvInitVideoDecoderManager(Endpoint<PVideoDecoderManagerChild>* aEndpoint)
{
GPUProcessManager::Get()->CreateContentVideoDecoderManager(OtherPid(), aEndpoint);
return true;
}
/*static*/ TabParent*
ContentParent::CreateBrowserOrApp(const TabContext& aContext,
Element* aFrameElement,

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

@ -271,6 +271,8 @@ public:
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,

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

@ -56,6 +56,7 @@ include protocol PWebBrowserPersistDocument;
include protocol PWebrtcGlobal;
include protocol PPresentation;
include protocol PVRManager;
include protocol PVideoDecoderManager;
include protocol PFlyWebPublishedServer;
include DOMTypes;
include JavaScriptTypes;
@ -788,6 +789,8 @@ parent:
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
sync InitVideoDecoderManager() returns (Endpoint<PVideoDecoderManagerChild> endpoint);
/**
* Is this token compatible with the provided version?
*

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

@ -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

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

@ -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

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

@ -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

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

@ -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

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

@ -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

26
dom/media/ipc/moz.build Normal file
Просмотреть файл

@ -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'

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

@ -26,6 +26,7 @@ DIRS += [
'gmp-plugin',
'gmp-plugin-openh264',
'imagecapture',
'ipc',
'mediasink',
'mediasource',
'ogg',

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

@ -17,6 +17,7 @@
#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"
@ -257,6 +258,12 @@ 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)
{

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

@ -41,6 +41,7 @@ public:
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;

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

@ -27,6 +27,8 @@
#include "VsyncBridgeChild.h"
#include "VsyncIOThreadHolder.h"
#include "VsyncSource.h"
#include "mozilla/dom/VideoDecoderManagerChild.h"
#include "mozilla/dom/VideoDecoderManagerParent.h"
namespace mozilla {
namespace gfx {
@ -617,6 +619,33 @@ GPUProcessManager::CreateContentVRManager(base::ProcessId aOtherProcess,
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)
{

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

@ -37,6 +37,7 @@ class CompositorWidget;
namespace dom {
class ContentParent;
class TabParent;
class PVideoDecoderManagerChild;
} // namespace dom
namespace ipc {
class GeckoChildProcessHost;
@ -92,6 +93,8 @@ public:
ipc::Endpoint<PCompositorBridgeChild>* aOutCompositor,
ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
ipc::Endpoint<PVRManagerChild>* aOutVRBridge);
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.

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

@ -8,6 +8,7 @@ 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";
@ -56,6 +57,7 @@ parent:
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);

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

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GPUVideoTextureClient.h"
#include "mozilla/dom/VideoDecoderManagerChild.h"
namespace mozilla {
namespace layers {
@ -34,6 +35,7 @@ GPUVideoTextureData::FillInfo(TextureData::Info& aInfo) const
void
GPUVideoTextureData::Deallocate(ClientIPCAllocator* aAllocator)
{
dom::VideoDecoderManagerChild::GetSingleton()->DeallocateSurfaceDescriptorGPUVideo(mSD);
mSD = SurfaceDescriptorGPUVideo();
}

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

@ -4,6 +4,7 @@
* 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 {
@ -14,6 +15,7 @@ GPUVideoTextureHost::GPUVideoTextureHost(TextureFlags aFlags,
: TextureHost(aFlags)
{
MOZ_COUNT_CTOR(GPUVideoTextureHost);
mImage = dom::VideoDecoderManagerParent::LookupImage(aDescriptor);
}
GPUVideoTextureHost::~GPUVideoTextureHost()

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

@ -67,6 +67,7 @@
#include "FrameLayerBuilder.h"
#include "AnimationCommon.h"
#include "LayerAnimationInfo.h"
#include "mozilla/dom/VideoDecoderManagerChild.h"
#include "AudioChannelService.h"
#include "mozilla/dom/PromiseDebugging.h"
@ -307,6 +308,8 @@ nsLayoutStatics::Initialize()
MediaDecoder::InitStatics();
VideoDecoderManagerChild::Initialize();
PromiseDebugging::Init();
mozilla::dom::devicestorage::DeviceStorageStatics::Initialize();
@ -390,6 +393,8 @@ nsLayoutStatics::Shutdown()
nsAutoCopyListener::Shutdown();
FrameLayerBuilder::Shutdown();
VideoDecoderManagerChild::Shutdown();
#ifdef MOZ_ANDROID_OMX
AndroidMediaPluginHost::Shutdown();
#endif