diff options
author | dalecurtis <dalecurtis@chromium.org> | 2016-03-17 15:03:35 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-17 22:04:46 +0000 |
commit | 5c1bee20afe6113087fc9a5781b5773a8894bbd4 (patch) | |
tree | 59fe5e75e3aa02db28783bb09d01f8fd5bdda15b /media/base | |
parent | b6d0d3c36ca322e5f2cb4513198f9d91b5ee53a9 (diff) | |
download | chromium_src-5c1bee20afe6113087fc9a5781b5773a8894bbd4.zip chromium_src-5c1bee20afe6113087fc9a5781b5773a8894bbd4.tar.gz chromium_src-5c1bee20afe6113087fc9a5781b5773a8894bbd4.tar.bz2 |
Cleanup MediaCodecUtil::GetDefaultCodecName().
There's no need to build an entire list of codecs and transport that
across JNI when we always want the first one in the list.
Notably this reduces the cost of GpuChildThread::OnInitialize() by
over 400ms on an N5 running Marshmallow (450.208ms vs 39.64ms)! The
reduction comes from VideoEncodeAccelerator no longer creating ~3
MediaCodec instances to determine the codec name during the call to
VideoEncodeAccelerator::GetSupportedProfiles() during child thread
startup. I suspect this will translate into real GPU process startup
improvements.
BUG=594814
TEST=codec lists match before after on KitKat below and above.
Review URL: https://codereview.chromium.org/1805163002
Cr-Commit-Position: refs/heads/master@{#381805}
Diffstat (limited to 'media/base')
-rw-r--r-- | media/base/android/java/src/org/chromium/media/MediaCodecUtil.java | 178 | ||||
-rw-r--r-- | media/base/android/media_codec_util.cc | 116 |
2 files changed, 66 insertions, 228 deletions
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 8383583..16ee434 100644 --- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java +++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java @@ -15,10 +15,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.MainDex; -import java.util.ArrayList; -import java.util.HashMap; import java.util.Locale; -import java.util.Map; /** * A collection of MediaCodec utility functions. @@ -32,37 +29,6 @@ class MediaCodecUtil { static final int MEDIA_CODEC_ENCODER = 1; /** - * This class represents supported android codec information. - */ - @MainDex - private static class CodecInfo { - private final String mCodecType; // e.g. "video/x-vnd.on2.vp8". - private final String mCodecName; // e.g. "OMX.google.vp8.decoder". - private final int mDirection; - - private CodecInfo(String codecType, String codecName, int direction) { - mCodecType = codecType; - mCodecName = codecName; - mDirection = direction; - } - - @CalledByNative("CodecInfo") - private String codecType() { - return mCodecType; - } - - @CalledByNative("CodecInfo") - private String codecName() { - return mCodecName; - } - - @CalledByNative("CodecInfo") - private int direction() { - return mDirection; - } - } - - /** * Class to pass parameters from createDecoder() */ @MainDex @@ -72,33 +38,35 @@ class MediaCodecUtil { } /** - * @return a list of supported android codec information. + * Class to abstract platform version API differences for interacting with + * the MediaCodecList. */ - @SuppressWarnings("deprecation") - @CalledByNative - private static CodecInfo[] getCodecsInfo() { - // Return the first (highest-priority) codec for each MIME type. - Map<String, CodecInfo> encoderInfoMap = new HashMap<String, CodecInfo>(); - Map<String, CodecInfo> decoderInfoMap = new HashMap<String, CodecInfo>(); - int count = MediaCodecList.getCodecCount(); - for (int i = 0; i < count; ++i) { - MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); - int direction = info.isEncoder() ? MEDIA_CODEC_ENCODER : MEDIA_CODEC_DECODER; - String codecString = info.getName(); - String[] supportedTypes = info.getSupportedTypes(); - for (int j = 0; j < supportedTypes.length; ++j) { - Map<String, CodecInfo> map = info.isEncoder() ? encoderInfoMap : decoderInfoMap; - if (!map.containsKey(supportedTypes[j])) { - map.put(supportedTypes[j], - new CodecInfo(supportedTypes[j], codecString, direction)); - } + @MainDex + private static class MediaCodecListHelper { + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public MediaCodecListHelper() { + if (hasNewMediaCodecList()) { + mCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS).getCodecInfos(); } } - ArrayList<CodecInfo> codecInfos = - new ArrayList<CodecInfo>(decoderInfoMap.size() + encoderInfoMap.size()); - codecInfos.addAll(encoderInfoMap.values()); - codecInfos.addAll(decoderInfoMap.values()); - return codecInfos.toArray(new CodecInfo[codecInfos.size()]); + + @SuppressWarnings("deprecation") + public int getCodecCount() { + if (hasNewMediaCodecList()) return mCodecList.length; + return MediaCodecList.getCodecCount(); + } + + @SuppressWarnings("deprecation") + public MediaCodecInfo getCodecInfoAt(int index) { + if (hasNewMediaCodecList()) return mCodecList[index]; + return MediaCodecList.getCodecInfoAt(index); + } + + private boolean hasNewMediaCodecList() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + } + + private MediaCodecInfo[] mCodecList; } /** @@ -107,27 +75,24 @@ class MediaCodecUtil { * @param direction Whether this is encoder or decoder. * @return name of the codec. */ - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) - @SuppressWarnings("deprecation") @CalledByNative private static String getDefaultCodecName(String mime, int direction) { - String codecName = ""; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - try { - MediaCodec mediaCodec = null; - if (direction == MEDIA_CODEC_ENCODER) { - mediaCodec = MediaCodec.createEncoderByType(mime); - } else { - mediaCodec = MediaCodec.createDecoderByType(mime); - } - codecName = mediaCodec.getName(); - mediaCodec.release(); - } catch (Exception e) { - Log.w(TAG, "getDefaultCodecName: Failed to create MediaCodec: %s, direction: %d", - mime, direction, e); + MediaCodecListHelper codecListHelper = new MediaCodecListHelper(); + int codecCount = codecListHelper.getCodecCount(); + for (int i = 0; i < codecCount; ++i) { + MediaCodecInfo info = codecListHelper.getCodecInfoAt(i); + + int codecDirection = info.isEncoder() ? MEDIA_CODEC_ENCODER : MEDIA_CODEC_DECODER; + if (codecDirection != direction) continue; + + String[] supportedTypes = info.getSupportedTypes(); + for (int j = 0; j < supportedTypes.length; ++j) { + if (supportedTypes[j].equalsIgnoreCase(mime)) return info.getName(); } } - return codecName; + + Log.e(TAG, "Decoder for type %s is not supported on this device", mime); + return ""; } /** @@ -135,63 +100,18 @@ class MediaCodecUtil { * @param mime MIME type of the media format. * @return a list of encoder supported color formats. */ - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @SuppressWarnings("deprecation") @CalledByNative private static int[] getEncoderColorFormatsForMime(String mime) { - MediaCodecInfo[] codecs = null; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS); - codecs = mediaCodecList.getCodecInfos(); - } else { - int count = MediaCodecList.getCodecCount(); - if (count <= 0) { - return null; - } - codecs = new MediaCodecInfo[count]; - for (int i = 0; i < count; ++i) { - MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); - codecs[i] = info; - } - } - - for (int i = 0; i < codecs.length; i++) { - if (!codecs[i].isEncoder()) { - continue; - } - - String[] supportedTypes = codecs[i].getSupportedTypes(); - for (int j = 0; j < supportedTypes.length; ++j) { - if (!supportedTypes[j].equalsIgnoreCase(mime)) { - continue; - } - - MediaCodecInfo.CodecCapabilities capabilities = - codecs[i].getCapabilitiesForType(mime); - return capabilities.colorFormats; - } - } - return null; - } - - /** - * Get decoder name for the input MIME type. - * @param mime MIME type of the media. - * @return name of the decoder. - */ - @SuppressWarnings("deprecation") - static String getDecoderNameForMime(String mime) { - int count = MediaCodecList.getCodecCount(); - for (int i = 0; i < count; ++i) { - MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i); - if (info.isEncoder()) { - continue; - } + MediaCodecListHelper codecListHelper = new MediaCodecListHelper(); + int codecCount = codecListHelper.getCodecCount(); + for (int i = 0; i < codecCount; i++) { + MediaCodecInfo info = codecListHelper.getCodecInfoAt(i); + if (!info.isEncoder()) continue; String[] supportedTypes = info.getSupportedTypes(); for (int j = 0; j < supportedTypes.length; ++j) { if (supportedTypes[j].equalsIgnoreCase(mime)) { - return info.getName(); + return info.getCapabilitiesForType(supportedTypes[j]).colorFormats; } } } @@ -236,15 +156,15 @@ class MediaCodecUtil { // Do not create codec for blacklisted devices. if (!isDecoderSupportedForDevice(mime)) { - Log.e(TAG, "Decoder for type " + mime + " is not supported on this device"); + Log.e(TAG, "Decoder for type %s is not supported on this device", mime); return result; } try { // |isSecure| only applies to video decoders. if (mime.startsWith("video") && isSecure) { - String decoderName = getDecoderNameForMime(mime); - if (decoderName == null) return null; + String decoderName = getDefaultCodecName(mime, MEDIA_CODEC_DECODER); + if (decoderName.equals("")) return null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // To work around an issue that we cannot get the codec info from the secure // decoder, create an insecure decoder first so that we can query its codec diff --git a/media/base/android/media_codec_util.cc b/media/base/android/media_codec_util.cc index ae726d0..5ad3254 100644 --- a/media/base/android/media_codec_util.cc +++ b/media/base/android/media_codec_util.cc @@ -25,8 +25,7 @@ using base::android::ScopedJavaLocalRef; namespace media { -// static -const std::string CodecTypeToAndroidMimeType(const std::string& codec) { +static std::string CodecTypeToAndroidMimeType(const std::string& codec) { // TODO(xhwang): Shall we handle more detailed strings like "mp4a.40.2"? if (codec == "avc1") return "video/avc"; @@ -45,34 +44,9 @@ const std::string CodecTypeToAndroidMimeType(const std::string& codec) { return std::string(); } -// TODO(qinmin): using a map to help all the conversions in this class. -const std::string AndroidMimeTypeToCodecType(const std::string& mime) { - if (mime == "video/mp4v-es") - return "mp4v"; - if (mime == "video/avc") - return "avc1"; - if (mime == "video/hevc") - return "hvc1"; - if (mime == "video/x-vnd.on2.vp8") - return "vp8"; - if (mime == "video/x-vnd.on2.vp9") - return "vp9"; - if (mime == "audio/mp4a-latm") - return "mp4a"; - if (mime == "audio/mpeg") - return "mp3"; - if (mime == "audio/vorbis") - return "vorbis"; - if (mime == "audio/opus") - return "opus"; - return std::string(); -} - -std::string GetDefaultCodecName(const std::string& mime_type, - MediaCodecDirection direction) { - if (!MediaCodecUtil::IsMediaCodecAvailable()) - return std::string(); - +static std::string GetDefaultCodecName(const std::string& mime_type, + MediaCodecDirection direction) { + DCHECK(MediaCodecUtil::IsMediaCodecAvailable()); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jstring> j_mime = ConvertUTF8ToJavaString(env, mime_type); ScopedJavaLocalRef<jstring> j_codec_name = @@ -80,49 +54,6 @@ std::string GetDefaultCodecName(const std::string& mime_type, return ConvertJavaStringToUTF8(env, j_codec_name.obj()); } -bool SupportsGetName() { - // MediaCodec.getName() is only available on JB MR2 and greater. - return base::android::BuildInfo::GetInstance()->sdk_int() >= 18; -} - -// Represents supported codecs on android. -// TODO(qinmin): Currently the codecs string only contains one codec. Do we -// need to support codecs separated by comma. (e.g. "vp8" -> "vp8, vp8.0")? -struct CodecsInfo { - std::string codecs; // E.g. "vp8" or "avc1". - std::string name; // E.g. "OMX.google.vp8.decoder". - MediaCodecDirection direction; -}; - -// Get a list of supported codecs. -std::vector<CodecsInfo> GetCodecsInfo() { - std::vector<CodecsInfo> codecs_info; - if (!MediaCodecUtil::IsMediaCodecAvailable()) - return codecs_info; - - JNIEnv* env = AttachCurrentThread(); - std::string mime_type; - ScopedJavaLocalRef<jobjectArray> j_codec_info_array = - Java_MediaCodecUtil_getCodecsInfo(env); - jsize len = env->GetArrayLength(j_codec_info_array.obj()); - for (jsize i = 0; i < len; ++i) { - ScopedJavaLocalRef<jobject> j_info( - env, env->GetObjectArrayElement(j_codec_info_array.obj(), i)); - ScopedJavaLocalRef<jstring> j_codec_type = - Java_CodecInfo_codecType(env, j_info.obj()); - ConvertJavaStringToUTF8(env, j_codec_type.obj(), &mime_type); - ScopedJavaLocalRef<jstring> j_codec_name = - Java_CodecInfo_codecName(env, j_info.obj()); - CodecsInfo info; - info.codecs = AndroidMimeTypeToCodecType(mime_type); - ConvertJavaStringToUTF8(env, j_codec_name.obj(), &info.name); - info.direction = static_cast<MediaCodecDirection>( - Java_CodecInfo_direction(env, j_info.obj())); - codecs_info.push_back(info); - } - return codecs_info; -} - // static bool MediaCodecUtil::IsMediaCodecAvailable() { // MediaCodec is only available on JB and greater. @@ -183,38 +114,25 @@ bool MediaCodecUtil::IsKnownUnaccelerated(const std::string& mime_type, if (!IsMediaCodecAvailable()) return true; - std::string codec_name; - if (SupportsGetName()) { - codec_name = GetDefaultCodecName(mime_type, direction); - } else { - std::string codec_type = AndroidMimeTypeToCodecType(mime_type); - std::vector<CodecsInfo> codecs_info = GetCodecsInfo(); - for (size_t i = 0; i < codecs_info.size(); ++i) { - if (codecs_info[i].codecs == codec_type && - codecs_info[i].direction == direction) { - codec_name = codecs_info[i].name; - break; - } - } - } - DVLOG(1) << __PRETTY_FUNCTION__ << "Default codec for " << mime_type << " : " - << codec_name; + std::string codec_name = GetDefaultCodecName(mime_type, direction); + DVLOG(1) << __FUNCTION__ << "Default codec for " << mime_type << " : " + << codec_name << ", direction: " << direction; + if (!codec_name.size()) + return true; + // It would be nice if MediaCodecInfo externalized some notion of // HW-acceleration but it doesn't. Android Media guidance is that the // "OMX.google" prefix is always used for SW decoders, so that's what we // use. "OMX.SEC.*" codec is Samsung software implementation - report it // as unaccelerated as well. MediaTek hardware vp8 is known slower than // the software implementation. http://crbug.com/446974. - if (codec_name.length() > 0) { - return base::StartsWith(codec_name, "OMX.google.", - base::CompareCase::SENSITIVE) || - base::StartsWith(codec_name, "OMX.SEC.", - base::CompareCase::SENSITIVE) || - (base::StartsWith(codec_name, "OMX.MTK.", - base::CompareCase::SENSITIVE) && - mime_type == "video/x-vnd.on2.vp8"); - } - return true; + return base::StartsWith(codec_name, "OMX.google.", + base::CompareCase::SENSITIVE) || + base::StartsWith(codec_name, "OMX.SEC.", + base::CompareCase::SENSITIVE) || + (base::StartsWith(codec_name, "OMX.MTK.", + base::CompareCase::SENSITIVE) && + mime_type == "video/x-vnd.on2.vp8"); } // static |