mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
8060707f38
commit
9d8feab426
@ -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) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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',
|
||||
|
143
mobile/android/base/util/HardwareCodecCapabilityUtils.java
Normal file
143
mobile/android/base/util/HardwareCodecCapabilityUtils.java
Normal 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.
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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[];
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user