Bug 1288618 - Part 16: Add media code facing RemoteVideoDecoder. r?cpearce,dvander draft
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 05 Sep 2016 16:24:33 +1200
changeset 409775 8f42ffa6cacdfcf069fb2d5f2cd7aeadb15da66d
parent 409774 233a2051130c8825443f8f93e21f021bf9451991
child 530405 2167701ece927c07dfdfcd8cdd977a463b69de6d
push id28541
push usermwoodrow@mozilla.com
push dateMon, 05 Sep 2016 04:26:09 +0000
reviewerscpearce, dvander
bugs1288618
milestone51.0a1
Bug 1288618 - Part 16: Add media code facing RemoteVideoDecoder. r?cpearce,dvander MozReview-Commit-ID: buEP5MvIS0
dom/media/ipc/RemoteVideoDecoder.cpp
dom/media/ipc/RemoteVideoDecoder.h
dom/media/ipc/moz.build
dom/media/platforms/PDMFactory.cpp
gfx/thebes/gfxPrefs.h
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/RemoteVideoDecoder.cpp
@@ -0,0 +1,146 @@
+/* -*- 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(nullptr)
+  , mCallback(aCallback)
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+}
+
+RemoteVideoDecoder::~RemoteVideoDecoder()
+{
+  VideoDecoderChild* actor = mActor;
+  VideoDecoderManagerChild::GetMessageLoop()->PostTask(NS_NewRunnableFunction([actor]() {
+    MOZ_ASSERT(actor);
+    PVideoDecoderChild::Send__delete__(actor);
+  }));
+}
+
+RefPtr<MediaDataDecoder::InitPromise>
+RemoteVideoDecoder::Init()
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  MozPromiseHolder<InitPromise> promise;
+  RefPtr<MediaDataDecoder::InitPromise> p = promise.Ensure(__func__);
+  RefPtr<MediaDataDecoder::InitPromise::Private> val = promise.Steal();
+  RefPtr<RemoteVideoDecoder> self = this;
+  VideoDecoderManagerChild::GetMessageLoop()->PostTask(NS_NewRunnableFunction([self, val]() mutable {
+    MOZ_ASSERT(self->mActor);
+    self->mActor->Init(val);
+  }));
+  return p;
+}
+
+nsresult
+RemoteVideoDecoder::Input(MediaRawData* aSample)
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  RefPtr<RemoteVideoDecoder> self = this;
+  RefPtr<MediaRawData> sample = aSample;
+  VideoDecoderManagerChild::GetMessageLoop()->PostTask(NS_NewRunnableFunction([self, sample]() {
+    MOZ_ASSERT(self->mActor);
+    self->mActor->Input(sample);
+  }));
+  return NS_OK;
+}
+
+nsresult
+RemoteVideoDecoder::Flush()
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  RefPtr<RemoteVideoDecoder> self = this;
+  VideoDecoderManagerChild::GetMessageLoop()->PostTask(NS_NewRunnableFunction([self]() {
+    MOZ_ASSERT(self->mActor);
+    self->mActor->Flush();
+  }));
+  return NS_OK;
+}
+
+nsresult
+RemoteVideoDecoder::Drain()
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  RefPtr<RemoteVideoDecoder> self = this;
+  VideoDecoderManagerChild::GetMessageLoop()->PostTask(NS_NewRunnableFunction([self]() {
+    MOZ_ASSERT(self->mActor);
+    self->mActor->Drain();
+  }));
+  return NS_OK;
+}
+
+nsresult
+RemoteVideoDecoder::Shutdown()
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+  RefPtr<RemoteVideoDecoder> self = this;
+  VideoDecoderManagerChild::GetMessageLoop()->PostTask(NS_NewRunnableFunction([self]() {
+    MOZ_ASSERT(self->mActor);
+    self->mActor->Shutdown();
+  }));
+  return NS_OK;
+}
+
+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::GetMessageLoop()->PostTask(NS_NewRunnableFunction([object, callback, info, backend]() {
+    VideoDecoderChild* child = static_cast<VideoDecoderChild*>(VideoDecoderManagerChild::GetSingleton()->SendPVideoDecoderConstructor());
+    object->mActor = child;
+    object->mActor->mCallback = callback;
+    object->mActor->mVideoInfo = info;
+    object->mActor->mLayersBackend = backend;
+  }));
+
+  return object.forget();
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/ipc/RemoteVideoDecoder.h
@@ -0,0 +1,78 @@
+/* -*- 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 "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;
+  nsresult Input(MediaRawData* aSample) override;
+  nsresult Flush() override;
+  nsresult Drain() override;
+  nsresult Shutdown() override;
+  nsresult ConfigurationChanged(const TrackInfo& aConfig) { MOZ_ASSERT(false); }
+
+  virtual const char* GetDescriptionName() const override { return "RemoteVideoDecoder"; }
+  
+private:
+  RemoteVideoDecoder(MediaDataDecoderCallback* aCallback);
+  ~RemoteVideoDecoder();
+
+  // Only ever accessed or written to from the manager thread (excluding the destructor)
+  VideoDecoderChild* mActor;
+  MediaDataDecoderCallback* mCallback;
+};
+
+// 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:
+  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/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);
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -471,17 +471,17 @@ private:
   // decrease it until we hit mid gray at -1 contrast, after that it gets weird.
   DECL_GFX_PREF(Live, "layers.effect.contrast",                LayersEffectContrast, float, 0.0f);
   DECL_GFX_PREF(Live, "layers.effect.grayscale",               LayersEffectGrayscale, bool, false);
   DECL_GFX_PREF(Live, "layers.effect.invert",                  LayersEffectInvert, bool, false);
   DECL_GFX_PREF(Once, "layers.enable-tiles",                   LayersTilesEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.flash-borders",                  FlashLayerBorders, bool, false);
   DECL_GFX_PREF(Once, "layers.force-shmem-tiles",              ForceShmemTiles, bool, false);
   DECL_GFX_PREF(Live, "layers.frame-counter",                  DrawFrameCounter, bool, false);
-  DECL_GFX_PREF(Once, "layers.gpu-process.dev.enabled",        GPUProcessDevEnabled, bool, false);
+  DECL_GFX_PREF(Once, "layers.gpu-process.dev.enabled",        GPUProcessDevEnabled, bool, true);
   DECL_GFX_PREF(Once, "layers.gpu-process.dev.timeout_ms",     GPUProcessDevTimeoutMs, int32_t, 5000);
   DECL_GFX_PREF(Once, "layers.gralloc.disable",                DisableGralloc, bool, false);
   DECL_GFX_PREF(Live, "layers.low-precision-buffer",           UseLowPrecisionBuffer, bool, false);
   DECL_GFX_PREF(Live, "layers.low-precision-opacity",          LowPrecisionOpacity, float, 1.0f);
   DECL_GFX_PREF(Live, "layers.low-precision-resolution",       LowPrecisionResolution, float, 0.25f);
   DECL_GFX_PREF(Live, "layers.max-active",                     MaxActiveLayers, int32_t, -1);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);