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 254721 cf1dbe9a71cf2350f029d1a41c7ed7a02200370b
parent 254720 3fd7798e4bf1a75190075e857e2d0a085714fd58
child 254722 eaf549a7c5f49829fb75f35f39ad10f817c36026
push id62836
push userryanvm@gmail.com
push dateMon, 27 Jul 2015 14:41:39 +0000
treeherdermozilla-inbound@e039b166890f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1178069
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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. */