Bug 1288618 - Part 15: Add media code facing RemoteVideoDecoder. r?cpearce,dvander draft
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 15 Sep 2016 14:25:58 +1200
changeset 413868 0baff1e537e718bad1605a233db351a7fd638a40
parent 413867 cd5d97a41b873c05c69afa15268b7d35b88f72a5
child 531329 5d32d4e17da415ca93b4237dd8be5a2a762ca9f6
push id29543
push usermwoodrow@mozilla.com
push dateThu, 15 Sep 2016 02:36:28 +0000
reviewerscpearce, dvander
bugs1288618
milestone51.0a1
Bug 1288618 - Part 15: Add media code facing RemoteVideoDecoder. r?cpearce,dvander * * * [mq]: fix MozReview-Commit-ID: CwAfpmFXBIM
dom/media/ipc/RemoteVideoDecoder.cpp
dom/media/ipc/RemoteVideoDecoder.h
dom/media/ipc/VideoDecoderManagerChild.cpp
dom/media/ipc/VideoDecoderManagerChild.h
dom/media/ipc/moz.build
dom/media/platforms/PDMFactory.cpp
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);