diff options
Diffstat (limited to 'dom/media/ipc/VideoDecoderManagerParent.cpp')
-rw-r--r-- | dom/media/ipc/VideoDecoderManagerParent.cpp | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/dom/media/ipc/VideoDecoderManagerParent.cpp b/dom/media/ipc/VideoDecoderManagerParent.cpp new file mode 100644 index 000000000..a111b5e53 --- /dev/null +++ b/dom/media/ipc/VideoDecoderManagerParent.cpp @@ -0,0 +1,238 @@ +/* -*- 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 "VideoDecoderParent.h" +#include "base/thread.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" +#include "mozilla/layers/VideoBridgeChild.h" +#include "mozilla/SharedThreadPool.h" +#include "mozilla/layers/ImageDataSerializer.h" +#include "mozilla/SyncRunnable.h" + +#if XP_WIN +#include <objbase.h> +#endif + +namespace mozilla { +namespace dom { + +using base::Thread; +using namespace ipc; +using namespace layers; +using namespace gfx; + +SurfaceDescriptorGPUVideo +VideoDecoderManagerParent::StoreImage(Image* aImage, TextureClient* aTexture) +{ + mImageMap[aTexture->GetSerial()] = aImage; + mTextureMap[aTexture->GetSerial()] = aTexture; + return SurfaceDescriptorGPUVideo(aTexture->GetSerial()); +} + +StaticRefPtr<nsIThread> sVideoDecoderManagerThread; +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 + sVideoDecoderManagerThread->Dispatch(NS_NewRunnableFunction([]() { + layers::VideoBridgeChild::Startup(); + }), NS_DISPATCH_NORMAL); + + sManagerTaskQueue = new TaskQueue(managerThread.forget()); + + ManagerThreadShutdownObserver* obs = new ManagerThreadShutdownObserver(); + observerService->AddObserver(obs, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); +} + +void +VideoDecoderManagerParent::ShutdownThreads() +{ + sManagerTaskQueue->BeginShutdown(); + sManagerTaskQueue->AwaitShutdownAndIdle(); + sManagerTaskQueue = nullptr; + + sVideoDecoderManagerThread->Shutdown(); + sVideoDecoderManagerThread = nullptr; +} + +void +VideoDecoderManagerParent::ShutdownVideoBridge() +{ + if (sVideoDecoderManagerThread) { + RefPtr<Runnable> task = NS_NewRunnableFunction([]() { + VideoBridgeChild::Shutdown(); + }); + SyncRunnable::DispatchToThread(sVideoDecoderManagerThread, task); + } +} + +bool +VideoDecoderManagerParent::OnManagerThread() +{ + return NS_GetCurrentThread() == sVideoDecoderManagerThread; +} + +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); +} + +PVideoDecoderParent* +VideoDecoderManagerParent::AllocPVideoDecoderParent() +{ + return new VideoDecoderParent(this, sManagerTaskQueue, new TaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("VideoDecoderParent"), 4))); +} + +bool +VideoDecoderManagerParent::DeallocPVideoDecoderParent(PVideoDecoderParent* actor) +{ + VideoDecoderParent* parent = static_cast<VideoDecoderParent*>(actor); + parent->Destroy(); + return true; +} + +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::RecvReadback(const SurfaceDescriptorGPUVideo& aSD, SurfaceDescriptor* aResult) +{ + RefPtr<Image> image = mImageMap[aSD.handle()]; + if (!image) { + *aResult = null_t(); + return true; + } + + RefPtr<SourceSurface> source = image->GetAsSourceSurface(); + if (!image) { + *aResult = null_t(); + return true; + } + + SurfaceFormat format = source->GetFormat(); + IntSize size = source->GetSize(); + size_t length = ImageDataSerializer::ComputeRGBBufferSize(size, format); + + Shmem buffer; + if (!length || !AllocShmem(length, Shmem::SharedMemory::TYPE_BASIC, &buffer)) { + *aResult = null_t(); + return true; + } + + RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(gfx::BackendType::CAIRO, + buffer.get<uint8_t>(), size, + ImageDataSerializer::ComputeRGBStride(format, size.width), + format); + if (!dt) { + DeallocShmem(buffer); + *aResult = null_t(); + return true; + } + + dt->CopySurface(source, IntRect(0, 0, size.width, size.height), IntPoint()); + dt->Flush(); + + *aResult = SurfaceDescriptorBuffer(RGBDescriptor(size, format, true), MemoryOrShmem(buffer)); + return true; +} + +bool +VideoDecoderManagerParent::RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) +{ + mImageMap.erase(aSD.handle()); + mTextureMap.erase(aSD.handle()); + return true; +} + +} // namespace dom +} // namespace mozilla |