/** * @return the maximum frame size for an H264 stream that can be decoded on the device. */ public static int maxH264DecodableFrameSize() throws DecoderQueryException { if (maxH264DecodableFrameSize == -1) { int result = 0; DecoderInfo decoderInfo = getDecoderInfo(MimeTypes.VIDEO_H264, false); if (decoderInfo != null) { for (CodecProfileLevel profileLevel : decoderInfo.capabilities.profileLevels) { result = Math.max(avcLevelToMaxFrameSize(profileLevel.level), result); } // We assume support for at least 360p. result = Math.max(result, 480 * 360); } maxH264DecodableFrameSize = result; } return maxH264DecodableFrameSize; }
/** * Conversion values taken from ISO 14496-10 Table A-1. * * @param avcLevel one of CodecProfileLevel.AVCLevel* constants. * @return maximum frame size that can be decoded by a decoder with the specified avc level * (or {@code -1} if the level is not recognized) */ private static int avcLevelToMaxFrameSize(int avcLevel) { switch (avcLevel) { case CodecProfileLevel.AVCLevel1: return 99 * 16 * 16; case CodecProfileLevel.AVCLevel1b: return 99 * 16 * 16; case CodecProfileLevel.AVCLevel12: return 396 * 16 * 16; case CodecProfileLevel.AVCLevel13: return 396 * 16 * 16; case CodecProfileLevel.AVCLevel2: return 396 * 16 * 16; case CodecProfileLevel.AVCLevel21: return 792 * 16 * 16; case CodecProfileLevel.AVCLevel22: return 1620 * 16 * 16; case CodecProfileLevel.AVCLevel3: return 1620 * 16 * 16; case CodecProfileLevel.AVCLevel31: return 3600 * 16 * 16; case CodecProfileLevel.AVCLevel32: return 5120 * 16 * 16; case CodecProfileLevel.AVCLevel4: return 8192 * 16 * 16; case CodecProfileLevel.AVCLevel41: return 8192 * 16 * 16; case CodecProfileLevel.AVCLevel42: return 8704 * 16 * 16; case CodecProfileLevel.AVCLevel5: return 22080 * 16 * 16; case CodecProfileLevel.AVCLevel51: return 36864 * 16 * 16; default: return -1; } }
public static String getProfileName(int profile) { switch (profile) { case CodecProfileLevel.AVCProfileBaseline: return "Baseline"; case CodecProfileLevel.AVCProfileMain: return "Main"; case CodecProfileLevel.AVCProfileExtended: return "Extends"; case CodecProfileLevel.AVCProfileHigh: return "High"; case CodecProfileLevel.AVCProfileHigh10: return "High10"; case CodecProfileLevel.AVCProfileHigh422: return "High422"; case CodecProfileLevel.AVCProfileHigh444: return "High444"; default: return "Unknown"; } }
/** * Returns the maximum frame size supported by the default H264 decoder. * * @return The maximum frame size for an H264 stream that can be decoded on the device. */ public static int maxH264DecodableFrameSize() throws DecoderQueryException { if (maxH264DecodableFrameSize == -1) { int result = 0; MediaCodecInfo decoderInfo = getDecoderInfo(MimeTypes.VIDEO_H264, false); if (decoderInfo != null) { for (CodecProfileLevel profileLevel : decoderInfo.getProfileLevels()) { result = Math.max(avcLevelToMaxFrameSize(profileLevel.level), result); } // We assume support for at least 480p (SDK_INT >= 21) or 360p (SDK_INT < 21), which are // the levels mandated by the Android CDD. result = Math.max(result, Util.SDK_INT >= 21 ? (720 * 480) : (480 * 360)); } maxH264DecodableFrameSize = result; } return maxH264DecodableFrameSize; }
/** * Conversion values taken from ISO 14496-10 Table A-1. * * @param avcLevel one of CodecProfileLevel.AVCLevel* constants. * @return maximum frame size that can be decoded by a decoder with the specified avc level * (or {@code -1} if the level is not recognized) */ private static int avcLevelToMaxFrameSize(int avcLevel) { switch (avcLevel) { case CodecProfileLevel.AVCLevel1: return 99 * 16 * 16; case CodecProfileLevel.AVCLevel1b: return 99 * 16 * 16; case CodecProfileLevel.AVCLevel12: return 396 * 16 * 16; case CodecProfileLevel.AVCLevel13: return 396 * 16 * 16; case CodecProfileLevel.AVCLevel2: return 396 * 16 * 16; case CodecProfileLevel.AVCLevel21: return 792 * 16 * 16; case CodecProfileLevel.AVCLevel22: return 1620 * 16 * 16; case CodecProfileLevel.AVCLevel3: return 1620 * 16 * 16; case CodecProfileLevel.AVCLevel31: return 3600 * 16 * 16; case CodecProfileLevel.AVCLevel32: return 5120 * 16 * 16; case CodecProfileLevel.AVCLevel4: return 8192 * 16 * 16; case CodecProfileLevel.AVCLevel41: return 8192 * 16 * 16; case CodecProfileLevel.AVCLevel42: return 8704 * 16 * 16; case CodecProfileLevel.AVCLevel5: return 22080 * 16 * 16; case CodecProfileLevel.AVCLevel51: return 36864 * 16 * 16; case CodecProfileLevel.AVCLevel52: return 36864 * 16 * 16; default: return -1; } }
@SuppressLint("InlinedApi") private static int parseAvcProfile(byte[] data) { int profileIdc = data[6] & 0xFF; switch (profileIdc) { case 0x42: return CodecProfileLevel.AVCProfileBaseline; case 0x4d: return CodecProfileLevel.AVCProfileMain; case 0x58: return CodecProfileLevel.AVCProfileExtended; case 0x64: return CodecProfileLevel.AVCProfileHigh; case 0x6e: return CodecProfileLevel.AVCProfileHigh10; case 0x7a: return CodecProfileLevel.AVCProfileHigh422; case 0xf4: return CodecProfileLevel.AVCProfileHigh444; default: return 0; } }
/** * @param profile An AVC profile constant from {@link CodecProfileLevel}. * @param level An AVC profile level from {@link CodecProfileLevel}. * @return Whether the specified profile is supported at the specified level. */ public static boolean isH264ProfileSupported(int profile, int level) throws DecoderQueryException { Pair<String, CodecCapabilities> info = getMediaCodecInfo(MimeTypes.VIDEO_H264, false); if (info == null) { return false; } CodecCapabilities capabilities = info.second; for (int i = 0; i < capabilities.profileLevels.length; i++) { CodecProfileLevel profileLevel = capabilities.profileLevels[i]; if (profileLevel.profile == profile && profileLevel.level >= level) { return true; } } return false; }
/** * Conversion values taken from: https://en.wikipedia.org/wiki/H.264/MPEG-4_AVC. * * @param avcLevel one of CodecProfileLevel.AVCLevel* constants. * @return maximum frame size that can be decoded by a decoder with the specified avc level * (or {@code -1} if the level is not recognized) */ private static int avcLevelToMaxFrameSize(int avcLevel) { switch (avcLevel) { case CodecProfileLevel.AVCLevel1: return 25344; case CodecProfileLevel.AVCLevel1b: return 25344; case CodecProfileLevel.AVCLevel12: return 101376; case CodecProfileLevel.AVCLevel13: return 101376; case CodecProfileLevel.AVCLevel2: return 101376; case CodecProfileLevel.AVCLevel21: return 202752; case CodecProfileLevel.AVCLevel22: return 414720; case CodecProfileLevel.AVCLevel3: return 414720; case CodecProfileLevel.AVCLevel31: return 921600; case CodecProfileLevel.AVCLevel32: return 1310720; case CodecProfileLevel.AVCLevel4: return 2097152; case CodecProfileLevel.AVCLevel41: return 2097152; case CodecProfileLevel.AVCLevel42: return 2228224; case CodecProfileLevel.AVCLevel5: return 5652480; case CodecProfileLevel.AVCLevel51: return 9437184; default: return -1; } }
/** * Whether the decoder supports the given {@code codec}. If there is insufficient information to * decide, returns true. * * @param codec Codec string as defined in RFC 6381. * @return True if the given codec is supported by the decoder. */ public boolean isCodecSupported(String codec) { if (codec == null || mimeType == null) { return true; } String codecMimeType = MimeTypes.getMediaMimeType(codec); if (codecMimeType == null) { return true; } if (!mimeType.equals(codecMimeType)) { return false; } Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(codec); if (codecProfileAndLevel == null) { // If we don't know any better, we assume that the profile and level are supported. return true; } for (CodecProfileLevel capabilities : getProfileLevels()) { if (capabilities.profile == codecProfileAndLevel.first && capabilities.level >= codecProfileAndLevel.second) { return true; } } return false; }
/** * Returns the maximum frame size supported by the default H264 decoder. * * @return The maximum frame size for an H264 stream that can be decoded on the device. */ public static int maxH264DecodableFrameSize() throws DecoderQueryException { if (maxH264DecodableFrameSize == -1) { int result = 0; MediaCodecInfo decoderInfo = getDecoderInfo(MimeTypes.VIDEO_H264, false); if (decoderInfo != null) { for (CodecProfileLevel profileLevel : decoderInfo.getProfileLevels()) { result = Math.max(avcLevelToMaxFrameSize(profileLevel.level), result); } // We assume support for at least 360p. result = Math.max(result, 480 * 360); } maxH264DecodableFrameSize = result; } return maxH264DecodableFrameSize; }
/** * @param profile An AVC profile constant from {@link CodecProfileLevel}. * @param level An AVC profile level from {@link CodecProfileLevel}. * @return Whether the specified profile is supported at the specified level. */ public static boolean isH264ProfileSupported(int profile, int level) { Pair<String, CodecCapabilities> info = getMediaCodecInfo(MimeTypes.VIDEO_H264, false); if (info == null) { return false; } CodecCapabilities capabilities = info.second; for (int i = 0; i < capabilities.profileLevels.length; i++) { CodecProfileLevel profileLevel = capabilities.profileLevels[i]; if (profileLevel.profile == profile && profileLevel.level >= level) { return true; } } return false; }
/** * Return an array of supported codecs and profiles. */ @CalledByNative private static Object[] getSupportedCodecProfileLevels() { CodecProfileLevelList profileLevels = new CodecProfileLevelList(); MediaCodecListHelper codecListHelper = new MediaCodecListHelper(); for (MediaCodecInfo info : codecListHelper) { for (String mime : info.getSupportedTypes()) { // On versions L and M, VP9 codecCapabilities do not advertise profile level // support. In this case, estimate the level from MediaCodecInfo.VideoCapabilities // instead. Assume VP9 is not supported before L. For more information, consult // https://developer.android.com/reference/android/media/MediaCodecInfo.CodecProfileLevel.html CodecCapabilities codecCapabilities = info.getCapabilitiesForType(mime); if (mime.endsWith("vp9") && Build.VERSION_CODES.LOLLIPOP <= Build.VERSION.SDK_INT && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { addVp9CodecProfileLevels(profileLevels, codecCapabilities); continue; } for (CodecProfileLevel profileLevel : codecCapabilities.profileLevels) { profileLevels.addCodecProfileLevel(mime, profileLevel); } } } return profileLevels.toArray(); }
/** * @param profile An AVC profile constant from {@link CodecProfileLevel}. * @param level An AVC profile level from {@link CodecProfileLevel}. * @return Whether the specified profile is supported at the specified level. */ public static boolean isH264ProfileSupported(int profile, int level) { Pair<MediaCodecInfo, CodecCapabilities> info = getMediaCodecInfo(MimeTypes.VIDEO_H264); if (info == null) { return false; } CodecCapabilities capabilities = info.second; for (int i = 0; i < capabilities.profileLevels.length; i++) { CodecProfileLevel profileLevel = capabilities.profileLevels[i]; if (profileLevel.profile == profile && profileLevel.level >= level) { return true; } } return false; }