Bug 1178069 - Check devices capability before enable use of vp8 hardware acceleration using android.media.MediaCodecList and android.media.MediaCodecInfo r=jrmuizel
authorQiang Lu <qiang.lu@intel.com>
Fri, 24 Jul 2015 12:45:55 -0700
changeset 254451 cf1dbe9a71cf2350f029d1a41c7ed7a02200370b
parent 254450 3fd7798e4bf1a75190075e857e2d0a085714fd58
child 254560 eaf549a7c5f49829fb75f35f39ad10f817c36026
push id14226
push userkwierso@gmail.com
push dateFri, 24 Jul 2015 19:50:44 +0000
treeherderfx-team@cf1dbe9a71cf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1178069
milestone42.0a1
Bug 1178069 - Check devices capability before enable use of vp8 hardware acceleration using android.media.MediaCodecList and android.media.MediaCodecInfo r=jrmuizel
media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
mobile/android/base/GeckoAppShell.java
mobile/android/base/moz.build
mobile/android/base/util/HardwareCodecCapabilityUtils.java
toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml
toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
widget/GfxInfoBase.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/GfxInfo.cpp
widget/nsIGfxInfo.idl
--- a/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
+++ b/media/webrtc/signaling/src/peerconnection/MediaPipelineFactory.cpp
@@ -881,17 +881,17 @@ MediaPipelineFactory::EnsureExternalCode
        bool enabled = mozilla::Preferences::GetBool("media.navigator.hardware.vp8_encode.acceleration_enabled", false);
 #else
        bool enabled = false;
 #endif
        if (enabled) {
          nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
          if (gfxInfo) {
            int32_t status;
-           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION, &status))) {
+           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, &status))) {
              if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
                NS_WARNING("VP8 encoder hardware is not whitelisted: disabling.\n");
              } else {
                VideoEncoder* encoder = nullptr;
                encoder = MediaCodecVideoCodec::CreateEncoder(MediaCodecVideoCodec::CodecType::CODEC_VP8);
                if (encoder) {
                  return aConduit.SetExternalSendCodec(aConfig, encoder);
                } else {
@@ -906,21 +906,20 @@ MediaPipelineFactory::EnsureExternalCode
        bool enabled = mozilla::Preferences::GetBool("media.navigator.hardware.vp8_decode.acceleration_enabled", false);
 #else
        bool enabled = false;
 #endif
        if (enabled) {
          nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
          if (gfxInfo) {
            int32_t status;
-           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION, &status))) {
+           if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE, &status))) {
              if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
                NS_WARNING("VP8 decoder hardware is not whitelisted: disabling.\n");
              } else {
-
                VideoDecoder* decoder;
                decoder = MediaCodecVideoCodec::CreateDecoder(MediaCodecVideoCodec::CodecType::CODEC_VP8);
                if (decoder) {
                  return aConduit.SetExternalRecvCodec(aConfig, decoder);
                } else {
                  return kMediaConduitNoError;
                }
              }
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -42,16 +42,17 @@ import org.mozilla.gecko.mozglue.GeckoLo
 import org.mozilla.gecko.mozglue.JNITarget;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter;
 import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
 import org.mozilla.gecko.overlays.ui.ShareDialog;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoRequest;
+import org.mozilla.gecko.util.HardwareCodecCapabilityUtils;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSContainer;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ProxySelector;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.annotation.TargetApi;
@@ -87,16 +88,17 @@ import android.hardware.SensorEventListe
 import android.hardware.SensorManager;
 import android.location.Criteria;
 import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
 import android.os.SystemClock;
 import android.os.Vibrator;
@@ -956,16 +958,26 @@ public class GeckoAppShell
         Uri uri = aURL.indexOf(':') >= 0 ? Uri.parse(aURL) : new Uri.Builder().scheme(aURL).build();
 
         Intent intent = getOpenURIIntent(getContext(), uri.toString(), "",
             TextUtils.isEmpty(aAction) ? Intent.ACTION_VIEW : aAction, "");
 
         return getHandlersForIntent(intent);
     }
 
