Merge "media: check profile, level and bitrate for isFormatSupported" into nyc-dev

This commit is contained in:
Lajos Molnar
2016-05-26 06:14:03 +00:00
committed by Android (Google) Code Review
2 changed files with 103 additions and 5 deletions

View File

@@ -567,6 +567,34 @@ public final class MediaCodecInfo {
return false; 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)) { if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
return false; return false;
} }
@@ -579,6 +607,57 @@ public final class MediaCodecInfo {
return true; 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 // errors while reading profile levels - accessed from sister capabilities
int mError; int mError;
@@ -1004,10 +1083,15 @@ public final class MediaCodecInfo {
Map<String, Object> map = format.getMap(); Map<String, Object> map = format.getMap();
Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE); Integer sampleRate = (Integer)map.get(MediaFormat.KEY_SAMPLE_RATE);
Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT); Integer channels = (Integer)map.get(MediaFormat.KEY_CHANNEL_COUNT);
if (!supports(sampleRate, channels)) { if (!supports(sampleRate, channels)) {
return false; return false;
} }
if (!CodecCapabilities.supportsBitrate(mBitrateRange, format)) {
return false;
}
// nothing to do for: // nothing to do for:
// KEY_CHANNEL_MASK: codecs don't get this // KEY_CHANNEL_MASK: codecs don't get this
// KEY_IS_ADTS: required feature for all AAC decoders // KEY_IS_ADTS: required feature for all AAC decoders
@@ -1310,8 +1394,7 @@ public final class MediaCodecInfo {
return supports(width, height, null); return supports(width, height, null);
} }
private boolean supports( private boolean supports(Integer width, Integer height, Number rate) {
Integer width, Integer height, Number rate) {
boolean ok = true; boolean ok = true;
if (ok && width != null) { if (ok && width != null) {
@@ -1353,9 +1436,16 @@ public final class MediaCodecInfo {
Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT); Integer height = (Integer)map.get(MediaFormat.KEY_HEIGHT);
Number rate = (Number)map.get(MediaFormat.KEY_FRAME_RATE); 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 */ /* no public constructor */

View File

@@ -185,11 +185,19 @@ public final class MediaFormat {
public static final String KEY_MAX_INPUT_SIZE = "max-input-size"; 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 * The associated value is an integer
*/ */
public static final String KEY_BIT_RATE = "bitrate"; 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. * A key describing the color format of the content in a video format.
* Constants are declared in {@link android.media.MediaCodecInfo.CodecCapabilities}. * Constants are declared in {@link android.media.MediaCodecInfo.CodecCapabilities}.