diff options
| -rw-r--r-- | media/java/android/media/MediaCodecInfo.java | 98 | ||||
| -rw-r--r-- | media/java/android/media/MediaFormat.java | 10 |
2 files changed, 103 insertions, 5 deletions
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 87c6d88a0c11..349d67ec9145 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -567,6 +567,34 @@ public final class MediaCodecInfo { return false; } } + + Integer profile = (Integer)map.get(MediaFormat.KEY_PROFILE); + Integer level = (Integer)map.get(MediaFormat.KEY_LEVEL); + + if (profile != null) { + if (!supportsProfileLevel(profile, level)) { + return false; + } + + // If we recognize this profile, check that this format is supported by the + // highest level supported by the codec for that profile. (Ignore specified + // level beyond the above profile/level check as level is only used as a + // guidance. E.g. AVC Level 1 CIF format is supported if codec supports level 1.1 + // even though max size for Level 1 is QCIF. However, MPEG2 Simple Profile + // 1080p format is not supported even if codec supports Main Profile Level High, + // as Simple Profile does not support 1080p. + CodecCapabilities levelCaps = null; + int maxLevel = 0; + for (CodecProfileLevel pl : profileLevels) { + if (pl.profile == profile && pl.level > maxLevel) { + maxLevel = pl.level; + } + } + levelCaps = createFromProfileLevel(mMime, profile, maxLevel); + if (levelCaps != null && !levelCaps.isFormatSupported(format)) { + return false; + } + } if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) { return false; } @@ -579,6 +607,57 @@ public final class MediaCodecInfo { return true; } + private static boolean supportsBitrate( + Range<Integer> bitrateRange, MediaFormat format) { + Map<String, Object> map = format.getMap(); + + // consider max bitrate over average bitrate for support + Integer maxBitrate = (Integer)map.get(MediaFormat.KEY_MAX_BIT_RATE); + Integer bitrate = (Integer)map.get(MediaFormat.KEY_BIT_RATE); + if (bitrate == null) { + bitrate = maxBitrate; + } else if (maxBitrate != null) { + bitrate = Math.max(bitrate, maxBitrate); + } + + if (bitrate != null && bitrate > 0) { + return bitrateRange.contains(bitrate); + } + + return true; + } + + private boolean supportsProfileLevel(int profile, Integer level) { + for (CodecProfileLevel pl: profileLevels) { + if (pl.profile != profile) { + continue; + } + + // AAC does not use levels + if (level == null || mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AAC)) { + return true; + } + + // H.263 levels are not completely ordered: + // Level45 support only implies Level10 support + if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { + if (pl.level != level && pl.level == CodecProfileLevel.H263Level45 + && level > CodecProfileLevel.H263Level10) { + continue; + } + } + if (pl.level >= level) { + // if we recognize the listed profile/level, we must also recognize the + // profile/level arguments. + if (createFromProfileLevel(mMime, profile, pl.level) != null) { + return createFromProfileLevel(mMime, profile, level) != null; + } + return true; + } + } + return false; + } + // errors while reading profile levels - accessed from sister capabilities int mError; @@ -1004,10 +1083,15 @@ public final class MediaCodecInfo { Map<String, Object> map = format.getMap(); Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE); Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT); + if (!supports(sampleRate, channels)) { return false; } + if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { + return false; + } + // nothing to do for: // KEY_CHANNEL_MASK: codecs don't get this // KEY_IS_ADTS: required feature for all AAC decoders @@ -1310,8 +1394,7 @@ public final class MediaCodecInfo { return supports(width, height, null); } - private boolean supports( - Integer width, Integer height, Number rate) { + private boolean supports(Integer width, Integer height, Number rate) { boolean ok = true; if (ok && width != null) { @@ -1353,9 +1436,16 @@ public final class MediaCodecInfo { Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT); Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE); - // we ignore color-format for now as it is not reliably reported by codec + if (!supports(width, height, rate)) { + return false; + } - return supports(width, height, rate); + if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) { + return false; + } + + // we ignore color-format for now as it is not reliably reported by codec + return true; } /* no public constructor */ diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 93c595f1ca2b..33e39575fdac 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -185,12 +185,20 @@ public final class MediaFormat { public static final String KEY_MAX_INPUT_SIZE = "max-input-size"; /** - * A key describing the bitrate in bits/sec. + * A key describing the average bitrate in bits/sec. * The associated value is an integer */ public static final String KEY_BIT_RATE = "bitrate"; /** + * A key describing the max bitrate in bits/sec. + * This is usually over a one-second sliding window (e.g. over any window of one second). + * The associated value is an integer + * @hide + */ + public static final String KEY_MAX_BIT_RATE = "max-bitrate"; + + /** * A key describing the color format of the content in a video format. * Constants are declared in {@link android.media.MediaCodecInfo.CodecCapabilities}. */ |