/** * @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; }
/** * Optional call to warm the codec cache for a given mime type. * <p> * Calling this method may speed up subsequent calls to {@link #getDecoderInfo(String, boolean)}. * * @param mimeType The mime type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. */ public static synchronized void warmCodec(String mimeType, boolean secure) { try { getMediaCodecInfo(mimeType, secure); } catch (DecoderQueryException e) { // Codec warming is best effort, so we can swallow the exception. Log.e(TAG, "Codec warming failed", e); } }
/** * @return the maximum frame size for an H264 stream that can be decoded on the device. */ public static int maxH264DecodableFrameSize() throws DecoderQueryException { Pair<String, CodecCapabilities> info = getMediaCodecInfo(MimeTypes.VIDEO_H264, false); if (info == null) { return 0; } int maxH264DecodableFrameSize = 0; CodecCapabilities capabilities = info.second; for (int i = 0; i < capabilities.profileLevels.length; i++) { CodecProfileLevel profileLevel = capabilities.profileLevels[i]; maxH264DecodableFrameSize = Math.max( avcLevelToMaxFrameSize(profileLevel.level), maxH264DecodableFrameSize); } return maxH264DecodableFrameSize; }
/** * Get information about the decoder that will be used for a given mime type. * * @param mimeType The mime type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. * @return Information about the decoder that will be used, or null if no decoder exists. */ public static DecoderInfo getDecoderInfo(String mimeType, boolean secure) throws DecoderQueryException { Pair<String, CodecCapabilities> info = getMediaCodecInfo(mimeType, secure); if (info == null) { return null; } return new DecoderInfo(info.first, isAdaptive(info.second)); }
/** * Returns the name of the best decoder and its capabilities for the given mimeType. */ private static synchronized Pair<String, CodecCapabilities> getMediaCodecInfo( String mimeType, boolean secure) throws DecoderQueryException { CodecKey key = new CodecKey(mimeType, secure); if (codecs.containsKey(key)) { return codecs.get(key); } MediaCodecListCompat mediaCodecList = Util.SDK_INT >= 21 ? new MediaCodecListCompatV21(secure) : new MediaCodecListCompatV16(); Pair<String, CodecCapabilities> codecInfo = getMediaCodecInfo(key, mediaCodecList); // TODO: Verify this cannot occur on v22, and change >= to == [Internal: b/18678462]. if (secure && codecInfo == null && Util.SDK_INT >= 21) { // Some devices don't list secure decoders on API level 21. Try the legacy path. mediaCodecList = new MediaCodecListCompatV16(); codecInfo = getMediaCodecInfo(key, mediaCodecList); if (codecInfo != null) { Log.w(TAG, "MediaCodecList API didn't list secure decoder for: " + mimeType + ". Assuming: " + codecInfo.first); } } return codecInfo; }
/** * Tests whether the device advertises it can decode video of a given type at a specified * width, height, and frame rate. * <p> * Must not be called if the device SDK version is less than 21. * * @param mimeType The mime type. * @param secure Whether the decoder is required to support secure decryption. Always pass false * unless secure decryption really is required. * @param width Width in pixels. * @param height Height in pixels. * @param frameRate Frame rate in frames per second. * @return Whether the decoder advertises support of the given size and frame rate. */ @TargetApi(21) public static boolean isSizeAndRateSupportedV21(String mimeType, boolean secure, int width, int height, double frameRate) throws DecoderQueryException { Assertions.checkState(Util.SDK_INT >= 21); Pair<String, CodecCapabilities> info = getMediaCodecInfo(mimeType, secure); if (info == null) { return false; } MediaCodecInfo.VideoCapabilities videoCapabilities = info.second.getVideoCapabilities(); return videoCapabilities != null && videoCapabilities.areSizeAndRateSupported(width, height, frameRate); }