Bug 1288618 - Part 15: Add media code facing RemoteVideoDecoder. r?cpearce,dvander
* * *
[mq]: fix
MozReview-Commit-ID: CwAfpmFXBIM
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/RemoteVideoDecoder.cpp
@@ -0,0 +1,145 @@
+/* -*- 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 "RemoteVideoDecoder.h"
+#include "VideoDecoderChild.h"
+#include "VideoDecoderManagerChild.h"
+#include "mozilla/layers/TextureClient.h"
+#include "base/thread.h"
+#include "MediaInfo.h"
+#include "ImageContainer.h"
+
+namespace mozilla {
+namespace dom {
+
+using base::Thread;
+using namespace ipc;
+using namespace layers;
+using namespace gfx;
+
+RemoteVideoDecoder::RemoteVideoDecoder(MediaDataDecoderCallback* aCallback)
+ : mActor(new VideoDecoderChild())
+{
+#ifdef DEBUG
+ mCallback = aCallback;
+#endif
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+}
+
+RemoteVideoDecoder::~RemoteVideoDecoder()
+{
+ // We're about to be destroyed and drop our ref to
+ // VideoDecoderChild. Make sure we put a ref into the
+ // task queue for the VideoDecoderChild thread to keep
+ // it alive until we send the delete message.
+ RefPtr<VideoDecoderChild> actor = mActor;
+ VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([actor]() {
+ MOZ_ASSERT(actor);
+ actor->DestroyIPDL();
+ }), NS_DISPATCH_NORMAL);
+}
+
+RefPtr<MediaDataDecoder::InitPromise>
+RemoteVideoDecoder::Init()
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ return InvokeAsync(VideoDecoderManagerChild::GetManagerAbstractThread(),
+ this, __func__, &RemoteVideoDecoder::InitInternal);
+}
+
+RefPtr<MediaDataDecoder::InitPromise>
+RemoteVideoDecoder::InitInternal()
+{
+ MOZ_ASSERT(mActor);
+ MOZ_ASSERT(NS_GetCurrentThread() == VideoDecoderManagerChild::GetManagerThread());
+ return mActor->Init();
+}
+
+void
+RemoteVideoDecoder::Input(MediaRawData* aSample)
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ RefPtr<RemoteVideoDecoder> self = this;
+ RefPtr<MediaRawData> sample = aSample;
+ VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([self, sample]() {
+ MOZ_ASSERT(self->mActor);
+ self->mActor->Input(sample);
+ }), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteVideoDecoder::Flush()
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ RefPtr<RemoteVideoDecoder> self = this;
+ VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([self]() {
+ MOZ_ASSERT(self->mActor);
+ self->mActor->Flush();
+ }), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteVideoDecoder::Drain()
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ RefPtr<RemoteVideoDecoder> self = this;
+ VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([self]() {
+ MOZ_ASSERT(self->mActor);
+ self->mActor->Drain();
+ }), NS_DISPATCH_NORMAL);
+}
+
+void
+RemoteVideoDecoder::Shutdown()
+{
+ MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+ RefPtr<RemoteVideoDecoder> self = this;
+ VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([self]() {
+ MOZ_ASSERT(self->mActor);
+ self->mActor->Shutdown();
+ }), NS_DISPATCH_NORMAL);
+}
+
+nsresult
+RemoteDecoderModule::Startup()
+{
+ if (!VideoDecoderManagerChild::GetSingleton()) {
+ return NS_ERROR_FAILURE;
+ }
+ return mWrapped->Startup();
+}
+
+bool
+RemoteDecoderModule::SupportsMimeType(const nsACString& aMimeType,
+ DecoderDoctorDiagnostics* aDiagnostics) const
+{
+ return mWrapped->SupportsMimeType(aMimeType, aDiagnostics);
+}
+
+PlatformDecoderModule::ConversionRequired
+RemoteDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const
+{
+ return mWrapped->DecoderNeedsConversion(aConfig);
+}
+
+already_AddRefed<MediaDataDecoder>
+RemoteDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
+{
+ MediaDataDecoderCallback* callback = aParams.mCallback;
+ MOZ_ASSERT(callback->OnReaderTaskQueue());
+ RefPtr<RemoteVideoDecoder> object = new RemoteVideoDecoder(callback);
+
+ VideoInfo info = aParams.VideoConfig();
+
+ layers::LayersBackend backend = aParams.mLayersBackend;
+ VideoDecoderManagerChild::GetManagerThread()->Dispatch(NS_NewRunnableFunction([object, callback, info, backend]() {
+ object->mActor->InitIPDL(callback, info, backend);
+ }), NS_DISPATCH_NORMAL);
+
+ return object.forget();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/RemoteVideoDecoder.h
@@ -0,0 +1,85 @@
+/* -*- 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_RemoteVideoDecoder_h
+#define include_dom_ipc_RemoteVideoDecoder_h
+
+#include "mozilla/RefPtr.h"
+#include "mozilla/DebugOnly.h"
+#include "MediaData.h"
+#include "PlatformDecoderModule.h"
+
+namespace mozilla {
+namespace dom {
+
+class VideoDecoderChild;
+class RemoteDecoderModule;
+
+// A MediaDataDecoder implementation that proxies through IPDL
+// to a 'real' decoder in the GPU process.
+// All requests get forwarded to a VideoDecoderChild instance that
+// operates solely on the VideoDecoderManagerChild thread.
+class RemoteVideoDecoder : public MediaDataDecoder
+{
+public:
+ friend class RemoteDecoderModule;
+
+ // MediaDataDecoder
+ RefPtr<InitPromise> Init() override;
+ void Input(MediaRawData* aSample) override;
+ void Flush() override;
+ void Drain() override;
+ void Shutdown() override;
+ void ConfigurationChanged(const TrackInfo& aConfig) override { MOZ_ASSERT(false); }
+
+ const char* GetDescriptionName() const override { return "RemoteVideoDecoder"; }
+
+private:
+ explicit RemoteVideoDecoder(MediaDataDecoderCallback* aCallback);
+ ~RemoteVideoDecoder();
+
+ RefPtr<InitPromise> InitInternal();
+
+ // Only ever written to from the reader task queue (during the constructor and destructor
+ // when we can guarantee no other threads are accessing it). Only read from the manager
+ // thread.
+ RefPtr<VideoDecoderChild> mActor;
+#ifdef DEBUG
+ MediaDataDecoderCallback* mCallback;
+#endif
+};
+
+// A PDM implementation that creates RemoteVideoDecoders.
+// We currently require a 'wrapped' PDM in order to be able to answer SupportsMimeType
+// and DecoderNeedsConversion. Ideally we'd check these over IPDL using the manager
+// protocol
+class RemoteDecoderModule : public PlatformDecoderModule
+{
+public:
+ explicit RemoteDecoderModule(PlatformDecoderModule* aWrapped)
+ : mWrapped(aWrapped)
+ {}
+
+ virtual nsresult Startup() override;
+
+ virtual bool SupportsMimeType(const nsACString& aMimeType,
+ DecoderDoctorDiagnostics* aDiagnostics) const override;
+
+ virtual ConversionRequired DecoderNeedsConversion(const TrackInfo& aConfig) const override;
+
+ virtual already_AddRefed<MediaDataDecoder>
+ CreateVideoDecoder(const CreateDecoderParams& aParams) override;
+
+ virtual already_AddRefed<MediaDataDecoder>
+ CreateAudioDecoder(const CreateDecoderParams& aParams) override { return nullptr; }
+
+private:
+ RefPtr<PlatformDecoderModule> mWrapped;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // include_dom_ipc_RemoteVideoDecoder_h
--- a/dom/media/ipc/VideoDecoderManagerChild.cpp
+++ b/dom/media/ipc/VideoDecoderManagerChild.cpp
@@ -12,16 +12,17 @@
namespace mozilla {
namespace dom {
using namespace ipc;
using namespace layers;
using namespace gfx;
StaticRefPtr<nsIThread> sVideoDecoderChildThread;
+StaticRefPtr<AbstractThread> sVideoDecoderChildAbstractThread;
static StaticRefPtr<VideoDecoderManagerChild> sDecoderManager;
/* static */ void
VideoDecoderManagerChild::Initialize()
{
MOZ_ASSERT(NS_IsMainThread());
MediaPrefs::GetSingleton();
@@ -36,16 +37,19 @@ VideoDecoderManagerChild::Initialize()
return;
}
if (!sVideoDecoderChildThread) {
RefPtr<nsIThread> childThread;
nsresult rv = NS_NewNamedThread("VideoChild", getter_AddRefs(childThread));
NS_ENSURE_SUCCESS_VOID(rv);
sVideoDecoderChildThread = childThread;
+
+ sVideoDecoderChildAbstractThread =
+ AbstractThread::CreateXPCOMThreadWrapper(childThread, false);
}
Endpoint<PVideoDecoderManagerChild> endpoint;
if (!ContentChild::GetSingleton()->SendInitVideoDecoderManager(&endpoint)) {
return;
}
// TODO: The above message should return an empty endpoint if there wasn't a GPU
@@ -72,16 +76,17 @@ VideoDecoderManagerChild::Shutdown()
MOZ_ASSERT(sDecoderManager);
sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([]() {
sDecoderManager->Close();
}), NS_DISPATCH_SYNC);
sDecoderManager = nullptr;
+ sVideoDecoderChildAbstractThread = nullptr;
sVideoDecoderChildThread->Shutdown();
sVideoDecoderChildThread = nullptr;
}
}
/* static */ VideoDecoderManagerChild*
VideoDecoderManagerChild::GetSingleton()
{
@@ -89,16 +94,22 @@ VideoDecoderManagerChild::GetSingleton()
}
/* static */ nsIThread*
VideoDecoderManagerChild::GetManagerThread()
{
return sVideoDecoderChildThread;
}
+/* static */ AbstractThread*
+VideoDecoderManagerChild::GetManagerAbstractThread()
+{
+ return sVideoDecoderChildAbstractThread;
+}
+
PVideoDecoderChild*
VideoDecoderManagerChild::AllocPVideoDecoderChild()
{
return new VideoDecoderChild();
}
bool
VideoDecoderManagerChild::DeallocPVideoDecoderChild(PVideoDecoderChild* actor)
--- a/dom/media/ipc/VideoDecoderManagerChild.h
+++ b/dom/media/ipc/VideoDecoderManagerChild.h
@@ -14,16 +14,17 @@ namespace dom {
class VideoDecoderManagerChild final : public PVideoDecoderManagerChild
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerChild)
static VideoDecoderManagerChild* GetSingleton();
static nsIThread* GetManagerThread();
+ static AbstractThread* GetManagerAbstractThread();
// 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();
--- a/dom/media/ipc/moz.build
+++ b/dom/media/ipc/moz.build
@@ -7,21 +7,23 @@
IPDL_SOURCES += [
'PVideoDecoder.ipdl',
'PVideoDecoderManager.ipdl',
]
EXPORTS.mozilla.dom += [
'MediaIPCUtils.h',
+ 'RemoteVideoDecoder.h',
'VideoDecoderManagerChild.h',
'VideoDecoderManagerParent.h',
]
SOURCES += [
+ 'RemoteVideoDecoder.cpp',
'VideoDecoderChild.cpp',
'VideoDecoderManagerChild.cpp',
'VideoDecoderManagerParent.cpp',
'VideoDecoderParent.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -42,16 +42,17 @@
#ifdef MOZ_EME
#include "EMEDecoderModule.h"
#include "mozilla/CDMProxy.h"
#endif
#include "DecoderDoctorDiagnostics.h"
#include "MP4Decoder.h"
+#include "mozilla/dom/RemoteVideoDecoder.h"
#include "mp4_demuxer/H264.h"
namespace mozilla {
extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
@@ -317,17 +318,21 @@ PDMFactory::CreatePDMs()
MediaPrefs::PDMAndroidMediaCodecEnabled()) {
m = new AndroidDecoderModule();
StartupPDM(m);
}
#endif
#ifdef XP_WIN
if (MediaPrefs::PDMWMFEnabled()) {
m = new WMFDecoderModule();
- mWMFFailedToLoad = !StartupPDM(m);
+ RefPtr<PlatformDecoderModule> remote = new dom::RemoteDecoderModule(m);
+ mWMFFailedToLoad = !StartupPDM(remote);
+ if (mWMFFailedToLoad) {
+ mWMFFailedToLoad = !StartupPDM(m);
+ }
} else {
mWMFFailedToLoad = MediaPrefs::DecoderDoctorWMFDisabledIsFailure();
}
#endif
#ifdef MOZ_FFVPX
if (MediaPrefs::PDMFFVPXEnabled()) {
m = FFVPXRuntimeLinker::CreateDecoderModule();
StartupPDM(m);