+    @WrapElementForJNI(stubName = "GetHWEncoderCapability")
+    static boolean getHWEncoderCapability() {
+      return HardwareCodecCapabilityUtils.getHWEncoderCapability();
+    }
+
+    @WrapElementForJNI(stubName = "GetHWDecoderCapability")
+    static boolean getHWDecoderCapability() {
+      return HardwareCodecCapabilityUtils.getHWDecoderCapability();
+    }
+
     static List<ResolveInfo> queryIntentActivities(Intent intent) {
         final PackageManager pm = getContext().getPackageManager();
 
         // Exclude any non-exported activities: we can't open them even if we want to!
         // Bug 1031569 has some details.
         final ArrayList<ResolveInfo> list = new ArrayList<>();
         for (ResolveInfo ri: pm.queryIntentActivities(intent, 0)) {
             if (ri.activityInfo.exported) {
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -78,16 +78,17 @@ gujar.sources += [
     'util/EventCallback.java',
     'util/FileUtils.java',
     'util/FloatUtils.java',
     'util/GamepadUtils.java',
     'util/GeckoBackgroundThread.java',
     'util/GeckoEventListener.java',
     'util/GeckoJarReader.java',
     'util/GeckoRequest.java',
+    'util/HardwareCodecCapabilityUtils.java',
     'util/HardwareUtils.java',
     'util/INIParser.java',
     'util/INISection.java',
     'util/InputOptionsUtils.java',
     'util/IOUtils.java',
     'util/JSONUtils.java',
     'util/MenuUtils.java',
     'util/NativeEventListener.java',
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/util/HardwareCodecCapabilityUtils.java
@@ -0,0 +1,143 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ *  * 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/. */
+
+
+package org.mozilla.gecko.util;
+
+import org.mozilla.gecko.AppConstants.Versions;
+
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecList;
+import android.util.Log;
+
+public final class HardwareCodecCapabilityUtils {
+  private static final String LOGTAG = "GeckoHardwareCodecCapabilityUtils";
+
+  // List of supported HW VP8 encoders.
+  private static final String[] supportedVp8HwEncCodecPrefixes =
+  {"OMX.qcom.", "OMX.Intel." };
+  // List of supported HW VP8 decoders.
+  private static final String[] supportedVp8HwDecCodecPrefixes =
+  {"OMX.qcom.", "OMX.Nvidia.", "OMX.Exynos.", "OMX.Intel." };
+  private static final String VP8_MIME_TYPE = "video/x-vnd.on2.vp8";
+  // NV12 color format supported by QCOM codec, but not declared in MediaCodec -
+  // see /hardware/qcom/media/mm-core/inc/OMX_QCOMExtns.h
+  private static final int
+    COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04;
+  // Allowable color formats supported by codec - in order of preference.
+  private static final int[] supportedColorList = {
+    CodecCapabilities.COLOR_FormatYUV420Planar,
+    CodecCapabilities.COLOR_FormatYUV420SemiPlanar,
+    CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar,
+    COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m
+  };
+
+
+  public static boolean getHWEncoderCapability() {
+    if (Versions.feature20Plus) {
+      for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) {
+        MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+        if (!info.isEncoder()) {
+          continue;
+        }
+        String name = null;
+        for (String mimeType : info.getSupportedTypes()) {
+          if (mimeType.equals(VP8_MIME_TYPE)) {
+            name = info.getName();
+            break;
+          }
+        }
+        if (name == null) {
+          continue;  // No HW support in this codec; try the next one.
+        }
+        Log.e(LOGTAG, "Found candidate encoder " + name);
+
+        // Check if this is supported encoder.
+        boolean supportedCodec = false;
+        for (String codecPrefix : supportedVp8HwEncCodecPrefixes) {
+          if (name.startsWith(codecPrefix)) {
+            supportedCodec = true;
+            break;
+          }
+        }
+        if (!supportedCodec) {
+          continue;
+        }
+
+        // Check if codec supports either yuv420 or nv12.
+        CodecCapabilities capabilities =
+          info.getCapabilitiesForType(VP8_MIME_TYPE);
+        for (int colorFormat : capabilities.colorFormats) {
+          Log.v(LOGTAG, "   Color: 0x" + Integer.toHexString(colorFormat));
+        }
+        for (int supportedColorFormat : supportedColorList) {
+          for (int codecColorFormat : capabilities.colorFormats) {
+            if (codecColorFormat == supportedColorFormat) {
+              // Found supported HW Encoder.
+              Log.e(LOGTAG, "Found target encoder " + name +
+                  ". Color: 0x" + Integer.toHexString(codecColorFormat));
+              return true;
+            }
+          }
+        }
+      }
+    }
+    // No HW encoder.
+    return false;
+  }
+
+  public static boolean getHWDecoderCapability() {
+    if (Versions.feature20Plus) { 
+      for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) {
+        MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+        if (info.isEncoder()) {
+          continue;
+        }
+        String name = null;
+        for (String mimeType : info.getSupportedTypes()) {
+          if (mimeType.equals(VP8_MIME_TYPE)) {
+            name = info.getName();
+            break;
+          }
+        }
+        if (name == null) {
+          continue;  // No HW support in this codec; try the next one.
+        }
+        Log.e(LOGTAG, "Found candidate decoder " + name);
+
+        // Check if this is supported decoder.
+        boolean supportedCodec = false;
+        for (String codecPrefix : supportedVp8HwDecCodecPrefixes) {
+          if (name.startsWith(codecPrefix)) {
+            supportedCodec = true;
+            break;
+          }
+        }
+        if (!supportedCodec) {
+          continue;
+        }
+
+        // Check if codec supports either yuv420 or nv12.
+        CodecCapabilities capabilities =
+          info.getCapabilitiesForType(VP8_MIME_TYPE);
+        for (int colorFormat : capabilities.colorFormats) {
+          Log.v(LOGTAG, "   Color: 0x" + Integer.toHexString(colorFormat));
+        }
+        for (int supportedColorFormat : supportedColorList) {
+          for (int codecColorFormat : capabilities.colorFormats) {
+            if (codecColorFormat == supportedColorFormat) {
+              // Found supported HW decoder.
+              Log.e(LOGTAG, "Found target decoder " + name +
+                  ". Color: 0x" + Integer.toHexString(codecColorFormat));
+              return true;
+            }
+          }
+        }
+      }
+    }
+    return false;  // No HW decoder.
+  }
+}
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_gfxBlacklist_AllOS.xml
@@ -130,16 +130,42 @@
       </devices>
       <feature> WEBRTC_HW_ACCELERATION </feature>
       <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
     </gfxBlacklistEntry>
 
     <gfxBlacklistEntry>
       <os>All</os>
       <vendor>0xabcd</vendor>
+      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
+      <devices>
+        <device>0x2783</device>
+        <device>0x1234</device>
+        <device>0x2782</device>
+      </devices>
+      <feature> WEBRTC_HW_ACCELERATION_ENCODE </feature>
+      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
+    </gfxBlacklistEntry>
+
+    <gfxBlacklistEntry>
+      <os>All</os>
+      <vendor>0xabcd</vendor>
+      <versionRange minVersion="42.0" maxVersion="13.0b2"/>
+      <devices>
+        <device>0x2783</device>
+        <device>0x1234</device>
+        <device>0x2782</device>
+      </devices>
+      <feature> WEBRTC_HW_ACCELERATION_DECODE </feature>
+      <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
+    </gfxBlacklistEntry>
+
+    <gfxBlacklistEntry>
+      <os>All</os>
+      <vendor>0xabcd</vendor>
       <versionRange minVersion="17.2a2" maxVersion="15.0"/>
       <devices>
         <device>0x2783</device>
         <device>0x1234</device>
         <device>0x2782</device>
       </devices>
       <feature> DIRECT3D_11_LAYERS </feature>
       <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
--- a/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_gfxBlacklist_Version.js
@@ -102,16 +102,22 @@ function run_test() {
     do_check_eq(status, Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION);
 
     status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_STAGEFRIGHT);
     do_check_eq(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
 
     status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBRTC_HW_ACCELERATION);
     do_check_eq(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
 
+    status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBRTC_HW_ACCELERATION_ENCODE);
+    do_check_eq(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
+
+    status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBRTC_HW_ACCELERATION_DECODE);
+    do_check_eq(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
+
     status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_DIRECT3D_11_LAYERS);
     do_check_eq(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
 
     status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_HARDWARE_VIDEO_DECODING);
     do_check_eq(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
 
     status = gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_DIRECT3D_11_ANGLE);
     do_check_eq(status, Ci.nsIGfxInfo.FEATURE_STATUS_OK);
--- a/widget/GfxInfoBase.cpp
+++ b/widget/GfxInfoBase.cpp
@@ -146,16 +146,22 @@ GetPrefNameForFeature(int32_t aFeature)
       name = BLACKLIST_PREF_BRANCH "webgl.msaa";
       break;
     case nsIGfxInfo::FEATURE_STAGEFRIGHT:
       name = BLACKLIST_PREF_BRANCH "stagefright";
       break;
     case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION:
       name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration";
       break;
+    case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE:
+      name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration.encode";
+      break;
+    case nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE:
+      name = BLACKLIST_PREF_BRANCH "webrtc.hw.acceleration.decode";
+      break;
     default:
       break;
   };
 
   return name;
 }
 
 // Returns the value of the pref for the relevant feature in aValue.
