| Index: media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
|
| diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
|
| index f6d97af9f23fd9c05cb4d45dcdbe26f5cffca74e..e3673d73aa5ed0f86e03d1d93df5fed0ceecedd1 100644
|
| --- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
|
| +++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
|
| @@ -15,6 +15,8 @@ import org.chromium.base.annotations.CalledByNative;
|
| import org.chromium.base.annotations.JNINamespace;
|
| import org.chromium.base.annotations.MainDex;
|
|
|
| +import java.util.Arrays;
|
| +import java.util.List;
|
| import java.util.Locale;
|
|
|
| /**
|
| @@ -22,7 +24,7 @@ import java.util.Locale;
|
| */
|
| @JNINamespace("media")
|
| class MediaCodecUtil {
|
| - private static final String TAG = "MediaCodecUtil";
|
| + private static final String TAG = "cr_MediaCodecUtil";
|
|
|
| // Codec direction. Keep this in sync with media_codec_direction.h.
|
| static final int MEDIA_CODEC_DECODER = 0;
|
| @@ -356,4 +358,123 @@ class MediaCodecUtil {
|
| }
|
| return false;
|
| }
|
| +
|
| + // List of supported HW encoders.
|
| + private static enum HWEncoderProperties {
|
| + QcomVp8(MimeTypes.VIDEO_VP8, "OMX.qcom.", Build.VERSION_CODES.KITKAT),
|
| + QcomH264(MimeTypes.VIDEO_H264, "OMX.qcom.", Build.VERSION_CODES.KITKAT),
|
| + ExynosVp8(MimeTypes.VIDEO_VP8, "OMX.Exynos.", Build.VERSION_CODES.M),
|
| + ExynosH264(MimeTypes.VIDEO_H264, "OMX.Exynos.", Build.VERSION_CODES.LOLLIPOP);
|
| +
|
| + private final String mMime;
|
| + private final String mPrefix;
|
| + private final int mMinSDK;
|
| +
|
| + private HWEncoderProperties(String mime, String prefix, int minSDK) {
|
| + this.mMime = mime;
|
| + this.mPrefix = prefix;
|
| + this.mMinSDK = minSDK;
|
| + }
|
| +
|
| + public String getMime() {
|
| + return mMime;
|
| + }
|
| +
|
| + public String getPrefix() {
|
| + return mPrefix;
|
| + }
|
| +
|
| + public int getMinSDK() {
|
| + return mMinSDK;
|
| + }
|
| + }
|
| +
|
| + // List of devices with poor H.264 encoder quality.
|
| + private static final String[] H264_ENCODER_MODEL_BLACKLIST = new String[] {
|
| + // HW H.264 encoder on below devices has poor bitrate control - actual bitrates deviates
|
| + // a lot from the target value.
|
| + "SAMSUNG-SGH-I337", "Nexus 7", "Nexus 4"};
|
| +
|
| + /**
|
| + * Creates MediaCodec encoder.
|
| + * @param mime MIME type of the media.
|
| + * @return CodecCreationInfo object
|
| + */
|
| + static CodecCreationInfo createEncoder(String mime) {
|
| + // Always return a valid CodecCreationInfo, its |mediaCodec| field will be null
|
| + // if we cannot create the codec.
|
| + CodecCreationInfo result = new CodecCreationInfo();
|
| +
|
| + if (!isEncoderSupportedByDevice(mime)) return result;
|
| +
|
| + try {
|
| + result.mediaCodec = MediaCodec.createEncoderByType(mime);
|
| + result.supportsAdaptivePlayback = false;
|
| + } catch (Exception e) {
|
| + Log.e(TAG, "Failed to create MediaCodec: %s", mime, e);
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + /**
|
| + * This is a way to blacklist misbehaving devices.
|
| + * @param mime MIME type as passed to mediaCodec.createEncoderByType(mime).
|
| + * @return true if this codec is supported for encoder on this device.
|
| + */
|
| + @CalledByNative
|
| + static boolean isEncoderSupportedByDevice(String mime) {
|
| + // MediaCodec.setParameters is missing for JB and below, so bitrate
|
| + // can not be adjusted dynamically.
|
| + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
| + return false;
|
| + }
|
| +
|
| + // Check if this is supported HW encoder.
|
| + if (mime.equals(MimeTypes.VIDEO_H264)) {
|
| + // Check if device is in H.264 exception list.
|
| + List<String> exceptionModels = Arrays.asList(H264_ENCODER_MODEL_BLACKLIST);
|
| + if (exceptionModels.contains(Build.MODEL)) {
|
| + Log.w(TAG, "Model: " + Build.MODEL + " has blacklisted H.264 encoder.");
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + MediaCodecListHelper codecListHelper = new MediaCodecListHelper();
|
| + int codecCount = codecListHelper.getCodecCount();
|
| + for (int i = 0; i < codecCount; ++i) {
|
| + MediaCodecInfo info = codecListHelper.getCodecInfoAt(i);
|
| +
|
| + if (!info.isEncoder() || isSoftwareCodec(info.getName())) continue;
|
| +
|
| + String encoderName = null;
|
| + for (String mimeType : info.getSupportedTypes()) {
|
| + if (mimeType.equalsIgnoreCase(mime)) {
|
| + encoderName = info.getName();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (encoderName == null) {
|
| + continue; // No HW support in this codec; try the next one.
|
| + }
|
| +
|
| + // Check if this is supported HW encoder.
|
| + for (HWEncoderProperties codecProperties : HWEncoderProperties.values()) {
|
| + if (!mime.equalsIgnoreCase(codecProperties.getMime())) continue;
|
| +
|
| + if (encoderName.startsWith(codecProperties.getPrefix())) {
|
| + if (Build.VERSION.SDK_INT < codecProperties.getMinSDK()) {
|
| + Log.w(TAG, "Codec " + encoderName + " is disabled due to SDK version "
|
| + + Build.VERSION.SDK_INT);
|
| + continue;
|
| + }
|
| + Log.d(TAG, "Found target encoder for mime " + mime + " : " + encoderName);
|
| + return true;
|
| + }
|
| + }
|
| + }
|
| +
|
| + Log.w(TAG, "HW encoder for " + mime + " is not available on this device.");
|
| + return false;
|
| + }
|
| }
|
|
|