Loading media/java/android/media/MediaCodecInfo.java +94 −35 Original line number Diff line number Diff line Loading @@ -450,10 +450,16 @@ public final class MediaCodecInfo { } private void applyLevelLimits() { if (mParent.getMime().equalsIgnoreCase( MediaFormat.MIMETYPE_AUDIO_FLAC)) { String mime = mParent.getMime(); if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { mComplexityRange = Range.create(0, 8); mBitControl = (1 << BITRATE_MODE_CQ); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { mBitControl = (1 << BITRATE_MODE_CBR); } } Loading Loading @@ -514,11 +520,12 @@ public final class MediaCodecInfo { /** @hide */ public void setDefaultFormat(MediaFormat format) { if (mQualityRange.getUpper() != mQualityRange.getLower() // don't list trivial quality/complexity as default for now if (!mQualityRange.getUpper().equals(mQualityRange.getLower()) && mDefaultQuality != null) { format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality); } if (mComplexityRange.getUpper() != mComplexityRange.getLower() if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower()) && mDefaultComplexity != null) { format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity); } Loading Loading @@ -985,34 +992,34 @@ public final class MediaCodecInfo { if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { // codec supports profiles that we don't know. // Extend ranges clipped to platform limits. // Use supplied values clipped to platform limits if (widths != null) { mWidthRange = mWidthRange.extend(widths); mWidthRange = SIZE_RANGE.intersect(widths); } if (heights != null) { mHeightRange = mHeightRange.extend(heights); mHeightRange = SIZE_RANGE.intersect(heights); } if (counts != null) { mBlockCountRange = mBlockCountRange.extend( mBlockCountRange = POSITIVE_INTEGERS.intersect( Utils.factorRange(counts, mBlockWidth * mBlockHeight / blockSize.getWidth() / blockSize.getHeight())); } if (blockRates != null) { mBlocksPerSecondRange = mBlocksPerSecondRange.extend( mBlocksPerSecondRange = POSITIVE_LONGS.intersect( Utils.factorRange(blockRates, mBlockWidth * mBlockHeight / blockSize.getWidth() / blockSize.getHeight())); } if (blockRatios != null) { mBlockAspectRatioRange = mBlockAspectRatioRange.extend( mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect( Utils.scaleRange(blockRatios, mBlockHeight / blockSize.getHeight(), mBlockWidth / blockSize.getWidth())); } if (ratios != null) { mAspectRatioRange = mAspectRatioRange.extend(ratios); mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios); } if (frameRates != null) { mFrameRateRange = mFrameRateRange.extend(frameRates); mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); } } else { // no unsupported profile/levels, so restrict values to known limits Loading Loading @@ -1235,7 +1242,6 @@ public final class MediaCodecInfo { Log.w(TAG, "Unrecognized level " + profileLevel.level + " for " + mime); errors |= ERROR_UNRECOGNIZED; supported = false; } switch (profileLevel.profile) { case CodecProfileLevel.AVCProfileHigh: Loading @@ -1245,7 +1251,7 @@ public final class MediaCodecInfo { case CodecProfileLevel.AVCProfileExtended: case CodecProfileLevel.AVCProfileHigh422: case CodecProfileLevel.AVCProfileHigh444: Log.w(TAG, "Unrecognized profile " Log.w(TAG, "Unsupported profile " + profileLevel.profile + " for " + mime); errors |= ERROR_UNSUPPORTED; supported = false; Loading @@ -1271,7 +1277,9 @@ public final class MediaCodecInfo { int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); applyMacroBlockLimits( maxLengthInBlocks, maxLengthInBlocks, maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1); maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { int maxWidth = 11, maxHeight = 9, maxRate = 15; maxBlocks = 99; Loading Loading @@ -1369,7 +1377,9 @@ public final class MediaCodecInfo { maxRate = Math.max(FR, maxRate); } applyMacroBlockLimits(maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1); maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); mFrameRateRange = mFrameRateRange.intersect(12, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { int maxWidth = 11, maxHeight = 9, maxRate = 15; Loading Loading @@ -1432,7 +1442,9 @@ public final class MediaCodecInfo { maxRate = Math.max(FR, maxRate); } applyMacroBlockLimits(maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1); maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); mFrameRateRange = Range.create(1, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { Loading Loading @@ -1465,6 +1477,12 @@ public final class MediaCodecInfo { } errors &= ~ERROR_NONE_SUPPORTED; } final int blockSize = mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8; applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE, maxBlocks, maxBlocksPerSecond, blockSize, blockSize, 1 /* widthAlignment */, 1 /* heightAlignment */); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { maxBlocks = 36864; maxBlocksPerSecond = maxBlocks * 15; Loading Loading @@ -1493,17 +1511,17 @@ public final class MediaCodecInfo { FR = 30; FS = 2228224; BR = 12000; break; case CodecProfileLevel.HEVCHighTierLevel4: FR = 30; FS = 2228224; BR = 30000; break; case CodecProfileLevel.HEVCHighTierLevel41: FR = 60; FS = 2228224; BR = 20000; break; case CodecProfileLevel.HEVCMainTierLevel41: FR = 60; FS = 2228224; BR = 20000; break; case CodecProfileLevel.HEVCHighTierLevel41: FR = 60; FS = 2228224; BR = 50000; break; case CodecProfileLevel.HEVCHighTierLevel5: FR = 30; FS = 8912896; BR = 25000; break; case CodecProfileLevel.HEVCMainTierLevel5: FR = 30; FS = 8912896; BR = 25000; break; case CodecProfileLevel.HEVCHighTierLevel5: FR = 30; FS = 8912896; BR = 100000; break; case CodecProfileLevel.HEVCHighTierLevel51: FR = 60; FS = 8912896; BR = 40000; break; case CodecProfileLevel.HEVCMainTierLevel51: FR = 60; FS = 8912896; BR = 40000; break; case CodecProfileLevel.HEVCHighTierLevel51: FR = 60; FS = 8912896; BR = 160000; break; case CodecProfileLevel.HEVCMainTierLevel52: FR = 120; FS = 8912896; BR = 60000; break; Loading @@ -1513,13 +1531,13 @@ public final class MediaCodecInfo { FR = 30; FS = 35651584; BR = 60000; break; case CodecProfileLevel.HEVCHighTierLevel6: FR = 30; FS = 35651584; BR = 240000; break; case CodecProfileLevel.HEVCHighTierLevel61: FR = 60; FS = 35651584; BR = 120000; break; case CodecProfileLevel.HEVCMainTierLevel61: FR = 60; FS = 35651584; BR = 120000; break; case CodecProfileLevel.HEVCHighTierLevel61: FR = 60; FS = 35651584; BR = 480000; break; case CodecProfileLevel.HEVCHighTierLevel62: FR = 120; FS = 35651584; BR = 240000; break; case CodecProfileLevel.HEVCMainTierLevel62: FR = 120; FS = 35651584; BR = 240000; break; case CodecProfileLevel.HEVCHighTierLevel62: FR = 120; FS = 35651584; BR = 800000; break; default: Log.w(TAG, "Unrecognized level " Loading Loading @@ -1557,9 +1575,13 @@ public final class MediaCodecInfo { applyMacroBlockLimits( maxLengthInBlocks, maxLengthInBlocks, maxBlocks, maxBlocksPerSecond, 8, 8, 1, 1); maxBlocks, maxBlocksPerSecond, 8 /* blockWidth */, 8 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); } else { Log.w(TAG, "Unsupported mime " + mime); // using minimal bitrate here. should be overriden by // info from media_codecs.xml maxBps = 64000; errors |= ERROR_UNSUPPORTED; } Loading Loading @@ -1628,21 +1650,26 @@ public final class MediaCodecInfo { if (mMime.toLowerCase().startsWith("audio/")) { mAudioCaps = AudioCapabilities.create(info, this); mAudioCaps.setDefaultFormat(mDefaultFormat); } else if (mMime.toLowerCase().startsWith("video/")) { mVideoCaps = VideoCapabilities.create(info, this); } if (encoder) { mEncoderCaps = EncoderCapabilities.create(info, this); mEncoderCaps.setDefaultFormat(mDefaultFormat); } for (Feature feat: getValidFeatures()) { Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); String key = MediaFormat.KEY_FEATURE_ + feat.mName; Integer yesNo = (Integer)map.get(key); if (yesNo == null) { continue; } else if (yesNo > 0) { mFlagsRequired |= feat.mValue; mDefaultFormat.setInteger(key, 1); } else { mFlagsSupported |= feat.mValue; mDefaultFormat.setInteger(key, 1); } // TODO restrict features by mFlagsVerified once all codecs reliably verify them } Loading @@ -1652,10 +1679,14 @@ public final class MediaCodecInfo { * A class that supports querying the audio capabilities of a codec. */ public static final class AudioCapabilities extends BaseCapabilities { private static final String TAG = "AudioCapabilities"; private int[] mSampleRates; private Range<Integer>[] mSampleRateRanges; private int mMaxInputChannelCount; private static final int MAX_INPUT_CHANNEL_COUNT = 30; /** * Returns the array of supported sample rates if the codec * supports only discrete values. Otherwise, it returns Loading Loading @@ -1702,7 +1733,7 @@ public final class MediaCodecInfo { } private void initWithPlatformLimits() { mMaxInputChannelCount = 30; mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT; // mBitrateRange = Range.create(1, 320000); mSampleRateRanges = new Range[] { Range.create(8000, 96000) }; mSampleRates = null; Loading Loading @@ -1758,7 +1789,7 @@ public final class MediaCodecInfo { // check if all values are discrete for (Range<Integer> range: mSampleRateRanges) { if (range.getLower() != range.getUpper()) { if (!range.getLower().equals(range.getUpper())) { mSampleRates = null; return; } Loading @@ -1777,7 +1808,7 @@ public final class MediaCodecInfo { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; bitRates = Range.create(8192, 327680); bitRates = Range.create(8000, 320000); maxChannels = 2; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { sampleRates = new int[] { 8000 }; Loading Loading @@ -1807,11 +1838,23 @@ public final class MediaCodecInfo { } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { sampleRateRange = Range.create(1, 96000); bitRates = Range.create(1, 10000000); maxChannels = 6; maxChannels = 8; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { sampleRateRange = Range.create(1, 655350); // lossless codec, so bitrate is ignored maxChannels = 255; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) { sampleRates = new int[] { 8000 }; bitRates = Range.create(64000, 64000); // platform allows multiple channels for this format } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { sampleRates = new int[] { 8000 }; bitRates = Range.create(13000, 13000); maxChannels = 1; } else { Log.w(TAG, "Unsupported mime " + mime); mParent.mError |= ERROR_UNSUPPORTED; } // restrict ranges Loading @@ -1832,7 +1875,7 @@ public final class MediaCodecInfo { } private void parseFromInfo(MediaFormat info) { int maxInputChannels = 1; int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; Range<Integer> bitRates = POSITIVE_INTEGERS; if (info.containsKey("sample-rate-ranges")) { Loading @@ -1844,7 +1887,8 @@ public final class MediaCodecInfo { limitSampleRates(rateRanges); } if (info.containsKey("max-channel-count")) { maxInputChannels = info.getInteger("max-channel-count"); maxInputChannels = Utils.parseIntSafely( info.getString("max-channel-count"), maxInputChannels); } if (info.containsKey("bitrate-range")) { bitRates = bitRates.intersect( Loading @@ -1853,6 +1897,21 @@ public final class MediaCodecInfo { applyLimits(maxInputChannels, bitRates); } /** @hide */ public void setDefaultFormat(MediaFormat format) { // report settings that have only a single choice if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) { format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower()); } if (mMaxInputChannelCount == 1) { // mono-only format format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); } if (mSampleRates != null && mSampleRates.length == 1) { format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]); } } /** @hide */ public boolean supportsFormat(MediaFormat format) { Map<String, Object> map = format.getMap(); Loading media/java/android/media/Utils.java +13 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,19 @@ class Utils { return fallback; } static int parseIntSafely(Object o, int fallback) { try { String s = (String)o; return Integer.parseInt(s); } catch (ClassCastException e) { } catch (NumberFormatException e) { } catch (NullPointerException e) { return fallback; } Log.w(TAG, "could not parse integer '" + o + "'"); return fallback; } static Range<Integer> parseIntRange(Object o, Range<Integer> fallback) { try { String s = (String)o; Loading Loading
media/java/android/media/MediaCodecInfo.java +94 −35 Original line number Diff line number Diff line Loading @@ -450,10 +450,16 @@ public final class MediaCodecInfo { } private void applyLevelLimits() { if (mParent.getMime().equalsIgnoreCase( MediaFormat.MIMETYPE_AUDIO_FLAC)) { String mime = mParent.getMime(); if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { mComplexityRange = Range.create(0, 8); mBitControl = (1 << BITRATE_MODE_CQ); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_WB) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { mBitControl = (1 << BITRATE_MODE_CBR); } } Loading Loading @@ -514,11 +520,12 @@ public final class MediaCodecInfo { /** @hide */ public void setDefaultFormat(MediaFormat format) { if (mQualityRange.getUpper() != mQualityRange.getLower() // don't list trivial quality/complexity as default for now if (!mQualityRange.getUpper().equals(mQualityRange.getLower()) && mDefaultQuality != null) { format.setInteger(MediaFormat.KEY_QUALITY, mDefaultQuality); } if (mComplexityRange.getUpper() != mComplexityRange.getLower() if (!mComplexityRange.getUpper().equals(mComplexityRange.getLower()) && mDefaultComplexity != null) { format.setInteger(MediaFormat.KEY_COMPLEXITY, mDefaultComplexity); } Loading Loading @@ -985,34 +992,34 @@ public final class MediaCodecInfo { if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { // codec supports profiles that we don't know. // Extend ranges clipped to platform limits. // Use supplied values clipped to platform limits if (widths != null) { mWidthRange = mWidthRange.extend(widths); mWidthRange = SIZE_RANGE.intersect(widths); } if (heights != null) { mHeightRange = mHeightRange.extend(heights); mHeightRange = SIZE_RANGE.intersect(heights); } if (counts != null) { mBlockCountRange = mBlockCountRange.extend( mBlockCountRange = POSITIVE_INTEGERS.intersect( Utils.factorRange(counts, mBlockWidth * mBlockHeight / blockSize.getWidth() / blockSize.getHeight())); } if (blockRates != null) { mBlocksPerSecondRange = mBlocksPerSecondRange.extend( mBlocksPerSecondRange = POSITIVE_LONGS.intersect( Utils.factorRange(blockRates, mBlockWidth * mBlockHeight / blockSize.getWidth() / blockSize.getHeight())); } if (blockRatios != null) { mBlockAspectRatioRange = mBlockAspectRatioRange.extend( mBlockAspectRatioRange = POSITIVE_RATIONALS.intersect( Utils.scaleRange(blockRatios, mBlockHeight / blockSize.getHeight(), mBlockWidth / blockSize.getWidth())); } if (ratios != null) { mAspectRatioRange = mAspectRatioRange.extend(ratios); mAspectRatioRange = POSITIVE_RATIONALS.intersect(ratios); } if (frameRates != null) { mFrameRateRange = mFrameRateRange.extend(frameRates); mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); } } else { // no unsupported profile/levels, so restrict values to known limits Loading Loading @@ -1235,7 +1242,6 @@ public final class MediaCodecInfo { Log.w(TAG, "Unrecognized level " + profileLevel.level + " for " + mime); errors |= ERROR_UNRECOGNIZED; supported = false; } switch (profileLevel.profile) { case CodecProfileLevel.AVCProfileHigh: Loading @@ -1245,7 +1251,7 @@ public final class MediaCodecInfo { case CodecProfileLevel.AVCProfileExtended: case CodecProfileLevel.AVCProfileHigh422: case CodecProfileLevel.AVCProfileHigh444: Log.w(TAG, "Unrecognized profile " Log.w(TAG, "Unsupported profile " + profileLevel.profile + " for " + mime); errors |= ERROR_UNSUPPORTED; supported = false; Loading @@ -1271,7 +1277,9 @@ public final class MediaCodecInfo { int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); applyMacroBlockLimits( maxLengthInBlocks, maxLengthInBlocks, maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1); maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { int maxWidth = 11, maxHeight = 9, maxRate = 15; maxBlocks = 99; Loading Loading @@ -1369,7 +1377,9 @@ public final class MediaCodecInfo { maxRate = Math.max(FR, maxRate); } applyMacroBlockLimits(maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1); maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); mFrameRateRange = mFrameRateRange.intersect(12, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { int maxWidth = 11, maxHeight = 9, maxRate = 15; Loading Loading @@ -1432,7 +1442,9 @@ public final class MediaCodecInfo { maxRate = Math.max(FR, maxRate); } applyMacroBlockLimits(maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, 16, 16, 1, 1); maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); mFrameRateRange = Range.create(1, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP9)) { Loading Loading @@ -1465,6 +1477,12 @@ public final class MediaCodecInfo { } errors &= ~ERROR_NONE_SUPPORTED; } final int blockSize = mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8) ? 16 : 8; applyMacroBlockLimits(Short.MAX_VALUE, Short.MAX_VALUE, maxBlocks, maxBlocksPerSecond, blockSize, blockSize, 1 /* widthAlignment */, 1 /* heightAlignment */); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { maxBlocks = 36864; maxBlocksPerSecond = maxBlocks * 15; Loading Loading @@ -1493,17 +1511,17 @@ public final class MediaCodecInfo { FR = 30; FS = 2228224; BR = 12000; break; case CodecProfileLevel.HEVCHighTierLevel4: FR = 30; FS = 2228224; BR = 30000; break; case CodecProfileLevel.HEVCHighTierLevel41: FR = 60; FS = 2228224; BR = 20000; break; case CodecProfileLevel.HEVCMainTierLevel41: FR = 60; FS = 2228224; BR = 20000; break; case CodecProfileLevel.HEVCHighTierLevel41: FR = 60; FS = 2228224; BR = 50000; break; case CodecProfileLevel.HEVCHighTierLevel5: FR = 30; FS = 8912896; BR = 25000; break; case CodecProfileLevel.HEVCMainTierLevel5: FR = 30; FS = 8912896; BR = 25000; break; case CodecProfileLevel.HEVCHighTierLevel5: FR = 30; FS = 8912896; BR = 100000; break; case CodecProfileLevel.HEVCHighTierLevel51: FR = 60; FS = 8912896; BR = 40000; break; case CodecProfileLevel.HEVCMainTierLevel51: FR = 60; FS = 8912896; BR = 40000; break; case CodecProfileLevel.HEVCHighTierLevel51: FR = 60; FS = 8912896; BR = 160000; break; case CodecProfileLevel.HEVCMainTierLevel52: FR = 120; FS = 8912896; BR = 60000; break; Loading @@ -1513,13 +1531,13 @@ public final class MediaCodecInfo { FR = 30; FS = 35651584; BR = 60000; break; case CodecProfileLevel.HEVCHighTierLevel6: FR = 30; FS = 35651584; BR = 240000; break; case CodecProfileLevel.HEVCHighTierLevel61: FR = 60; FS = 35651584; BR = 120000; break; case CodecProfileLevel.HEVCMainTierLevel61: FR = 60; FS = 35651584; BR = 120000; break; case CodecProfileLevel.HEVCHighTierLevel61: FR = 60; FS = 35651584; BR = 480000; break; case CodecProfileLevel.HEVCHighTierLevel62: FR = 120; FS = 35651584; BR = 240000; break; case CodecProfileLevel.HEVCMainTierLevel62: FR = 120; FS = 35651584; BR = 240000; break; case CodecProfileLevel.HEVCHighTierLevel62: FR = 120; FS = 35651584; BR = 800000; break; default: Log.w(TAG, "Unrecognized level " Loading Loading @@ -1557,9 +1575,13 @@ public final class MediaCodecInfo { applyMacroBlockLimits( maxLengthInBlocks, maxLengthInBlocks, maxBlocks, maxBlocksPerSecond, 8, 8, 1, 1); maxBlocks, maxBlocksPerSecond, 8 /* blockWidth */, 8 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); } else { Log.w(TAG, "Unsupported mime " + mime); // using minimal bitrate here. should be overriden by // info from media_codecs.xml maxBps = 64000; errors |= ERROR_UNSUPPORTED; } Loading Loading @@ -1628,21 +1650,26 @@ public final class MediaCodecInfo { if (mMime.toLowerCase().startsWith("audio/")) { mAudioCaps = AudioCapabilities.create(info, this); mAudioCaps.setDefaultFormat(mDefaultFormat); } else if (mMime.toLowerCase().startsWith("video/")) { mVideoCaps = VideoCapabilities.create(info, this); } if (encoder) { mEncoderCaps = EncoderCapabilities.create(info, this); mEncoderCaps.setDefaultFormat(mDefaultFormat); } for (Feature feat: getValidFeatures()) { Integer yesNo = (Integer)map.get(MediaFormat.KEY_FEATURE_ + feat.mName); String key = MediaFormat.KEY_FEATURE_ + feat.mName; Integer yesNo = (Integer)map.get(key); if (yesNo == null) { continue; } else if (yesNo > 0) { mFlagsRequired |= feat.mValue; mDefaultFormat.setInteger(key, 1); } else { mFlagsSupported |= feat.mValue; mDefaultFormat.setInteger(key, 1); } // TODO restrict features by mFlagsVerified once all codecs reliably verify them } Loading @@ -1652,10 +1679,14 @@ public final class MediaCodecInfo { * A class that supports querying the audio capabilities of a codec. */ public static final class AudioCapabilities extends BaseCapabilities { private static final String TAG = "AudioCapabilities"; private int[] mSampleRates; private Range<Integer>[] mSampleRateRanges; private int mMaxInputChannelCount; private static final int MAX_INPUT_CHANNEL_COUNT = 30; /** * Returns the array of supported sample rates if the codec * supports only discrete values. Otherwise, it returns Loading Loading @@ -1702,7 +1733,7 @@ public final class MediaCodecInfo { } private void initWithPlatformLimits() { mMaxInputChannelCount = 30; mMaxInputChannelCount = MAX_INPUT_CHANNEL_COUNT; // mBitrateRange = Range.create(1, 320000); mSampleRateRanges = new Range[] { Range.create(8000, 96000) }; mSampleRates = null; Loading Loading @@ -1758,7 +1789,7 @@ public final class MediaCodecInfo { // check if all values are discrete for (Range<Integer> range: mSampleRateRanges) { if (range.getLower() != range.getUpper()) { if (!range.getLower().equals(range.getUpper())) { mSampleRates = null; return; } Loading @@ -1777,7 +1808,7 @@ public final class MediaCodecInfo { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }; bitRates = Range.create(8192, 327680); bitRates = Range.create(8000, 320000); maxChannels = 2; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AMR_NB)) { sampleRates = new int[] { 8000 }; Loading Loading @@ -1807,11 +1838,23 @@ public final class MediaCodecInfo { } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { sampleRateRange = Range.create(1, 96000); bitRates = Range.create(1, 10000000); maxChannels = 6; maxChannels = 8; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { sampleRateRange = Range.create(1, 655350); // lossless codec, so bitrate is ignored maxChannels = 255; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_ALAW) || mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_G711_MLAW)) { sampleRates = new int[] { 8000 }; bitRates = Range.create(64000, 64000); // platform allows multiple channels for this format } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_MSGSM)) { sampleRates = new int[] { 8000 }; bitRates = Range.create(13000, 13000); maxChannels = 1; } else { Log.w(TAG, "Unsupported mime " + mime); mParent.mError |= ERROR_UNSUPPORTED; } // restrict ranges Loading @@ -1832,7 +1875,7 @@ public final class MediaCodecInfo { } private void parseFromInfo(MediaFormat info) { int maxInputChannels = 1; int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; Range<Integer> bitRates = POSITIVE_INTEGERS; if (info.containsKey("sample-rate-ranges")) { Loading @@ -1844,7 +1887,8 @@ public final class MediaCodecInfo { limitSampleRates(rateRanges); } if (info.containsKey("max-channel-count")) { maxInputChannels = info.getInteger("max-channel-count"); maxInputChannels = Utils.parseIntSafely( info.getString("max-channel-count"), maxInputChannels); } if (info.containsKey("bitrate-range")) { bitRates = bitRates.intersect( Loading @@ -1853,6 +1897,21 @@ public final class MediaCodecInfo { applyLimits(maxInputChannels, bitRates); } /** @hide */ public void setDefaultFormat(MediaFormat format) { // report settings that have only a single choice if (mBitrateRange.getLower().equals(mBitrateRange.getUpper())) { format.setInteger(MediaFormat.KEY_BIT_RATE, mBitrateRange.getLower()); } if (mMaxInputChannelCount == 1) { // mono-only format format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); } if (mSampleRates != null && mSampleRates.length == 1) { format.setInteger(MediaFormat.KEY_SAMPLE_RATE, mSampleRates[0]); } } /** @hide */ public boolean supportsFormat(MediaFormat format) { Map<String, Object> map = format.getMap(); Loading
media/java/android/media/Utils.java +13 −0 Original line number Diff line number Diff line Loading @@ -210,6 +210,19 @@ class Utils { return fallback; } static int parseIntSafely(Object o, int fallback) { try { String s = (String)o; return Integer.parseInt(s); } catch (ClassCastException e) { } catch (NumberFormatException e) { } catch (NullPointerException e) { return fallback; } Log.w(TAG, "could not parse integer '" + o + "'"); return fallback; } static Range<Integer> parseIntRange(Object o, Range<Integer> fallback) { try { String s = (String)o; Loading