@@ -335,16 +341,20 @@ BlacklistFeatureToGfxFeature(const nsASt
   else if (aFeature.EqualsLiteral("WEBGL_OPENGL"))
     return nsIGfxInfo::FEATURE_WEBGL_OPENGL;
   else if (aFeature.EqualsLiteral("WEBGL_ANGLE"))
     return nsIGfxInfo::FEATURE_WEBGL_ANGLE;
   else if (aFeature.EqualsLiteral("WEBGL_MSAA"))
     return nsIGfxInfo::FEATURE_WEBGL_MSAA;
   else if (aFeature.EqualsLiteral("STAGEFRIGHT"))
     return nsIGfxInfo::FEATURE_STAGEFRIGHT;
+  else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION_ENCODE"))
+    return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE;
+  else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION_DECODE"))
+    return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE;
   else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION"))
     return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION;
 
   // If we don't recognize the feature, it may be new, and something
   // this version doesn't understand.  So, nothing to do.  This is
   // different from feature not being specified at all, in which case
   // this method should not get called and we should continue with the
   // "all features" blocklisting.
@@ -967,16 +977,18 @@ GfxInfoBase::EvaluateDownloadedBlacklist
     nsIGfxInfo::FEATURE_DIRECT3D_10_LAYERS,
     nsIGfxInfo::FEATURE_DIRECT3D_10_1_LAYERS,
     nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
     nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE,
     nsIGfxInfo::FEATURE_HARDWARE_VIDEO_DECODING,
     nsIGfxInfo::FEATURE_OPENGL_LAYERS,
     nsIGfxInfo::FEATURE_WEBGL_OPENGL,
     nsIGfxInfo::FEATURE_WEBGL_ANGLE,
+    nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE,
+    nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE,
     nsIGfxInfo::FEATURE_WEBGL_MSAA,
     nsIGfxInfo::FEATURE_STAGEFRIGHT,
     nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION,
     0
   };
 
   // For every feature we know about, we evaluate whether this blacklist has a
   // non-STATUS_OK status. If it does, we set the pref we evaluate in
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -467,16 +467,37 @@ AndroidBridge::GetHandlersForMimeType(co
 
     getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
                                aDefaultApp, aAction,
                                NS_ConvertUTF16toUTF8(aMimeType));
     return true;
 }
 
 bool
