private static DecoderProperties findDecoder(String mime, String[] supportedCodecPrefixes) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { return null; // MediaCodec.setParameters is missing. } 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(mime)) { name = info.getName(); break; } } if (name == null) { continue; // No HW support in this codec; try the next one. } Logging.v(TAG, "Found candidate decoder " + name); // Check if this is supported decoder. boolean supportedCodec = false; for (String codecPrefix : supportedCodecPrefixes) { if (name.startsWith(codecPrefix)) { supportedCodec = true; break; } } if (!supportedCodec) { continue; } // Check if codec supports either yuv420 or nv12. CodecCapabilities capabilities = info.getCapabilitiesForType(mime); for (int colorFormat : capabilities.colorFormats) { Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); } for (int supportedColorFormat : supportedColorList) { for (int codecColorFormat : capabilities.colorFormats) { if (codecColorFormat == supportedColorFormat) { // Found supported HW decoder. Logging.d( TAG, "Found target decoder " + name + ". Color: 0x" + Integer.toHexString(codecColorFormat)); return new DecoderProperties(name, codecColorFormat); } } } } return null; // No HW decoder. }
/** * Creates new instance of <tt>CodecInfo</tt> that will encapsulate given <tt>codecInfo</tt>. * * @param codecInfo the codec info object to encapsulate. * @param mediaType media type of the codec */ public CodecInfo(MediaCodecInfo codecInfo, String mediaType) { this.codecInfo = codecInfo; this.mediaType = mediaType; this.caps = codecInfo.getCapabilitiesForType(mediaType); this.colors = new ArrayList<CodecColorFormat>(); int[] colorFormats = caps.colorFormats; for (int colorFormat : colorFormats) { colors.add(CodecColorFormat.fromInt(colorFormat)); } }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static IjkMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo, String mimeType) { if (codecInfo == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return null; String name = codecInfo.getName(); if (TextUtils.isEmpty(name)) return null; name = name.toLowerCase(Locale.US); int rank = RANK_NO_SENSE; if (!name.startsWith("omx.")) { rank = RANK_NON_STANDARD; } else if (name.startsWith("omx.pv")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.google.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.ffmpeg.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.k3.ffmpeg.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.avcodec.")) { rank = RANK_SOFTWARE; } else if (name.startsWith("omx.ittiam.")) { // unknown codec in qualcomm SoC rank = RANK_NO_SENSE; } else if (name.startsWith("omx.mtk.")) { // 1. MTK only works on 4.3 and above // 2. MTK works on MIUI 6 (4.2.1) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) rank = RANK_NO_SENSE; else rank = RANK_TESTED; } else { Integer knownRank = getKnownCodecList().get(name); if (knownRank != null) { rank = knownRank; } else { try { CodecCapabilities cap = codecInfo.getCapabilitiesForType(mimeType); if (cap != null) rank = RANK_ACCEPTABLE; else rank = RANK_LAST_CHANCE; } catch (Throwable e) { rank = RANK_LAST_CHANCE; } } } IjkMediaCodecInfo candidate = new IjkMediaCodecInfo(); candidate.mCodecInfo = codecInfo; candidate.mRank = rank; candidate.mMimeType = mimeType; return candidate; }
@SuppressWarnings("RedundantThrows") public static String dumpDecoders() throws Exception { String str = ""; for (MediaCodecInfo codecInfo : getMediaCodecList()) { // Skip encoders if (codecInfo.isEncoder()) { continue; } str += "Decoder: " + codecInfo.getName() + "\n"; for (String type : codecInfo.getSupportedTypes()) { str += "\t" + type + "\n"; CodecCapabilities caps = codecInfo.getCapabilitiesForType(type); for (CodecProfileLevel profile : caps.profileLevels) { str += "\t\t" + profile.profile + " " + profile.level + "\n"; } } } return str; }
// We declare this method as explicitly throwing Exception // since some bad decoders can throw IllegalArgumentExceptions unexpectedly // and we want to be sure all callers are handling this possibility @SuppressWarnings("RedundantThrows") private static MediaCodecInfo findKnownSafeDecoder(String mimeType, int requiredProfile) throws Exception { for (MediaCodecInfo codecInfo : getMediaCodecList()) { // Skip encoders if (codecInfo.isEncoder()) { continue; } // Check for explicitly blacklisted decoders if (isDecoderInList(blacklistedDecoderPrefixes, codecInfo.getName())) { LimeLog.info("Skipping blacklisted decoder: " + codecInfo.getName()); continue; } // Find a decoder that supports the requested video format for (String mime : codecInfo.getSupportedTypes()) { if (mime.equalsIgnoreCase(mimeType)) { LimeLog.info("Examining decoder capabilities of " + codecInfo.getName()); CodecCapabilities caps = codecInfo.getCapabilitiesForType(mime); if (requiredProfile != -1) { for (CodecProfileLevel profile : caps.profileLevels) { if (profile.profile == requiredProfile) { LimeLog.info("Decoder " + codecInfo.getName() + " supports required profile"); return codecInfo; } } LimeLog.info("Decoder " + codecInfo.getName() + " does NOT support required profile"); } else { return codecInfo; } } } } return null; }
private boolean supports(String mimeType, int profile, int level, boolean testLevel) { int numCodecs = MediaCodecList.getCodecCount(); for (int i = 0; i < numCodecs; i++) { MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); if (codecInfo.isEncoder()) { continue; } if (!supportsMimeType(codecInfo, mimeType)) { continue; } CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType); for (CodecProfileLevel profileLevel : capabilities.profileLevels) { if (profileLevel.profile == profile && (!testLevel || profileLevel.level >= level)) { return true; } } } return false; }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) public void dumpProfileLevels(String mimeType) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return; try { CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mimeType); int maxProfile = 0; int maxLevel = 0; if (caps != null) { if (caps.profileLevels != null) { for (CodecProfileLevel profileLevel : caps.profileLevels) { if (profileLevel == null) continue; maxProfile = Math.max(maxProfile, profileLevel.profile); maxLevel = Math.max(maxLevel, profileLevel.level); } } } Log.i(TAG, String.format(Locale.US, "%s", getProfileLevelName(maxProfile, maxLevel))); } catch (Throwable e) { Log.i(TAG, "profile-level: exception"); } }