Bug 1178069 - Check devices capability before enable use of vp8 hardware acceleration using android.media.MediaCodecList and android.media.MediaCodecInfo r=jrmuizel

This commit is contained in:
Qiang Lu 2015-07-24 12:45:55 -07:00
parent 8060707f38
commit 9d8feab426
13 changed files with 289 additions and 17 deletions

View File

@ -886,7 +886,7 @@ MediaPipelineFactory::EnsureExternalCodec(VideoSessionConduit& aConduit,
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 {
@ -911,11 +911,10 @@ MediaPipelineFactory::EnsureExternalCodec(VideoSessionConduit& aConduit,
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) {

View File

@ -47,6 +47,7 @@ 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;
@ -92,6 +93,7 @@ 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;
@ -961,6 +963,16 @@ public class GeckoAppShell
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();

View File

@ -83,6 +83,7 @@ gujar.sources += [
'util/GeckoEventListener.java',
'util/GeckoJarReader.java',
'util/GeckoRequest.java',
'util/HardwareCodecCapabilityUtils.java',
'util/HardwareUtils.java',
'util/INIParser.java',
'util/INISection.java',

View File

@ -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.
}
}

View File

@ -132,6 +132,32 @@
<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>

View File

@ -107,6 +107,12 @@ function run_test() {
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);

View File

@ -151,6 +151,12 @@ GetPrefNameForFeature(int32_t aFeature)
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;
};
@ -340,6 +346,10 @@ BlacklistFeatureToGfxFeature(const nsAString& aFeature)
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;
@ -972,6 +982,8 @@ GfxInfoBase::EvaluateDownloadedBlacklist(nsTArray<GfxDriverInfo>& aDriverInfo)
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,

View File

@ -471,6 +471,27 @@ AndroidBridge::GetHandlersForMimeType(const nsAString& 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,

View File

@ -207,6 +207,9 @@ public:
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);

View File

@ -278,6 +278,22 @@ mozilla::jni::String::LocalRef GeckoAppShell::GetExternalPublicDirectory(mozilla
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[];

View File

@ -644,6 +644,40 @@ public:
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;

View File

@ -587,20 +587,15 @@ GfxInfo::GetFeatureStatusImpl(int32_t aFeature,
}
}
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;
}
}

View File

@ -8,7 +8,7 @@
/* 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
{
/*
@ -102,6 +102,10 @@ interface nsIGfxInfo : nsISupports
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