+AndroidBridge::GetHWEncoderCapability()
+{
+  ALOG_BRIDGE("AndroidBridge::GetHWEncoderCapability");
+
+  bool value = GeckoAppShell::GetHWEncoderCapability();
+
+  return value;
+}
+
+
+bool
+AndroidBridge::GetHWDecoderCapability()
+{
+  ALOG_BRIDGE("AndroidBridge::GetHWDecoderCapability");
+
+  bool value = GeckoAppShell::GetHWDecoderCapability();
+
+  return value;
+}
+
+bool
 AndroidBridge::GetHandlersForURL(const nsAString& aURL,
                                  nsIMutableArray* aHandlersArray,
                                  nsIHandlerApp **aDefaultApp,
                                  const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
 
     auto arr = GeckoAppShell::GetHandlersForURLWrapper(aURL, aAction);
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -202,16 +202,19 @@ public:
                            nsIHandlerApp **aDefaultApp = nullptr,
                            const nsAString& aAction = EmptyString());
 
     bool GetHandlersForMimeType(const nsAString& aMimeType,
                                 nsIMutableArray* handlersArray = nullptr,
                                 nsIHandlerApp **aDefaultApp = nullptr,
                                 const nsAString& aAction = EmptyString());
 
+    bool GetHWEncoderCapability();
+    bool GetHWDecoderCapability();
+
     void GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType);
     void GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt);
 
     bool GetClipboardText(nsAString& aText);
 
     void ShowAlertNotification(const nsAString& aImageUrl,
                                const nsAString& aAlertTitle,
                                const nsAString& aAlertText,
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -273,16 +273,32 @@ mozilla::jni::String::LocalRef GeckoAppS
 constexpr char GeckoAppShell::GetExternalPublicDirectory_t::name[];
 constexpr char GeckoAppShell::GetExternalPublicDirectory_t::signature[];
 
 mozilla::jni::String::LocalRef GeckoAppShell::GetExternalPublicDirectory(mozilla::jni::String::Param a0)
 {
     return mozilla::jni::Method<GetExternalPublicDirectory_t>::Call(nullptr, nullptr, a0);
 }
 
+constexpr char GeckoAppShell::GetHWDecoderCapability_t::name[];
+constexpr char GeckoAppShell::GetHWDecoderCapability_t::signature[];
+
+bool GeckoAppShell::GetHWDecoderCapability()
+{
+    return mozilla::jni::Method<GetHWDecoderCapability_t>::Call(nullptr, nullptr);
+}
+
+constexpr char GeckoAppShell::GetHWEncoderCapability_t::name[];
+constexpr char GeckoAppShell::GetHWEncoderCapability_t::signature[];
+
+bool GeckoAppShell::GetHWEncoderCapability()
+{
+    return mozilla::jni::Method<GetHWEncoderCapability_t>::Call(nullptr, nullptr);
+}
+
 constexpr char GeckoAppShell::GetHandlersForMimeTypeWrapper_t::name[];
 constexpr char GeckoAppShell::GetHandlersForMimeTypeWrapper_t::signature[];
 
 mozilla::jni::ObjectArray::LocalRef GeckoAppShell::GetHandlersForMimeTypeWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
 {
     return mozilla::jni::Method<GetHandlersForMimeTypeWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -640,16 +640,50 @@ public:
         static const bool isMultithreaded = false;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
     static mozilla::jni::String::LocalRef GetExternalPublicDirectory(mozilla::jni::String::Param);
 
 public:
+    struct GetHWDecoderCapability_t {
+        typedef GeckoAppShell Owner;
+        typedef bool ReturnType;
+        typedef bool SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "getHWDecoderCapability";
+        static constexpr char signature[] =
+                "()Z";
+        static const bool isStatic = true;
+        static const bool isMultithreaded = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+    };
+
+    static bool GetHWDecoderCapability();
+
+public:
+    struct GetHWEncoderCapability_t {
+        typedef GeckoAppShell Owner;
+        typedef bool ReturnType;
+        typedef bool SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "getHWEncoderCapability";
+        static constexpr char signature[] =
+                "()Z";
+        static const bool isStatic = true;
+        static const bool isMultithreaded = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+    };
+
+    static bool GetHWEncoderCapability();
+
+public:
     struct GetHandlersForMimeTypeWrapper_t {
         typedef GeckoAppShell Owner;
         typedef mozilla::jni::ObjectArray::LocalRef ReturnType;
         typedef mozilla::jni::ObjectArray::Param SetterType;
         typedef mozilla::jni::Args<
                 mozilla::jni::String::Param,
                 mozilla::jni::String::Param> Args;
         static constexpr char name[] = "getHandlersForMimeType";
--- a/widget/android/GfxInfo.cpp
+++ b/widget/android/GfxInfo.cpp
@@ -582,30 +582,25 @@ GfxInfo::GetFeatureStatusImpl(int32_t aF
         // Blocklist all Sony devices
         if (cManufacturer.Find("Sony", true) != -1) {
           *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
           return NS_OK;
         }
       }
     }
 
-    if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION) {
-      NS_LossyConvertUTF16toASCII cManufacturer(mManufacturer);
-      NS_LossyConvertUTF16toASCII cModel(mModel);
-      NS_LossyConvertUTF16toASCII cHardware(mHardware);
-
-      if (cHardware.EqualsLiteral("hammerhead") &&
-          CompareVersions(mOSVersion.get(), "4.4.2") >= 0 &&
-          cManufacturer.Equals("lge", nsCaseInsensitiveCStringComparator()) &&
-          cModel.Equals("nexus 5", nsCaseInsensitiveCStringComparator())) {
-        *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
+    if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_ENCODE) {
+      if (mozilla::AndroidBridge::Bridge()) {
+        *aStatus = mozilla::AndroidBridge::Bridge()->GetHWEncoderCapability() ? nsIGfxInfo::FEATURE_STATUS_OK : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
         return NS_OK;
-      } else {
-        // Blocklist all other devices except Nexus 5 which VP8 hardware acceleration is supported
-        *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
+      }
+    }
+    if (aFeature == FEATURE_WEBRTC_HW_ACCELERATION_DECODE) {
+      if (mozilla::AndroidBridge::Bridge()) {
+        *aStatus = mozilla::AndroidBridge::Bridge()->GetHWDecoderCapability() ? nsIGfxInfo::FEATURE_STATUS_OK : nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
         return NS_OK;
       }
     }
   }
 
   return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, &os);
 }
 
