Bug 1306529 - Add initial implementation of PureOmxPlatformLayer r?jya draft
authorTakuro Ashie <ashie@clear-code.com>
Wed, 18 Apr 2018 11:38:12 +0900
changeset 784106 1a5f4814afff3eeece6704ea2ca56c0190f0feca
parent 783966 789e30ff2e3d6e1fcfce1a373c1e5635488d24da
child 784107 eab5f39bd504983b589541fa8038cffd7d53d004
push id106858
push userbmo:ashie@clear-code.com
push dateWed, 18 Apr 2018 05:30:01 +0000
reviewersjya
bugs1306529
milestone61.0a1
Bug 1306529 - Add initial implementation of PureOmxPlatformLayer r?jya It's a concrete class of OmxPlatformLayer for accessing OpenMAX IL libraries directly. It will be usable on various embedded linux systems. Note that it's not enabled by default yet. Add the following config to your mozconfig. ac_add_options --enable-openmax TODO: Implement zero-copy mode MozReview-Commit-ID: EMEXAKzzR64
dom/media/platforms/PDMFactory.cpp
dom/media/platforms/moz.build
dom/media/platforms/omx/OmxCoreLibLinker.cpp
dom/media/platforms/omx/OmxCoreLibLinker.h
dom/media/platforms/omx/OmxDataDecoder.cpp
dom/media/platforms/omx/OmxDataDecoder.h
dom/media/platforms/omx/OmxDecoderModule.cpp
dom/media/platforms/omx/OmxDecoderModule.h
dom/media/platforms/omx/OmxFunctionList.h
dom/media/platforms/omx/OmxPlatformLayer.cpp
dom/media/platforms/omx/PureOmxPlatformLayer.cpp
dom/media/platforms/omx/PureOmxPlatformLayer.h
dom/media/platforms/omx/moz.build
modules/libpref/init/StaticPrefList.h
toolkit/moz.configure
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -17,16 +17,19 @@
 #include "FFmpegRuntimeLinker.h"
 #endif
 #ifdef MOZ_APPLEMEDIA
 #include "AppleDecoderModule.h"
 #endif
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidDecoderModule.h"
 #endif
+#ifdef MOZ_OMX
+#include "OmxDecoderModule.h"
+#endif
 #include "GMPDecoderModule.h"
 
 #include "mozilla/CDMProxy.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SharedThreadPool.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/StaticPrefs.h"
 #include "mozilla/SyncRunnable.h"
@@ -58,16 +61,19 @@ public:
   PDMFactoryImpl()
   {
 #ifdef XP_WIN
     WMFDecoderModule::Init();
 #endif
 #ifdef MOZ_APPLEMEDIA
     AppleDecoderModule::Init();
 #endif
+#ifdef MOZ_OMX
+    OmxDecoderModule::Init();
+#endif
 #ifdef MOZ_FFVPX
     FFVPXRuntimeLinker::Init();
 #endif
 #ifdef MOZ_FFMPEG
     FFmpegRuntimeLinker::Init();
 #endif
   }
 };
@@ -348,16 +354,22 @@ PDMFactory::CreatePDMs()
     RefPtr<PlatformDecoderModule> remote = new dom::RemoteDecoderModule(m);
     StartupPDM(remote);
     mWMFFailedToLoad = !StartupPDM(m);
   } else {
     mWMFFailedToLoad =
       StaticPrefs::MediaDecoderDoctorWmfDisabledIsFailure();
   }
 #endif
