summaryrefslogtreecommitdiffstats
path: root/dom/media/ipc/VideoDecoderManagerParent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/ipc/VideoDecoderManagerParent.cpp')
-rw-r--r--dom/media/ipc/VideoDecoderManagerParent.cpp238
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