--- a/widget/nsIGfxInfo.idl
+++ b/widget/nsIGfxInfo.idl
@@ -3,17 +3,17 @@
  * 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 "nsISupports.idl"
 
 /* NOTE: this interface is completely undesigned, not stable and likely to change */
 
-[scriptable, uuid(98690931-c9a5-4675-9ab4-90932ec32bf2)]
+[scriptable, uuid(4b5ea59e-af89-44f7-8c1c-2dea47a170d1)]
 interface nsIGfxInfo : nsISupports
 {
   /*
    * These are win32-specific
    */
   readonly attribute boolean D2DEnabled;
   readonly attribute boolean DWriteEnabled;
   readonly attribute DOMString DWriteVersion;
@@ -97,16 +97,20 @@ interface nsIGfxInfo : nsISupports
   /* Whether Webrtc Hardware acceleration is supported, starting in 31. */
   const long FEATURE_WEBRTC_HW_ACCELERATION = 10;
   /* Whether Direct3D 11 is supported for layers, starting in 32. */
   const long FEATURE_DIRECT3D_11_LAYERS = 11;
   /* Whether hardware accelerated video decoding is supported, starting in 36. */
   const long FEATURE_HARDWARE_VIDEO_DECODING = 12;
   /* Whether Direct3D 11 is supported for ANGLE, starting in 38. */
   const long FEATURE_DIRECT3D_11_ANGLE = 13;
+  /* Whether Webrtc Hardware acceleration is supported, starting in 42. */
+  const long FEATURE_WEBRTC_HW_ACCELERATION_ENCODE = 14;
+  /* Whether Webrtc Hardware acceleration is supported, starting in 42. */
+  const long FEATURE_WEBRTC_HW_ACCELERATION_DECODE = 15;
 
   /*
    * A set of return values from GetFeatureStatus
    */
 
   /* The driver is safe to the best of our knowledge */
   const long FEATURE_STATUS_OK = 1;
   /* We don't know the status of the feature yet. The analysis probably hasn't finished yet. */