+#ifdef MOZ_OMX
+  if (StaticPrefs::MediaOmxEnabled()) {
+    m = OmxDecoderModule::Create();
+    StartupPDM(m);
+  }
+#endif
 #ifdef MOZ_FFVPX
   if (StaticPrefs::MediaFfvpxEnabled()) {
     m = FFVPXRuntimeLinker::CreateDecoderModule();
     StartupPDM(m);
   }
 #endif
 #ifdef MOZ_FFMPEG
   if (StaticPrefs::MediaFfmpegEnabled()) {
--- a/dom/media/platforms/moz.build
+++ b/dom/media/platforms/moz.build
@@ -65,16 +65,24 @@ if CONFIG['MOZ_FFMPEG']:
 if CONFIG['MOZ_AV1']:
     EXPORTS += [
         'agnostic/AOMDecoder.h',
     ]
     UNIFIED_SOURCES += [
         'agnostic/AOMDecoder.cpp',
     ]
 
+if CONFIG['MOZ_OMX']:
+    EXPORTS += [
+        'omx/OmxCoreLibLinker.h',
+    ]
+    UNIFIED_SOURCES += [
+        'omx/OmxCoreLibLinker.cpp',
+    ]
+
 if CONFIG['MOZ_APPLEMEDIA']:
   EXPORTS += [
       'apple/AppleDecoderModule.h',
   ]
   UNIFIED_SOURCES += [
       'apple/AppleATDecoder.cpp',
       'apple/AppleCMLinker.cpp',
       'apple/AppleDecoderModule.cpp',
new file mode 100644
--- /dev/null
+++ b/dom/media/platforms/omx/OmxCoreLibLinker.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "OmxCoreLibLinker.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Preferences.h"
+#include "MainThreadUtils.h"
+#include "prlink.h"
+#include "PlatformDecoderModule.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("OmxCoreLibLinker::%s: " arg, __func__, ##__VA_ARGS__))
+
+namespace mozilla
+{
+
+OmxCoreLibLinker::LinkStatus OmxCoreLibLinker::sLinkStatus =
+  LinkStatus_INIT;
+
+const char* OmxCoreLibLinker::sLibNames[] = {
+  "libopenmaxil.so",        // Raspberry Pi
+  "libomxr_core.so",        // Renesas R-Car, RZ/G
+  "libomxil-bellagio.so.0", // Bellagio: An OSS implementation of OpenMAX IL
+};
+
+PRLibrary* OmxCoreLibLinker::sLinkedLib = nullptr;
+const char* OmxCoreLibLinker::sLibName = nullptr;
+
+#define OMX_FUNC(func) void (*func)();
+#include "OmxFunctionList.h"
+#undef OMX_FUNC
+
+bool
+OmxCoreLibLinker::TryLinkingLibrary(const char *libName)
+{
+  PRLibSpec lspec;
+  lspec.type = PR_LibSpec_Pathname;
+  lspec.value.pathname = libName;
+  sLinkedLib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
+  if (sLinkedLib) {
+    if (Bind(libName)) {
+      sLibName = libName;
+      LOG("Succeeded to load %s", libName);
+      return true;
+    } else {
+      LOG("Failed to link %s", libName);
+    }
+    Unlink();
+  }
+  return false;
+}
+
+/* static */ bool
+OmxCoreLibLinker::Link()
+{
+  LOG("");
+
+  if (sLinkStatus) {
+    return sLinkStatus == LinkStatus_SUCCEEDED;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoCString libPath;
+  nsresult rv = Preferences::GetCString("media.omx.core-lib-path", libPath);
+  if (NS_SUCCEEDED(rv) && !libPath.IsEmpty()) {
+    if (TryLinkingLibrary(libPath.Data())) {
+      sLinkStatus = LinkStatus_SUCCEEDED;
+      return true;
+    }
+  }
+
+  // try known paths
+  for (size_t i = 0; i < ArrayLength(sLibNames); i++) {
+    if (TryLinkingLibrary(sLibNames[i])) {
+      sLinkStatus = LinkStatus_SUCCEEDED;
+      return true;
+    }
+  }
+  sLinkStatus = LinkStatus_FAILED;
+  return false;
+}
+
+/* static */ bool
+OmxCoreLibLinker::Bind(const char* aLibName)
+{
+#define OMX_FUNC(func)                                                  \
+  {                                                                     \
+    if (!(func = (typeof(func))PR_FindSymbol(sLinkedLib, #func))) {     \
+      LOG("Couldn't load function " #func " from %s.", aLibName);       \
+      return false;                                                     \
+    }                                                                   \
+  }
+#include "OmxFunctionList.h"
+#undef OMX_FUNC
+  return true;
+}
+
+/* static */ void
+OmxCoreLibLinker::Unlink()
+{
+  LOG("");
+
+  if (sLinkedLib) {
+    PR_UnloadLibrary(sLinkedLib);
+    sLinkedLib = nullptr;
+    sLibName = nullptr;
+    sLinkStatus = LinkStatus_INIT;
+  }
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/platforms/omx/OmxCoreLibLinker.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 __OmxCoreLibLinker_h__
+#define __OmxCoreLibLinker_h__
+
+struct PRLibrary;
+
+namespace mozilla
+{
+
+class OmxCoreLibLinker
+{
+public:
+  static bool Link();
+  static void Unlink();
+
+private:
+  static PRLibrary* sLinkedLib;
+  static const char* sLibName;
+  static const char* sLibNames[];
+
+  static bool TryLinkingLibrary(const char *libName);
+  static bool Bind(const char* aLibName);
+
+  static enum LinkStatus
+  {
+    LinkStatus_INIT = 0,
+    LinkStatus_FAILED,
+    LinkStatus_SUCCEEDED
+  } sLinkStatus;
+};
+
+}
+
+#endif // __OmxCoreLibLinker_h__
--- a/dom/media/platforms/omx/OmxDataDecoder.cpp
+++ b/dom/media/platforms/omx/OmxDataDecoder.cpp
@@ -95,18 +95,20 @@ protected:
 
   AudioCompactor mAudioCompactor;
 
   // video output
   RefPtr<layers::ImageContainer> mImageContainer;
 };
 
 OmxDataDecoder::OmxDataDecoder(const TrackInfo& aTrackInfo,
+                               TaskQueue* aTaskQueue,
                                layers::ImageContainer* aImageContainer)
   : mOmxTaskQueue(CreateMediaDecodeTaskQueue("OmxDataDecoder::mOmxTaskQueue"))
+  , mTaskQueue(aTaskQueue)
   , mImageContainer(aImageContainer)
   , mWatchManager(this, mOmxTaskQueue)
   , mOmxState(OMX_STATETYPE::OMX_StateInvalid, "OmxDataDecoder::mOmxState")
   , mTrackInfo(aTrackInfo.Clone())
   , mFlushing(false)
   , mShuttingDown(false)
   , mCheckingInputExhausted(false)
   , mPortSettingsChanged(-1, "OmxDataDecoder::mPortSettingsChanged")
--- a/dom/media/platforms/omx/OmxDataDecoder.h
+++ b/dom/media/platforms/omx/OmxDataDecoder.h
@@ -62,16 +62,17 @@ class OmxDataDecoder
   : public MediaDataDecoder
   , public DecoderDoctorLifeLogger<OmxDataDecoder>
 {
 protected:
   virtual ~OmxDataDecoder();
 
 public:
   OmxDataDecoder(const TrackInfo& aTrackInfo,
+                 TaskQueue* aTaskQueue,
                  layers::ImageContainer* aImageContainer);
 
   RefPtr<InitPromise> Init() override;
   RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
   RefPtr<DecodePromise> Drain() override;
   RefPtr<FlushPromise> Flush() override;
   RefPtr<ShutdownPromise> Shutdown() override;
 
@@ -155,16 +156,18 @@ protected:
 
   // aType could be OMX_DirMax for all types.
   RefPtr<OmxPromiseLayer::OmxBufferPromise::AllPromiseType>
   CollectBufferPromises(OMX_DIRTYPE aType);
 
   // The Omx TaskQueue.
   RefPtr<TaskQueue> mOmxTaskQueue;
 
+  RefPtr<TaskQueue> mTaskQueue;
+
   RefPtr<layers::ImageContainer> mImageContainer;
 
   WatchManager<OmxDataDecoder> mWatchManager;
 
   // It is accessed in omx TaskQueue.
   Watchable<OMX_STATETYPE> mOmxState;
 
   RefPtr<OmxPromiseLayer> mOmxLayer;
--- a/dom/media/platforms/omx/OmxDecoderModule.cpp
+++ b/dom/media/platforms/omx/OmxDecoderModule.cpp
@@ -4,30 +4,56 @@
  * 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 "OmxDecoderModule.h"
 
 #include "OmxDataDecoder.h"
 #include "OmxPlatformLayer.h"
 
+#ifdef MOZ_OMX
+#include "PureOmxPlatformLayer.h"
+#endif
+
 namespace mozilla {
 
+/* static */ bool
+OmxDecoderModule::Init()
+{
+#ifdef MOZ_OMX
+  return PureOmxPlatformLayer::Init();
+#endif
+  return false;
+}
+
+OmxDecoderModule*
+OmxDecoderModule::Create()
+{
+#ifdef MOZ_OMX
+  if (Init()) {
+    return new OmxDecoderModule();
+  }
+#endif
+  return nullptr;
+}
+
 already_AddRefed<MediaDataDecoder>
 OmxDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
 {
   RefPtr<OmxDataDecoder> decoder = new OmxDataDecoder(aParams.mConfig,
+                                                      aParams.mTaskQueue,
                                                       aParams.mImageContainer);
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 OmxDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
 {
   RefPtr<OmxDataDecoder> decoder = new OmxDataDecoder(aParams.mConfig,
+                                                      aParams.mTaskQueue,
                                                       nullptr);
   return decoder.forget();
 }
 
 bool
 OmxDecoderModule::SupportsMimeType(const nsACString& aMimeType,
                                    DecoderDoctorDiagnostics* aDiagnostics) const
 {
--- a/dom/media/platforms/omx/OmxDecoderModule.h
+++ b/dom/media/platforms/omx/OmxDecoderModule.h
@@ -9,16 +9,20 @@
 
 #include "PlatformDecoderModule.h"
 
 namespace mozilla {
 
 class OmxDecoderModule : public PlatformDecoderModule
 {
 public:
+  // Called on main thread.
+  static bool Init();
+  static OmxDecoderModule* Create();
+
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const CreateDecoderParams& aParams) override;
 
   already_AddRefed<MediaDataDecoder>
   CreateAudioDecoder(const CreateDecoderParams& aParams) override;
 
   bool SupportsMimeType(const nsACString& aMimeType,
                         DecoderDoctorDiagnostics* aDiagnostics) const override;
new file mode 100644
--- /dev/null
+++ b/dom/media/platforms/omx/OmxFunctionList.h
@@ -0,0 +1,13 @@
+/* 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/. */
+
+OMX_FUNC(OMX_Init)
+OMX_FUNC(OMX_Deinit)
+OMX_FUNC(OMX_GetHandle)
+OMX_FUNC(OMX_FreeHandle)
+OMX_FUNC(OMX_ComponentNameEnum)
+OMX_FUNC(OMX_GetComponentsOfRole)
+OMX_FUNC(OMX_GetRolesOfComponent)
+OMX_FUNC(OMX_SetupTunnel)
+OMX_FUNC(OMX_GetContentPipe)
--- a/dom/media/platforms/omx/OmxPlatformLayer.cpp
+++ b/dom/media/platforms/omx/OmxPlatformLayer.cpp
@@ -3,16 +3,20 @@
 /* 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 "OmxPlatformLayer.h"
 
 #include "OMX_VideoExt.h" // For VP8.
 
+#ifdef MOZ_OMX
+#include "PureOmxPlatformLayer.h"
+#endif
+
 #include "VPXDecoder.h"
 
 #ifdef LOG
 #undef LOG
 #endif
 
 #define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("OmxPlatformLayer -- %s: " arg, __func__, ##__VA_ARGS__))
 
@@ -277,25 +281,46 @@ OmxPlatformLayer::CompressionFormat()
   } else if (VPXDecoder::IsVP8(mInfo->mMimeType)) {
     return static_cast<OMX_VIDEO_CODINGTYPE>(OMX_VIDEO_CodingVP8);
   } else {
     MOZ_ASSERT_UNREACHABLE("Unsupported compression format");
     return OMX_VIDEO_CodingUnused;
   }
 }
 
-// For platforms without OMX IL support.
+// Implementations for different platforms will be defined in their own files.
+#if defined(MOZ_OMX)
+
+bool
+OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType)
+{
+  return PureOmxPlatformLayer::SupportsMimeType(aMimeType);
+}
+
+OmxPlatformLayer*
+OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder,
+                         OmxPromiseLayer* aPromiseLayer,
+                         TaskQueue* aTaskQueue,
+                         layers::ImageContainer* aImageContainer)
+{
+  return new PureOmxPlatformLayer(aDataDecoder, aPromiseLayer,
+                                  aTaskQueue, aImageContainer);
+}
+
+#else // For platforms without OMX IL support.
+
 bool
 OmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType)
 {
   return false;
 }
 
 OmxPlatformLayer*
 OmxPlatformLayer::Create(OmxDataDecoder* aDataDecoder,
                         OmxPromiseLayer* aPromiseLayer,
                         TaskQueue* aTaskQueue,
                         layers::ImageContainer* aImageContainer)
 {
   return nullptr;
 }
 
+#endif
 }
new file mode 100644
--- /dev/null
+++ b/dom/media/platforms/omx/PureOmxPlatformLayer.cpp
@@ -0,0 +1,452 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "OmxDataDecoder.h"
+#include "OmxPromiseLayer.h"
+#include "PureOmxPlatformLayer.h"
+#include "OmxCoreLibLinker.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("PureOmxPlatformLayer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
+#define LOG_BUF(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("PureOmxBufferData(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
+
+namespace mozilla {
+
+#define OMX_FUNC(func) extern typeof(func)* func;
+#include "OmxFunctionList.h"
+#undef OMX_FUNC
+
+PureOmxBufferData::PureOmxBufferData(const PureOmxPlatformLayer& aPlatformLayer,
+                                     const OMX_PARAM_PORTDEFINITIONTYPE& aPortDef)
+  : BufferData(nullptr)
+  , mPlatformLayer(aPlatformLayer)
+  , mPortDef(aPortDef)
+{
+  LOG_BUF("");
+
+  if (ShouldUseEGLImage()) {
+    // TODO
+    LOG_BUF("OMX_UseEGLImage() seems available but using it isn't implemented yet.");
+  }
+
+  OMX_ERRORTYPE err;
+  err = OMX_AllocateBuffer(mPlatformLayer.GetComponent(),
+                           &mBuffer,
+                           mPortDef.nPortIndex,
+                           this,
+                           mPortDef.nBufferSize);
+  if (err != OMX_ErrorNone) {
+    LOG_BUF("Failed to allocate the buffer!: 0x%08x", err);
+  }
+}
+
+PureOmxBufferData::~PureOmxBufferData()
+{
+  LOG_BUF("");
+  ReleaseBuffer();
+}
+
+void PureOmxBufferData::ReleaseBuffer()
+{
+  LOG_BUF("");
+
+  if (mBuffer) {
+    OMX_ERRORTYPE err;
+    err = OMX_FreeBuffer(mPlatformLayer.GetComponent(),
+                         mPortDef.nPortIndex,
+                         mBuffer);
+    if (err != OMX_ErrorNone) {
+      LOG_BUF("Failed to free the buffer!: 0x%08x", err);
+    }
+    mBuffer = nullptr;
+  }
+}
+
+bool PureOmxBufferData::ShouldUseEGLImage()
+{
+  OMX_ERRORTYPE err;
+  err = OMX_UseEGLImage(mPlatformLayer.GetComponent(),
+                        nullptr,
+                        mPortDef.nPortIndex,
+                        nullptr,
+                        nullptr);
+  return (err != OMX_ErrorNotImplemented);
+}
+
+/* static */ bool
+PureOmxPlatformLayer::Init(void)
+{
+  if (!OmxCoreLibLinker::Link()) {
+    return false;
+  }
+
+  OMX_ERRORTYPE err = OMX_Init();
+  if (err != OMX_ErrorNone) {
+    MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
+            ("PureOmxPlatformLayer::%s: Failed to initialize OMXCore: 0x%08x",
+             __func__, err));
+    return false;
+  }
+
+  return true;
+}
+
+/* static */ OMX_CALLBACKTYPE PureOmxPlatformLayer::sCallbacks =
+  { EventHandler, EmptyBufferDone, FillBufferDone };
+
+PureOmxPlatformLayer::PureOmxPlatformLayer(OmxDataDecoder* aDataDecoder,
+                                           OmxPromiseLayer* aPromiseLayer,
+                                           TaskQueue* aTaskQueue,
+                                           layers::ImageContainer* aImageContainer)
+  : mComponent(nullptr)
+  , mDataDecoder(aDataDecoder)
+  , mPromiseLayer(aPromiseLayer)
+  , mTaskQueue(aTaskQueue)
+  , mImageContainer(aImageContainer)
+{
+  LOG("");
+}
+
+PureOmxPlatformLayer::~PureOmxPlatformLayer()
+{
+  LOG("");
+  if (mComponent) {
+    OMX_FreeHandle(mComponent);
+  }
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::InitOmxToStateLoaded(const TrackInfo* aInfo)
+{
+  LOG("");
+
+  if (!aInfo) {
+    return OMX_ErrorUndefined;
+  }
+  mInfo = aInfo;
+
+  return CreateComponent();
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::EmptyThisBuffer(BufferData* aData)
+{
+  LOG("");
+  return OMX_EmptyThisBuffer(mComponent, aData->mBuffer);
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::FillThisBuffer(BufferData* aData)
+{
+  LOG("");
+  return OMX_FillThisBuffer(mComponent, aData->mBuffer);
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::SendCommand(OMX_COMMANDTYPE aCmd,
+                                  OMX_U32 aParam1,
+                                  OMX_PTR aCmdData)
+{
+  LOG("aCmd: 0x%08x", aCmd);
+  if (!mComponent) {
+    return OMX_ErrorUndefined;
+  }
+  return OMX_SendCommand(mComponent, aCmd, aParam1, aCmdData);
+}
+
+nsresult
+PureOmxPlatformLayer::FindPortDefinition(OMX_DIRTYPE aType,
+                                         OMX_PARAM_PORTDEFINITIONTYPE& portDef)
+{
+  nsTArray<uint32_t> portIndex;
+  GetPortIndices(portIndex);
+  for (auto idx : portIndex) {
+    InitOmxParameter(&portDef);
+    portDef.nPortIndex = idx;
+
+    OMX_ERRORTYPE err;
+    err = GetParameter(OMX_IndexParamPortDefinition,
+                       &portDef,
+                       sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+    if (err != OMX_ErrorNone) {
+      return NS_ERROR_FAILURE;
+    } else if (portDef.eDir == aType) {
+      LOG("Found OMX_IndexParamPortDefinition: port: %d, type: %d",
+          portDef.nPortIndex, portDef.eDir);
+      return NS_OK;
+    }
+  }
+  return NS_ERROR_FAILURE;
+}
+
+nsresult
+PureOmxPlatformLayer::AllocateOmxBuffer(OMX_DIRTYPE aType,
+                                        BUFFERLIST* aBufferList)
+{
+  LOG("aType: %d", aType);
+
+  OMX_PARAM_PORTDEFINITIONTYPE portDef;
+  nsresult result = FindPortDefinition(aType, portDef);
+  if (result != NS_OK) {
+    return result;
+  }
+
+  LOG("nBufferCountActual: %d, nBufferSize: %d",
+      portDef.nBufferCountActual, portDef.nBufferSize);
+
+  for (OMX_U32 i = 0; i < portDef.nBufferCountActual; ++i) {
+    RefPtr<PureOmxBufferData> buffer = new PureOmxBufferData(*this, portDef);
+    aBufferList->AppendElement(buffer);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+PureOmxPlatformLayer::ReleaseOmxBuffer(OMX_DIRTYPE aType,
+                                       BUFFERLIST* aBufferList)
+{
+  LOG("aType: 0x%08x", aType);
+
+  uint32_t len = aBufferList->Length();
+  for (uint32_t i = 0; i < len; i++) {
+    PureOmxBufferData* buffer =
+      static_cast<PureOmxBufferData*>(aBufferList->ElementAt(i).get());
+
+    // All raw OpenMAX buffers have to be released here to flush
+    // OMX_CommandStateSet for switching the state to OMX_StateLoaded.
+    // See OmxDataDecoder::DoAsyncShutdown() for more detail.
+    buffer->ReleaseBuffer();
+  }
+  aBufferList->Clear();
+
+  return NS_OK;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::GetState(OMX_STATETYPE* aType)
+{
+  LOG("");
+
+  if (mComponent) {
+    return OMX_GetState(mComponent, aType);
+  }
+
+  return OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::GetParameter(OMX_INDEXTYPE aParamIndex,
+                                   OMX_PTR aComponentParameterStructure,
+                                   OMX_U32 aComponentParameterSize)
+{
+  LOG("aParamIndex: 0x%08x", aParamIndex);
+
+  if (!mComponent) {
+    return OMX_ErrorUndefined;
+  }
+
+  return OMX_GetParameter(mComponent,
+                          aParamIndex,
+                          aComponentParameterStructure);
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::SetParameter(OMX_INDEXTYPE aParamIndex,
+                                   OMX_PTR aComponentParameterStructure,
+                                   OMX_U32 aComponentParameterSize)
+{
+  LOG("aParamIndex: 0x%08x", aParamIndex);
+
+  if (!mComponent) {
+    return OMX_ErrorUndefined;
+  }
+
+  return OMX_SetParameter(mComponent,
+                          aParamIndex,
+                          aComponentParameterStructure);
+}
+
+nsresult
+PureOmxPlatformLayer::Shutdown()
+{
+  LOG("");
+  return NS_OK;
+}
+
+/* static */ OMX_ERRORTYPE
+PureOmxPlatformLayer::EventHandler(OMX_HANDLETYPE hComponent,
+                                   OMX_PTR pAppData,
+                                   OMX_EVENTTYPE eEventType,
+                                   OMX_U32 nData1,
+                                   OMX_U32 nData2,
+                                   OMX_PTR pEventData)
+{
+  PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
+  nsCOMPtr<nsIRunnable> r =
+    NS_NewRunnableFunction(
+        "mozilla::PureOmxPlatformLayer::EventHandler",
+        [self, eEventType, nData1, nData2, pEventData] () {
+          self->EventHandler(eEventType, nData1, nData2, pEventData);
+        });
+  nsresult rv = self->mTaskQueue->Dispatch(r.forget());
+  return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
+}
+
+/* static */ OMX_ERRORTYPE
+PureOmxPlatformLayer::EmptyBufferDone(OMX_HANDLETYPE hComponent,
+                                      OMX_IN OMX_PTR pAppData,
+                                      OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+  PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+      "mozilla::PureOmxPlatformLayer::EmptyBufferDone",
+      [self, pBuffer] () {
+        self->EmptyBufferDone(pBuffer);
+      });
+  nsresult rv = self->mTaskQueue->Dispatch(r.forget());
+  return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
+}
+
+/* static */ OMX_ERRORTYPE
+PureOmxPlatformLayer::FillBufferDone(OMX_OUT OMX_HANDLETYPE hComponent,
+                                     OMX_OUT OMX_PTR pAppData,
+                                     OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
+{
+  PureOmxPlatformLayer* self = static_cast<PureOmxPlatformLayer*>(pAppData);
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
+      "mozilla::PureOmxPlatformLayer::FillBufferDone",
+      [self, pBuffer] () {
+        self->FillBufferDone(pBuffer);
+      });
+  nsresult rv = self->mTaskQueue->Dispatch(r.forget());
+  return NS_SUCCEEDED(rv) ? OMX_ErrorNone : OMX_ErrorUndefined;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::EventHandler(OMX_EVENTTYPE eEventType,
+                                   OMX_U32 nData1,
+                                   OMX_U32 nData2,
+                                   OMX_PTR pEventData)
+{
+  bool handled = mPromiseLayer->Event(eEventType, nData1, nData2);
+  LOG("eEventType: 0x%08x, handled: %d", eEventType, handled);
+  return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::EmptyBufferDone(OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+  PureOmxBufferData* buffer = static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
+  OMX_DIRTYPE portDirection = buffer->GetPortDirection();
+  LOG("PortDirection: %d", portDirection);
+  mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
+  return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::FillBufferDone(OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
+{
+  PureOmxBufferData* buffer = static_cast<PureOmxBufferData*>(pBuffer->pAppPrivate);
+  OMX_DIRTYPE portDirection = buffer->GetPortDirection();
+  LOG("PortDirection: %d", portDirection);
+  mPromiseLayer->EmptyFillBufferDone(portDirection, buffer);
+  return OMX_ErrorNone;
+}
+
+bool
+PureOmxPlatformLayer::SupportsMimeType(const nsACString& aMimeType)
+{
+  return FindStandardComponent(aMimeType, nullptr);
+}
+
+static bool
+GetStandardComponentRole(const nsACString& aMimeType,
+                         nsACString& aRole)
+{
+  if (aMimeType.EqualsLiteral("video/avc") ||
+      aMimeType.EqualsLiteral("video/mp4") ||
+      aMimeType.EqualsLiteral("video/mp4v-es")) {
+    aRole.Assign("video_decoder.avc");
+    return true;
+  } else if (aMimeType.EqualsLiteral("audio/mp4a-latm") ||
+             aMimeType.EqualsLiteral("audio/mp4") ||
+             aMimeType.EqualsLiteral("audio/aac")) {
+    aRole.Assign("audio_decoder.aac");
+    return true;
+  }
+  return false;
+}
+
+/* static */ bool
+PureOmxPlatformLayer::FindStandardComponent(const nsACString& aMimeType,
+                                            nsACString* aComponentName)
+{
+  nsAutoCString role;
+  if (!GetStandardComponentRole(aMimeType, role))
+    return false;
+
+  OMX_U32 nComponents = 0;
+  OMX_ERRORTYPE err;
+  err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
+                                &nComponents, nullptr);
+  if (err != OMX_ErrorNone || nComponents <= 0) {
+    return false;
+  }
+  if (!aComponentName) {
+    return true;
+  }
+
+  // TODO:
+  // Only the first component will be used.
+  // We should detect the most preferred component.
+  OMX_U8* componentNames[1];
+  UniquePtr<OMX_U8[]> componentName;
+  componentName = MakeUniqueFallible<OMX_U8[]>(OMX_MAX_STRINGNAME_SIZE);
+  componentNames[0] = componentName.get();
+  nComponents = 1;
+  err = OMX_GetComponentsOfRole(const_cast<OMX_STRING>(role.Data()),
+                                &nComponents, componentNames);
+  if (err == OMX_ErrorNone) {
+    MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug,
+            ("PureOmxPlatformLayer::%s: A component has been found for %s: %s",
+             __func__, aMimeType.Data(), componentNames[0]));
+    aComponentName->Assign(reinterpret_cast<char*>(componentNames[0]));
+  }
+
+  return err == OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE
+PureOmxPlatformLayer::CreateComponent(const nsACString* aComponentName)
+{
+  nsAutoCString componentName;
+  if (aComponentName) {
+    componentName = *aComponentName;
+  } else if (!FindStandardComponent(mInfo->mMimeType, &componentName)) {
+    return OMX_ErrorComponentNotFound;
+  }
+
+  OMX_ERRORTYPE err;
+  err = OMX_GetHandle(&mComponent,
+                      const_cast<OMX_STRING>(componentName.Data()),
+                      this,
+                      &sCallbacks);
+
+  const char* mime = mInfo->mMimeType.Data();
+  if (err == OMX_ErrorNone) {
+    LOG("Succeeded to create the component for %s", mime);
+  } else {
+    LOG("Failed to create the component for %s: 0x%08x", mime, err);
+  }
+
+  return err;
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/dom/media/platforms/omx/PureOmxPlatformLayer.h
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#if !defined(PureOmxPlatformLayer_h_)
+#define PureOmxPlatformLayer_h_
+
+#include "OmxPlatformLayer.h"
+
+namespace mozilla {
+
+class PureOmxPlatformLayer;
+
+class PureOmxBufferData : public OmxPromiseLayer::BufferData
+{
+protected:
+  virtual ~PureOmxBufferData();
+
+public:
+  PureOmxBufferData(const PureOmxPlatformLayer& aPlatformLayer,
+                    const OMX_PARAM_PORTDEFINITIONTYPE& aPortDef);
+
+  void ReleaseBuffer();
+  OMX_DIRTYPE GetPortDirection() const { return mPortDef.eDir; };
+
+protected:
+  bool ShouldUseEGLImage();
+
+  const PureOmxPlatformLayer& mPlatformLayer;
+  const OMX_PARAM_PORTDEFINITIONTYPE mPortDef;
+};
+
+class PureOmxPlatformLayer : public OmxPlatformLayer
+{
+public:
+  static bool Init(void);
+
+  static bool SupportsMimeType(const nsACString& aMimeType);
+
+  PureOmxPlatformLayer(OmxDataDecoder* aDataDecoder,
+                       OmxPromiseLayer* aPromiseLayer,
+                       TaskQueue* aTaskQueue,
+                       layers::ImageContainer* aImageContainer);
+
+  virtual ~PureOmxPlatformLayer();
+
+  OMX_ERRORTYPE InitOmxToStateLoaded(const TrackInfo* aInfo) override;
+
+  OMX_ERRORTYPE EmptyThisBuffer(BufferData* aData) override;
+
+  OMX_ERRORTYPE FillThisBuffer(BufferData* aData) override;
+
+  OMX_ERRORTYPE SendCommand(OMX_COMMANDTYPE aCmd,
+                            OMX_U32 aParam1,
+                            OMX_PTR aCmdData) override;
+
+  nsresult AllocateOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) override;
+
+  nsresult ReleaseOmxBuffer(OMX_DIRTYPE aType, BUFFERLIST* aBufferList) override;
+
+  OMX_ERRORTYPE GetState(OMX_STATETYPE* aType) override;
+
+  OMX_ERRORTYPE GetParameter(OMX_INDEXTYPE aParamIndex,
+                             OMX_PTR aComponentParameterStructure,
+                             OMX_U32 aComponentParameterSize) override;
+
+  OMX_ERRORTYPE SetParameter(OMX_INDEXTYPE aParamIndex,
+                             OMX_PTR aComponentParameterStructure,
+                             OMX_U32 aComponentParameterSize) override;
+
+  nsresult Shutdown() override;
+
+  OMX_HANDLETYPE GetComponent() const { return mComponent; };
+
+  static OMX_ERRORTYPE EventHandler(OMX_HANDLETYPE hComponent,
+                                    OMX_PTR pAppData,
+                                    OMX_EVENTTYPE eEventType,
+                                    OMX_U32 nData1,
+                                    OMX_U32 nData2,
+                                    OMX_PTR pEventData);
+  static OMX_ERRORTYPE EmptyBufferDone(OMX_HANDLETYPE hComponent,
+                                       OMX_IN OMX_PTR pAppData,
+                                       OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+  static OMX_ERRORTYPE FillBufferDone(OMX_OUT OMX_HANDLETYPE hComponent,
+                                      OMX_OUT OMX_PTR pAppData,
+                                      OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+
+protected:
+  static bool FindStandardComponent(const nsACString& aMimeType,
+                                    nsACString* aComponentName);
+
+  OMX_ERRORTYPE CreateComponent(const nsACString* aComponentName = nullptr);
+  nsresult FindPortDefinition(OMX_DIRTYPE aType,
+                              OMX_PARAM_PORTDEFINITIONTYPE& portDef);
+
+  OMX_ERRORTYPE EventHandler(OMX_EVENTTYPE eEventType,
+                             OMX_U32 nData1,
+                             OMX_U32 nData2,
+                             OMX_PTR pEventData);
+  OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+  OMX_ERRORTYPE FillBufferDone(OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+
+protected:
+  static OMX_CALLBACKTYPE sCallbacks;
+
+  OMX_HANDLETYPE mComponent;
+  RefPtr<OmxDataDecoder> mDataDecoder;
+  RefPtr<OmxPromiseLayer> mPromiseLayer;
+  RefPtr<TaskQueue> mTaskQueue;
+  RefPtr<layers::ImageContainer> mImageContainer;
+};
+
+}
+
+#endif // PureOmxPlatformLayer_h_
--- a/dom/media/platforms/omx/moz.build
+++ b/dom/media/platforms/omx/moz.build
@@ -16,16 +16,21 @@ UNIFIED_SOURCES += [
 ]
 
 LOCAL_INCLUDES += [
     '/media/openmax_il/il112',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
+if CONFIG['MOZ_OMX']:
+    UNIFIED_SOURCES += [
+        'PureOmxPlatformLayer.cpp',
+    ]
+
 FINAL_LIBRARY = 'xul'
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
 
 if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
     # Avoid warnings from third-party code that we can not modify.
     if CONFIG['CC_TYPE'] == 'clang-cl':
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -513,16 +513,24 @@ PREF("media.navigator.hardware.vp8_decod
 // decoding.
 VARCACHE_PREF(
   "media.navigator.mediadatadecoder_enabled",
    MediaNavigatorMediadatadecoderEnabled,
   bool, false
 )
 #endif // MOZ_WEBRTC
 
+#ifdef MOZ_OMX
+VARCACHE_PREF(
+  "media.omx.enabled",
+   MediaOmxEnabled,
+  bool, false
+)
+#endif
+
 #ifdef MOZ_FFMPEG
 
 # if defined(XP_MACOSX)
 #  define PREF_VALUE false
 # else
 #  define PREF_VALUE true
 # endif
 VARCACHE_PREF(
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -414,16 +414,30 @@ def fmp4(value, target, wmf, applemedia)
         enabled = wmf or applemedia or target.os == 'Android'
     if enabled:
         return True
 
 set_config('MOZ_FMP4', fmp4)
 set_define('MOZ_FMP4', fmp4)
 add_old_configure_assignment('MOZ_FMP4', fmp4)
 
+# OpenMAX IL Decoding Support
+# ==============================================================
+option('--enable-openmax',
+       help='Enable OpenMAX IL for video/audio decoding')
+
+@depends('--enable-openmax')
+def openmax(value):
+    enabled = bool(value)
+    if enabled:
+        return True
+
+set_config('MOZ_OMX', openmax)
+set_define('MOZ_OMX', openmax)
+
 # EME Support
 # ==============================================================
 # Widevine is enabled by default in desktop browser builds.
 @depends(build_project, '--help')
 def eme_default(build_project, help):
     if build_project == 'browser':
         return 'widevine'