From 637309d62da056476a9c25407e68a20caa81c8e9 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 15 Sep 2016 23:18:00 +1200 Subject: [PATCH] Bug 1288618 - Part 14: Add PVideoDecoder protocol for individual decoders. r=cpearce,dvander --- dom/media/ipc/PVideoDecoder.ipdl | 75 +++++++ dom/media/ipc/PVideoDecoderManager.ipdl | 3 + dom/media/ipc/VideoDecoderChild.cpp | 208 ++++++++++++++++++ dom/media/ipc/VideoDecoderChild.h | 71 ++++++ dom/media/ipc/VideoDecoderManagerChild.cpp | 21 ++ dom/media/ipc/VideoDecoderManagerChild.h | 5 + dom/media/ipc/VideoDecoderManagerParent.cpp | 22 ++ dom/media/ipc/VideoDecoderManagerParent.h | 5 + dom/media/ipc/VideoDecoderParent.cpp | 227 ++++++++++++++++++++ dom/media/ipc/VideoDecoderParent.h | 66 ++++++ dom/media/ipc/moz.build | 3 + 11 files changed, 706 insertions(+) create mode 100644 dom/media/ipc/PVideoDecoder.ipdl create mode 100644 dom/media/ipc/VideoDecoderChild.cpp create mode 100644 dom/media/ipc/VideoDecoderChild.h create mode 100644 dom/media/ipc/VideoDecoderParent.cpp create mode 100644 dom/media/ipc/VideoDecoderParent.h diff --git a/dom/media/ipc/PVideoDecoder.ipdl b/dom/media/ipc/PVideoDecoder.ipdl new file mode 100644 index 000000000000..b44e0f753d3d --- /dev/null +++ b/dom/media/ipc/PVideoDecoder.ipdl @@ -0,0 +1,75 @@ +/* -*- 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 "mozilla/dom/MediaIPCUtils.h"; + +include protocol PVideoDecoderManager; +include LayersSurfaces; +using VideoInfo from "MediaInfo.h"; +using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h"; + +namespace mozilla { +namespace dom { + +struct MediaDataIPDL +{ + int64_t offset; + int64_t time; + int64_t timecode; + int64_t duration; + uint32_t frames; + bool keyframe; +}; + +struct VideoDataIPDL +{ + MediaDataIPDL base; + IntSize display; + SurfaceDescriptorGPUVideo sd; + int32_t frameID; +}; + +struct MediaRawDataIPDL +{ + MediaDataIPDL base; + Shmem buffer; +}; + +// This protocol provides a way to use MediaDataDecoder/MediaDataDecoderCallback +// across processes. The parent side currently is only implemented to work with +// Window Media Foundation, but can be extended easily to support other backends. +// The child side runs in the content process, and the parent side runs in the +// GPU process. We run a separate IPDL thread for both sides. +async protocol PVideoDecoder +{ + manager PVideoDecoderManager; +parent: + async Init(VideoInfo info, LayersBackend backend); + + async Input(MediaRawDataIPDL data); + + async Flush(); + async Drain(); + async Shutdown(); + + async __delete__(); + +child: + + async InitComplete(); + async InitFailed(nsresult reason); + + // Each output includes a SurfaceDescriptorGPUVideo that represents the decoded + // frame. This SurfaceDescriptor can be used on the Layers IPDL protocol, but + // must be released explicitly using DeallocateSurfaceDescriptorGPUVideo + // on the manager protocol. + async Output(VideoDataIPDL data); + async InputExhausted(); + async DrainComplete(); + async Error(nsresult error); +}; + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/ipc/PVideoDecoderManager.ipdl b/dom/media/ipc/PVideoDecoderManager.ipdl index 1f95771c3ac5..143ce026251b 100644 --- a/dom/media/ipc/PVideoDecoderManager.ipdl +++ b/dom/media/ipc/PVideoDecoderManager.ipdl @@ -3,6 +3,7 @@ * 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 protocol PVideoDecoder; include LayersSurfaces; include "mozilla/dom/MediaIPCUtils.h"; @@ -11,7 +12,9 @@ namespace dom { async protocol PVideoDecoderManager { + manages PVideoDecoder; parent: + async PVideoDecoder(); async DeallocateSurfaceDescriptorGPUVideo(SurfaceDescriptorGPUVideo sd); }; diff --git a/dom/media/ipc/VideoDecoderChild.cpp b/dom/media/ipc/VideoDecoderChild.cpp new file mode 100644 index 000000000000..a233d2091844 --- /dev/null +++ b/dom/media/ipc/VideoDecoderChild.cpp @@ -0,0 +1,208 @@ +/* -*- 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 "VideoDecoderChild.h" +#include "VideoDecoderManagerChild.h" +#include "mozilla/layers/TextureClient.h" +#include "base/thread.h" +#include "MediaInfo.h" +#include "ImageContainer.h" +#include "GPUVideoImage.h" + +namespace mozilla { +namespace dom { + +using base::Thread; +using namespace ipc; +using namespace layers; +using namespace gfx; + +VideoDecoderChild::VideoDecoderChild() + : mThread(VideoDecoderManagerChild::GetManagerThread()) + , mCanSend(true) +{ +} + +VideoDecoderChild::~VideoDecoderChild() +{ + AssertOnManagerThread(); + mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); +} + +bool +VideoDecoderChild::RecvOutput(const VideoDataIPDL& aData) +{ + AssertOnManagerThread(); + VideoInfo info(aData.display().width, aData.display().height); + + // The Image here creates a TextureData object that takes ownership + // of the SurfaceDescriptor, and is responsible for making sure that + // it gets deallocated. + RefPtr image = new GPUVideoImage(aData.sd(), aData.display()); + + RefPtr video = VideoData::CreateFromImage(info, + aData.base().offset(), + aData.base().time(), + aData.base().duration(), + image, + aData.base().keyframe(), + aData.base().timecode(), + IntRect()); + mCallback->Output(video); + return true; +} + +bool +VideoDecoderChild::RecvInputExhausted() +{ + AssertOnManagerThread(); + mCallback->InputExhausted(); + return true; +} + +bool +VideoDecoderChild::RecvDrainComplete() +{ + AssertOnManagerThread(); + mCallback->DrainComplete(); + return true; +} + +bool +VideoDecoderChild::RecvError(const nsresult& aError) +{ + AssertOnManagerThread(); + mCallback->Error(aError); + return true; +} + +bool +VideoDecoderChild::RecvInitComplete() +{ + AssertOnManagerThread(); + mInitPromise.Resolve(TrackInfo::kVideoTrack, __func__); + return true; +} + +bool +VideoDecoderChild::RecvInitFailed(const nsresult& aReason) +{ + AssertOnManagerThread(); + mInitPromise.Reject(aReason, __func__); + return true; +} + +void +VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy) +{ + mCanSend = false; +} + +void +VideoDecoderChild::InitIPDL(MediaDataDecoderCallback* aCallback, + const VideoInfo& aVideoInfo, + layers::LayersBackend aLayersBackend) +{ + VideoDecoderManagerChild::GetSingleton()->SendPVideoDecoderConstructor(this); + mIPDLSelfRef = this; + mCallback = aCallback; + mVideoInfo = aVideoInfo; + mLayersBackend = aLayersBackend; +} + +void +VideoDecoderChild::DestroyIPDL() +{ + if (mCanSend) { + PVideoDecoderChild::Send__delete__(this); + } +} + +void +VideoDecoderChild::IPDLActorDestroyed() +{ + mIPDLSelfRef = nullptr; +} + +// MediaDataDecoder methods + +RefPtr +VideoDecoderChild::Init() +{ + AssertOnManagerThread(); + if (!mCanSend || !SendInit(mVideoInfo, mLayersBackend)) { + return MediaDataDecoder::InitPromise::CreateAndReject( + NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); + } + return mInitPromise.Ensure(__func__); +} + +void +VideoDecoderChild::Input(MediaRawData* aSample) +{ + AssertOnManagerThread(); + if (!mCanSend) { + mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + return; + } + + // TODO: It would be nice to add an allocator method to + // MediaDataDecoder so that the demuxer could write directly + // into shmem rather than requiring a copy here. + Shmem buffer; + if (!AllocShmem(aSample->Size(), Shmem::SharedMemory::TYPE_BASIC, &buffer)) { + mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + return; + } + + memcpy(buffer.get(), aSample->Data(), aSample->Size()); + + MediaRawDataIPDL sample(MediaDataIPDL(aSample->mOffset, + aSample->mTime, + aSample->mTimecode, + aSample->mDuration, + aSample->mFrames, + aSample->mKeyframe), + buffer); + if (!SendInput(sample)) { + mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + } +} + +void +VideoDecoderChild::Flush() +{ + AssertOnManagerThread(); + if (!mCanSend || !SendFlush()) { + mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + } +} + +void +VideoDecoderChild::Drain() +{ + AssertOnManagerThread(); + if (!mCanSend || !SendDrain()) { + mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + } +} + +void +VideoDecoderChild::Shutdown() +{ + AssertOnManagerThread(); + if (!mCanSend || !SendShutdown()) { + mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + } +} + +void +VideoDecoderChild::AssertOnManagerThread() +{ + MOZ_ASSERT(NS_GetCurrentThread() == mThread); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/ipc/VideoDecoderChild.h b/dom/media/ipc/VideoDecoderChild.h new file mode 100644 index 000000000000..ce68c2f692da --- /dev/null +++ b/dom/media/ipc/VideoDecoderChild.h @@ -0,0 +1,71 @@ +/* -*- 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_VideoDecoderChild_h +#define include_dom_ipc_VideoDecoderChild_h + +#include "mozilla/RefPtr.h" +#include "mozilla/dom/PVideoDecoderChild.h" +#include "MediaData.h" +#include "PlatformDecoderModule.h" + +namespace mozilla { +namespace dom { + +class RemoteVideoDecoder; +class RemoteDecoderModule; + +class VideoDecoderChild final : public PVideoDecoderChild +{ +public: + explicit VideoDecoderChild(); + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderChild) + + // PVideoDecoderChild + bool RecvOutput(const VideoDataIPDL& aData) override; + bool RecvInputExhausted() override; + bool RecvDrainComplete() override; + bool RecvError(const nsresult& aError) override; + bool RecvInitComplete() override; + bool RecvInitFailed(const nsresult& aReason) override; + + void ActorDestroy(ActorDestroyReason aWhy) override; + + RefPtr Init(); + void Input(MediaRawData* aSample); + void Flush(); + void Drain(); + void Shutdown(); + + void InitIPDL(MediaDataDecoderCallback* aCallback, + const VideoInfo& aVideoInfo, + layers::LayersBackend aLayersBackend); + void DestroyIPDL(); + + // Called from IPDL when our actor has been destroyed + void IPDLActorDestroyed(); + +private: + ~VideoDecoderChild(); + + void AssertOnManagerThread(); + + RefPtr mIPDLSelfRef; + RefPtr mThread; + + MediaDataDecoderCallback* mCallback; + + MozPromiseHolder mInitPromise; + + VideoInfo mVideoInfo; + layers::LayersBackend mLayersBackend; + bool mCanSend; +}; + +} // namespace dom +} // namespace mozilla + +#endif // include_dom_ipc_VideoDecoderChild_h diff --git a/dom/media/ipc/VideoDecoderManagerChild.cpp b/dom/media/ipc/VideoDecoderManagerChild.cpp index d6260bda0448..01cff6b88513 100644 --- a/dom/media/ipc/VideoDecoderManagerChild.cpp +++ b/dom/media/ipc/VideoDecoderManagerChild.cpp @@ -4,6 +4,7 @@ * 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 "VideoDecoderChild.h" #include "mozilla/dom/ContentChild.h" #include "MediaPrefs.h" #include "nsThreadUtils.h" @@ -87,6 +88,26 @@ VideoDecoderManagerChild::GetSingleton() return sDecoderManager; } +/* static */ nsIThread* +VideoDecoderManagerChild::GetManagerThread() +{ + return sVideoDecoderChildThread; +} + +PVideoDecoderChild* +VideoDecoderManagerChild::AllocPVideoDecoderChild() +{ + return new VideoDecoderChild(); +} + +bool +VideoDecoderManagerChild::DeallocPVideoDecoderChild(PVideoDecoderChild* actor) +{ + VideoDecoderChild* child = static_cast(actor); + child->IPDLActorDestroyed(); + return true; +} + void VideoDecoderManagerChild::Open(Endpoint&& aEndpoint) { diff --git a/dom/media/ipc/VideoDecoderManagerChild.h b/dom/media/ipc/VideoDecoderManagerChild.h index 0310e2e46f1d..40daa514eee0 100644 --- a/dom/media/ipc/VideoDecoderManagerChild.h +++ b/dom/media/ipc/VideoDecoderManagerChild.h @@ -18,6 +18,7 @@ public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerChild) static VideoDecoderManagerChild* GetSingleton(); + static nsIThread* GetManagerThread(); // Can be called from any thread, dispatches the request to the IPDL thread internally. void DeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD); @@ -28,6 +29,10 @@ public: static void Initialize(); static void Shutdown(); +protected: + PVideoDecoderChild* AllocPVideoDecoderChild() override; + bool DeallocPVideoDecoderChild(PVideoDecoderChild* actor) override; + private: VideoDecoderManagerChild() {} diff --git a/dom/media/ipc/VideoDecoderManagerParent.cpp b/dom/media/ipc/VideoDecoderManagerParent.cpp index 0eb786ff7e26..045893c277ae 100644 --- a/dom/media/ipc/VideoDecoderManagerParent.cpp +++ b/dom/media/ipc/VideoDecoderManagerParent.cpp @@ -4,6 +4,7 @@ * 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/StaticMutex.h" #include "mozilla/UniquePtr.h" @@ -159,6 +160,12 @@ VideoDecoderManagerParent::ShutdownThreads() sVideoDecoderManagerThread = nullptr; } +bool +VideoDecoderManagerParent::OnManagerThread() +{ + return NS_GetCurrentThread() == sVideoDecoderManagerThread; +} + bool VideoDecoderManagerParent::CreateForContent(Endpoint&& aEndpoint) { @@ -190,6 +197,21 @@ VideoDecoderManagerParent::~VideoDecoderManagerParent() ClearAllOwnedImages(); } +PVideoDecoderParent* +VideoDecoderManagerParent::AllocPVideoDecoderParent() +{ + RefPtr target = sVideoDecoderTaskThread;; + return new VideoDecoderParent(this, sManagerTaskQueue, new TaskQueue(target.forget())); +} + +bool +VideoDecoderManagerParent::DeallocPVideoDecoderParent(PVideoDecoderParent* actor) +{ + VideoDecoderParent* parent = static_cast(actor); + parent->Destroy(); + return true; +} + void VideoDecoderManagerParent::Open(Endpoint&& aEndpoint) { diff --git a/dom/media/ipc/VideoDecoderManagerParent.h b/dom/media/ipc/VideoDecoderManagerParent.h index 71a7c789e162..3e2289cab4b5 100644 --- a/dom/media/ipc/VideoDecoderManagerParent.h +++ b/dom/media/ipc/VideoDecoderManagerParent.h @@ -25,7 +25,12 @@ public: static void StartupThreads(); static void ShutdownThreads(); + bool OnManagerThread(); + protected: + PVideoDecoderParent* AllocPVideoDecoderParent() override; + bool DeallocPVideoDecoderParent(PVideoDecoderParent* actor) override; + bool RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) override; void ActorDestroy(mozilla::ipc::IProtocolManager::ActorDestroyReason) override {} diff --git a/dom/media/ipc/VideoDecoderParent.cpp b/dom/media/ipc/VideoDecoderParent.cpp new file mode 100644 index 000000000000..2b9509e675f1 --- /dev/null +++ b/dom/media/ipc/VideoDecoderParent.cpp @@ -0,0 +1,227 @@ +/* -*- 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 "VideoDecoderParent.h" +#include "mozilla/Unused.h" +#include "mozilla/layers/CompositorThread.h" +#include "base/thread.h" +#include "mozilla/layers/TextureHost.h" +#include "mozilla/layers/PTextureParent.h" +#include "MediaInfo.h" +#include "VideoDecoderManagerParent.h" +#ifdef XP_WIN +#include "WMFDecoderModule.h" +#endif + +namespace mozilla { +namespace dom { + +using base::Thread; +using namespace ipc; +using namespace layers; +using namespace gfx; + +VideoDecoderParent::VideoDecoderParent(VideoDecoderManagerParent* aParent, + TaskQueue* aManagerTaskQueue, + TaskQueue* aDecodeTaskQueue) + : mParent(aParent) + , mManagerTaskQueue(aManagerTaskQueue) + , mDecodeTaskQueue(aDecodeTaskQueue) + , mDestroyed(false) +{ + MOZ_COUNT_CTOR(VideoDecoderParent); + // We hold a reference to ourselves to keep us alive until IPDL + // explictly destroys us. There may still be refs held by + // tasks, but no new ones should be added after we're + // destroyed. + mIPDLSelfRef = this; +} + +VideoDecoderParent::~VideoDecoderParent() +{ + MOZ_COUNT_DTOR(VideoDecoderParent); +} + +void +VideoDecoderParent::Destroy() +{ + mDecodeTaskQueue->AwaitShutdownAndIdle(); + mDestroyed = true; + mIPDLSelfRef = nullptr; +} + +bool +VideoDecoderParent::RecvInit(const VideoInfo& aInfo, const layers::LayersBackend& aBackend) +{ + CreateDecoderParams params(aInfo); + params.mTaskQueue = mDecodeTaskQueue; + params.mCallback = this; + params.mLayersBackend = aBackend; + params.mImageContainer = new layers::ImageContainer(); + +#ifdef XP_WIN + // TODO: Ideally we wouldn't hardcode the WMF PDM, and we'd use the normal PDM + // factory logic for picking a decoder. + WMFDecoderModule::Init(); + RefPtr pdm(new WMFDecoderModule()); + pdm->Startup(); + + mDecoder = pdm->CreateVideoDecoder(params); + if (!mDecoder) { + Unused << SendInitFailed(NS_ERROR_DOM_MEDIA_FATAL_ERR); + return true; + } +#else + MOZ_ASSERT(false, "Can't use RemoteVideoDecoder on non-Windows platforms yet"); +#endif + + RefPtr self = this; + mDecoder->Init()->Then(mManagerTaskQueue, __func__, + [self] (TrackInfo::TrackType aTrack) { + if (!self->mDestroyed) { + Unused << self->SendInitComplete(); + } + }, + [self] (MediaResult aReason) { + if (!self->mDestroyed) { + Unused << self->SendInitFailed(aReason); + } + }); + return true; +} + +bool +VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData) +{ + // XXX: This copies the data into a buffer owned by the MediaRawData. Ideally we'd just take ownership + // of the shmem. + RefPtr data = new MediaRawData(aData.buffer().get(), aData.buffer().Size()); + data->mOffset = aData.base().offset(); + data->mTime = aData.base().time(); + data->mTimecode = aData.base().timecode(); + data->mDuration = aData.base().duration(); + data->mKeyframe = aData.base().keyframe(); + + DeallocShmem(aData.buffer()); + + mDecoder->Input(data); + return true; +} + +bool +VideoDecoderParent::RecvFlush() +{ + MOZ_ASSERT(!mDestroyed); + mDecoder->Flush(); + return true; +} + +bool +VideoDecoderParent::RecvDrain() +{ + MOZ_ASSERT(!mDestroyed); + mDecoder->Drain(); + return true; +} + +bool +VideoDecoderParent::RecvShutdown() +{ + MOZ_ASSERT(!mDestroyed); + mDecoder->Shutdown(); + mDecoder = nullptr; + return true; +} + +void +VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy) +{ + MOZ_ASSERT(!mDestroyed); + if (mDecoder) { + mDecoder->Shutdown(); + mDecoder = nullptr; + } + if (mDecodeTaskQueue) { + mDecodeTaskQueue->BeginShutdown(); + } +} + +void +VideoDecoderParent::Output(MediaData* aData) +{ + MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn()); + RefPtr self = this; + RefPtr data = aData; + mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self, data]() { + if (self->mDestroyed) { + return; + } + + MOZ_ASSERT(data->mType == MediaData::VIDEO_DATA, "Can only decode videos using VideoDecoderParent!"); + VideoData* video = static_cast(data.get()); + + MOZ_ASSERT(video->mImage, "Decoded video must output a layer::Image to be used with VideoDecoderParent"); + + VideoDataIPDL output(MediaDataIPDL(data->mOffset, + data->mTime, + data->mTimecode, + data->mDuration, + data->mFrames, + data->mKeyframe), + video->mDisplay, + self->GetManager()->StoreImage(video->mImage), + video->mFrameID); + Unused << self->SendOutput(output); + })); +} + +void +VideoDecoderParent::Error(const MediaResult& aError) +{ + MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn()); + RefPtr self = this; + MediaResult error = aError; + mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self, error]() { + if (!self->mDestroyed) { + Unused << self->SendError(error); + } + })); +} + +void +VideoDecoderParent::InputExhausted() +{ + MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn()); + RefPtr self = this; + mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self]() { + if (!self->mDestroyed) { + Unused << self->SendInputExhausted(); + } + })); +} + +void +VideoDecoderParent::DrainComplete() +{ + MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn()); + RefPtr self = this; + mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self]() { + if (!self->mDestroyed) { + Unused << self->SendDrainComplete(); + } + })); +} + +bool +VideoDecoderParent::OnReaderTaskQueue() +{ + // Most of our calls into mDecoder come directly from IPDL so are on + // the right thread, but not actually on the task queue. We only ever + // run a single thread, not a pool, so this should work fine. + return mParent->OnManagerThread(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/ipc/VideoDecoderParent.h b/dom/media/ipc/VideoDecoderParent.h new file mode 100644 index 000000000000..3ef21e75f70a --- /dev/null +++ b/dom/media/ipc/VideoDecoderParent.h @@ -0,0 +1,66 @@ +/* -*- 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_VideoDecoderParent_h +#define include_dom_ipc_VideoDecoderParent_h + +#include "mozilla/RefPtr.h" +#include "mozilla/dom/PVideoDecoderParent.h" +#include "VideoDecoderManagerParent.h" +#include "MediaData.h" +#include "ImageContainer.h" + +namespace mozilla { +namespace dom { + +class VideoDecoderParent final : public PVideoDecoderParent, + public MediaDataDecoderCallback +{ +public: + // We refcount this class since the task queue can have runnables + // that reference us. + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderParent) + + VideoDecoderParent(VideoDecoderManagerParent* aParent, + TaskQueue* aManagerTaskQueue, + TaskQueue* aDecodeTaskQueue); + + void Destroy(); + + // PVideoDecoderParent + bool RecvInit(const VideoInfo& aVideoInfo, const layers::LayersBackend& aBackend) override; + bool RecvInput(const MediaRawDataIPDL& aData) override; + bool RecvFlush() override; + bool RecvDrain() override; + bool RecvShutdown() override; + + void ActorDestroy(ActorDestroyReason aWhy) override; + + // MediaDataDecoderCallback + void Output(MediaData* aData) override; + void Error(const MediaResult& aError) override; + void InputExhausted() override; + void DrainComplete() override; + bool OnReaderTaskQueue() override; + +private: + ~VideoDecoderParent(); + + VideoDecoderManagerParent* GetManager() { return static_cast(Manager()); } + + RefPtr mParent; + RefPtr mIPDLSelfRef; + RefPtr mManagerTaskQueue; + RefPtr mDecodeTaskQueue; + RefPtr mDecoder; + + // Can only be accessed from the manager thread + bool mDestroyed; +}; + +} // namespace dom +} // namespace mozilla + +#endif // include_dom_ipc_VideoDecoderParent_h diff --git a/dom/media/ipc/moz.build b/dom/media/ipc/moz.build index b3ce8e7b517d..8ce841ca8c17 100644 --- a/dom/media/ipc/moz.build +++ b/dom/media/ipc/moz.build @@ -6,6 +6,7 @@ IPDL_SOURCES += [ + 'PVideoDecoder.ipdl', 'PVideoDecoderManager.ipdl', ] @@ -16,8 +17,10 @@ EXPORTS.mozilla.dom += [ ] SOURCES += [ + 'VideoDecoderChild.cpp', 'VideoDecoderManagerChild.cpp', 'VideoDecoderManagerParent.cpp', + 'VideoDecoderParent.cpp', ] include('/ipc/chromium/chromium-config.mozbuild')