Loading media/java/android/media/MediaCodecInfo.java +128 −25 Original line number Diff line number Diff line Loading @@ -651,6 +651,27 @@ public final class MediaCodecInfo { continue; } } // MPEG4 levels are not completely ordered: // Level1 support only implies Level0 (and not Level0b) support if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1 && level > CodecProfileLevel.MPEG4Level0) { continue; } } // HEVC levels incorporate both tiers and levels. Verify tier support. if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { boolean supportsHighTier = (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0; boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0; // high tier levels are only supported by other high tier levels if (checkingHighTier && !supportsHighTier) { continue; } } if (pl.level >= level) { // if we recognize the listed profile/level, we must also recognize the // profile/level arguments. Loading Loading @@ -1132,6 +1153,8 @@ public final class MediaCodecInfo { private int mHeightAlignment; private int mSmallerDimensionUpperLimit; private boolean mAllowMbOverride; // allow XML to override calculated limits /** * Returns the range of supported bitrates in bits/second. */ Loading Loading @@ -1696,7 +1719,7 @@ public final class MediaCodecInfo { Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(), alignment.getWidth(), alignment.getHeight()); if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) { // codec supports profiles that we don't know. // Use supplied values clipped to platform limits if (widths != null) { Loading Loading @@ -1728,7 +1751,12 @@ public final class MediaCodecInfo { mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); } if (bitRates != null) { // only allow bitrate override if unsupported profiles were encountered if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { mBitrateRange = BITRATE_RANGE.intersect(bitRates); } else { mBitrateRange = mBitrateRange.intersect(bitRates); } } } else { // no unsupported profile/levels, so restrict values to known limits Loading Loading @@ -1883,6 +1911,19 @@ public final class MediaCodecInfo { int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment) { applyMacroBlockLimits( 1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */, maxHorizontalBlocks, maxVerticalBlocks, maxBlocks, maxBlocksPerSecond, blockWidth, blockHeight, widthAlignment, heightAlignment); } private void applyMacroBlockLimits( int minHorizontalBlocks, int minVerticalBlocks, int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment) { applyAlignment(widthAlignment, heightAlignment); applyBlockLimits( blockWidth, blockHeight, Range.create(1, maxBlocks), Loading @@ -1892,10 +1933,12 @@ public final class MediaCodecInfo { new Rational(maxHorizontalBlocks, 1))); mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1, maxHorizontalBlocks / (mBlockWidth / blockWidth)); Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)), maxHorizontalBlocks / (mBlockWidth / blockWidth)); mVerticalBlockRange = mVerticalBlockRange.intersect( 1, maxVerticalBlocks / (mBlockHeight / blockHeight)); Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)), maxVerticalBlocks / (mBlockHeight / blockHeight)); } private void applyLevelLimits() { Loading Loading @@ -2005,7 +2048,7 @@ public final class MediaCodecInfo { case CodecProfileLevel.MPEG2ProfileSimple: switch (profileLevel.level) { case CodecProfileLevel.MPEG2LevelML: FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 15000; break; FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; default: Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile + "/" Loading @@ -2018,7 +2061,7 @@ public final class MediaCodecInfo { case CodecProfileLevel.MPEG2LevelLL: FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break; case CodecProfileLevel.MPEG2LevelML: FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 15000; break; FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; case CodecProfileLevel.MPEG2LevelH14: FR = 60; W = 90; H = 68; MBPS = 183600; FS = 6120; BR = 60000; break; case CodecProfileLevel.MPEG2LevelHL: Loading Loading @@ -2068,16 +2111,19 @@ public final class MediaCodecInfo { maxBps = 64000; for (CodecProfileLevel profileLevel: profileLevels) { int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; boolean strict = false; // true: W, H and FR are individual max limits boolean supported = true; switch (profileLevel.profile) { case CodecProfileLevel.MPEG4ProfileSimple: switch (profileLevel.level) { case CodecProfileLevel.MPEG4Level0: strict = true; FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; case CodecProfileLevel.MPEG4Level1: FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; case CodecProfileLevel.MPEG4Level0b: FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; strict = true; FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; case CodecProfileLevel.MPEG4Level2: FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break; case CodecProfileLevel.MPEG4Level3: Loading Loading @@ -2125,11 +2171,16 @@ public final class MediaCodecInfo { case CodecProfileLevel.MPEG4ProfileCore: // 1-2 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2 // Studio profiles are not supported by our codecs. // Only profiles that can decode simple object types are considered. // The following profiles are not able to. case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2 Log.i(TAG, "Unsupported profile " + profileLevel.profile + " for " + mime); Loading @@ -2147,9 +2198,17 @@ public final class MediaCodecInfo { maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); maxBlocks = Math.max(FS, maxBlocks); maxBps = Math.max(BR * 1000, maxBps); if (strict) { maxWidth = Math.max(W, maxWidth); maxHeight = Math.max(H, maxHeight); maxRate = Math.max(FR, maxRate); } else { // assuming max 60 fps frame rate and 1:2 aspect ratio int maxDim = (int)Math.sqrt(FS * 2); maxWidth = Math.max(maxDim, maxWidth); maxHeight = Math.max(maxDim, maxHeight); maxRate = Math.max(Math.max(FR, 60), maxRate); } } applyMacroBlockLimits(maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, Loading @@ -2158,34 +2217,47 @@ public final class MediaCodecInfo { mFrameRateRange = mFrameRateRange.intersect(12, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { int maxWidth = 11, maxHeight = 9, maxRate = 15; int minWidth = maxWidth, minHeight = maxHeight; int minAlignment = 16; maxBlocks = 99; maxBlocksPerSecond = 1485; maxBps = 64000; for (CodecProfileLevel profileLevel: profileLevels) { int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0; int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight; boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF) switch (profileLevel.level) { case CodecProfileLevel.H263Level10: strict = true; // only supports sQCIF & QCIF FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level20: // only supports CIF, 0..QCIF FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * FR; break; strict = true; // only supports sQCIF, QCIF & CIF FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * 15; break; case CodecProfileLevel.H263Level30: // only supports CIF, 0..QCIF strict = true; // only supports sQCIF, QCIF & CIF FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level40: // only supports CIF, 0..QCIF strict = true; // only supports sQCIF, QCIF & CIF FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level45: // only implies level 10 support FR = 30; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline || profileLevel.profile == CodecProfileLevel.H263ProfileBackwardCompatible; if (!strict) { minW = 1; minH = 1; minAlignment = 4; } FR = 15; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level50: // only supports 50fps for H > 15 minW = 1; minH = 1; minAlignment = 4; FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break; case CodecProfileLevel.H263Level60: // only supports 50fps for H > 15 minW = 1; minH = 1; minAlignment = 4; FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break; case CodecProfileLevel.H263Level70: // only supports 50fps for H > 30 minW = 1; minH = 1; minAlignment = 4; FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break; default: Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile Loading @@ -2208,6 +2280,18 @@ public final class MediaCodecInfo { + profileLevel.profile + " for " + mime); errors |= ERROR_UNRECOGNIZED; } if (strict) { // Strict levels define sub-QCIF min size and enumerated sizes. We cannot // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities // but we can express "only QCIF (& CIF)", so set minimume size at QCIF. // minW = 8; minH = 6; minW = 11; minH = 9; } else { // any support for non-strict levels (including unrecognized profiles or // levels) allow custom frame size support beyond supported limits // (other than bitrate) mAllowMbOverride = true; } errors &= ~ERROR_NONE_SUPPORTED; maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); maxBlocks = Math.max(W * H, maxBlocks); Loading @@ -2215,11 +2299,21 @@ public final class MediaCodecInfo { maxWidth = Math.max(W, maxWidth); maxHeight = Math.max(H, maxHeight); maxRate = Math.max(FR, maxRate); minWidth = Math.min(minW, minWidth); minHeight = Math.min(minH, minHeight); } applyMacroBlockLimits(maxWidth, maxHeight, // unless we encountered custom frame size support, limit size to QCIF and CIF // using aspect ratio. if (!mAllowMbOverride) { mBlockAspectRatioRange = Range.create(new Rational(11, 9), new Rational(11, 9)); } applyMacroBlockLimits( minWidth, minHeight, maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); minAlignment /* widthAlignment */, minAlignment /* heightAlignment */); mFrameRateRange = Range.create(1, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) { maxBlocks = Integer.MAX_VALUE; Loading Loading @@ -2307,6 +2401,8 @@ public final class MediaCodecInfo { case CodecProfileLevel.VP9Profile1: case CodecProfileLevel.VP9Profile2: case CodecProfileLevel.VP9Profile3: case CodecProfileLevel.VP9Profile2HDR: case CodecProfileLevel.VP9Profile3HDR: break; default: Log.w(TAG, "Unrecognized profile " Loading @@ -2331,7 +2427,8 @@ public final class MediaCodecInfo { blockSize, blockSize, 1 /* widthAlignment */, 1 /* heightAlignment */); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { maxBlocks = 36864; // CTBs are at least 8x8 so use 8x8 block size maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks maxBlocksPerSecond = maxBlocks * 15; maxBps = 128000; for (CodecProfileLevel profileLevel: profileLevels) { Loading @@ -2339,6 +2436,10 @@ public final class MediaCodecInfo { int FS = 0; int BR = 0; switch (profileLevel.level) { /* The HEVC spec talks only in a very convoluted manner about the existence of levels 1-3.1 for High tier, which could also be understood as 'decoders and encoders should treat these levels as if they were Main tier', so we do that. */ case CodecProfileLevel.HEVCMainTierLevel1: case CodecProfileLevel.HEVCHighTierLevel1: FR = 15; FS = 36864; BR = 128; break; Loading Loading @@ -2409,6 +2510,7 @@ public final class MediaCodecInfo { else DPB = 6; */ FS >>= 6; // convert pixels to blocks errors &= ~ERROR_NONE_SUPPORTED; maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond); maxBlocks = Math.max(FS, maxBlocks); Loading @@ -2416,11 +2518,6 @@ public final class MediaCodecInfo { } int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); // CTBs are at least 8x8 maxBlocks = Utils.divUp(maxBlocks, 8 * 8); maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, 8 * 8); maxLengthInBlocks = Utils.divUp(maxLengthInBlocks, 8); applyMacroBlockLimits( maxLengthInBlocks, maxLengthInBlocks, maxBlocks, maxBlocksPerSecond, Loading Loading @@ -2834,6 +2931,12 @@ public final class MediaCodecInfo { public static final int HEVCMainTierLevel62 = 0x1000000; public static final int HEVCHighTierLevel62 = 0x2000000; private static final int HEVCHighTierLevels = HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 | HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 | HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | HEVCHighTierLevel62; // from OMX_VIDEO_DOLBYVISIONPROFILETYPE public static final int DolbyVisionProfileDvavPer = 0x1; public static final int DolbyVisionProfileDvavPen = 0x2; Loading Loading
media/java/android/media/MediaCodecInfo.java +128 −25 Original line number Diff line number Diff line Loading @@ -651,6 +651,27 @@ public final class MediaCodecInfo { continue; } } // MPEG4 levels are not completely ordered: // Level1 support only implies Level0 (and not Level0b) support if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_MPEG4)) { if (pl.level != level && pl.level == CodecProfileLevel.MPEG4Level1 && level > CodecProfileLevel.MPEG4Level0) { continue; } } // HEVC levels incorporate both tiers and levels. Verify tier support. if (mMime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { boolean supportsHighTier = (pl.level & CodecProfileLevel.HEVCHighTierLevels) != 0; boolean checkingHighTier = (level & CodecProfileLevel.HEVCHighTierLevels) != 0; // high tier levels are only supported by other high tier levels if (checkingHighTier && !supportsHighTier) { continue; } } if (pl.level >= level) { // if we recognize the listed profile/level, we must also recognize the // profile/level arguments. Loading Loading @@ -1132,6 +1153,8 @@ public final class MediaCodecInfo { private int mHeightAlignment; private int mSmallerDimensionUpperLimit; private boolean mAllowMbOverride; // allow XML to override calculated limits /** * Returns the range of supported bitrates in bits/second. */ Loading Loading @@ -1696,7 +1719,7 @@ public final class MediaCodecInfo { Long.MAX_VALUE, blockSize.getWidth(), blockSize.getHeight(), alignment.getWidth(), alignment.getHeight()); if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { if ((mParent.mError & ERROR_UNSUPPORTED) != 0 || mAllowMbOverride) { // codec supports profiles that we don't know. // Use supplied values clipped to platform limits if (widths != null) { Loading Loading @@ -1728,7 +1751,12 @@ public final class MediaCodecInfo { mFrameRateRange = FRAME_RATE_RANGE.intersect(frameRates); } if (bitRates != null) { // only allow bitrate override if unsupported profiles were encountered if ((mParent.mError & ERROR_UNSUPPORTED) != 0) { mBitrateRange = BITRATE_RANGE.intersect(bitRates); } else { mBitrateRange = mBitrateRange.intersect(bitRates); } } } else { // no unsupported profile/levels, so restrict values to known limits Loading Loading @@ -1883,6 +1911,19 @@ public final class MediaCodecInfo { int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment) { applyMacroBlockLimits( 1 /* minHorizontalBlocks */, 1 /* minVerticalBlocks */, maxHorizontalBlocks, maxVerticalBlocks, maxBlocks, maxBlocksPerSecond, blockWidth, blockHeight, widthAlignment, heightAlignment); } private void applyMacroBlockLimits( int minHorizontalBlocks, int minVerticalBlocks, int maxHorizontalBlocks, int maxVerticalBlocks, int maxBlocks, long maxBlocksPerSecond, int blockWidth, int blockHeight, int widthAlignment, int heightAlignment) { applyAlignment(widthAlignment, heightAlignment); applyBlockLimits( blockWidth, blockHeight, Range.create(1, maxBlocks), Loading @@ -1892,10 +1933,12 @@ public final class MediaCodecInfo { new Rational(maxHorizontalBlocks, 1))); mHorizontalBlockRange = mHorizontalBlockRange.intersect( 1, maxHorizontalBlocks / (mBlockWidth / blockWidth)); Utils.divUp(minHorizontalBlocks, (mBlockWidth / blockWidth)), maxHorizontalBlocks / (mBlockWidth / blockWidth)); mVerticalBlockRange = mVerticalBlockRange.intersect( 1, maxVerticalBlocks / (mBlockHeight / blockHeight)); Utils.divUp(minVerticalBlocks, (mBlockHeight / blockHeight)), maxVerticalBlocks / (mBlockHeight / blockHeight)); } private void applyLevelLimits() { Loading Loading @@ -2005,7 +2048,7 @@ public final class MediaCodecInfo { case CodecProfileLevel.MPEG2ProfileSimple: switch (profileLevel.level) { case CodecProfileLevel.MPEG2LevelML: FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 15000; break; FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; default: Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile + "/" Loading @@ -2018,7 +2061,7 @@ public final class MediaCodecInfo { case CodecProfileLevel.MPEG2LevelLL: FR = 30; W = 22; H = 18; MBPS = 11880; FS = 396; BR = 4000; break; case CodecProfileLevel.MPEG2LevelML: FR = 30; W = 45; H = 36; MBPS = 48600; FS = 1620; BR = 15000; break; FR = 30; W = 45; H = 36; MBPS = 40500; FS = 1620; BR = 15000; break; case CodecProfileLevel.MPEG2LevelH14: FR = 60; W = 90; H = 68; MBPS = 183600; FS = 6120; BR = 60000; break; case CodecProfileLevel.MPEG2LevelHL: Loading Loading @@ -2068,16 +2111,19 @@ public final class MediaCodecInfo { maxBps = 64000; for (CodecProfileLevel profileLevel: profileLevels) { int MBPS = 0, FS = 0, BR = 0, FR = 0, W = 0, H = 0; boolean strict = false; // true: W, H and FR are individual max limits boolean supported = true; switch (profileLevel.profile) { case CodecProfileLevel.MPEG4ProfileSimple: switch (profileLevel.level) { case CodecProfileLevel.MPEG4Level0: strict = true; FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; case CodecProfileLevel.MPEG4Level1: FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 64; break; case CodecProfileLevel.MPEG4Level0b: FR = 30; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; strict = true; FR = 15; W = 11; H = 9; MBPS = 1485; FS = 99; BR = 128; break; case CodecProfileLevel.MPEG4Level2: FR = 30; W = 22; H = 18; MBPS = 5940; FS = 396; BR = 128; break; case CodecProfileLevel.MPEG4Level3: Loading Loading @@ -2125,11 +2171,16 @@ public final class MediaCodecInfo { case CodecProfileLevel.MPEG4ProfileCore: // 1-2 case CodecProfileLevel.MPEG4ProfileAdvancedCore: // 1-4 case CodecProfileLevel.MPEG4ProfileSimpleScalable: // 0-2 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 case CodecProfileLevel.MPEG4ProfileHybrid: // 1-2 // Studio profiles are not supported by our codecs. // Only profiles that can decode simple object types are considered. // The following profiles are not able to. case CodecProfileLevel.MPEG4ProfileBasicAnimated: // 1-2 case CodecProfileLevel.MPEG4ProfileScalableTexture: // 1 case CodecProfileLevel.MPEG4ProfileSimpleFace: // 1-2 case CodecProfileLevel.MPEG4ProfileAdvancedScalable: // 1-3 case CodecProfileLevel.MPEG4ProfileSimpleFBA: // 1-2 Log.i(TAG, "Unsupported profile " + profileLevel.profile + " for " + mime); Loading @@ -2147,9 +2198,17 @@ public final class MediaCodecInfo { maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); maxBlocks = Math.max(FS, maxBlocks); maxBps = Math.max(BR * 1000, maxBps); if (strict) { maxWidth = Math.max(W, maxWidth); maxHeight = Math.max(H, maxHeight); maxRate = Math.max(FR, maxRate); } else { // assuming max 60 fps frame rate and 1:2 aspect ratio int maxDim = (int)Math.sqrt(FS * 2); maxWidth = Math.max(maxDim, maxWidth); maxHeight = Math.max(maxDim, maxHeight); maxRate = Math.max(Math.max(FR, 60), maxRate); } } applyMacroBlockLimits(maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, Loading @@ -2158,34 +2217,47 @@ public final class MediaCodecInfo { mFrameRateRange = mFrameRateRange.intersect(12, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)) { int maxWidth = 11, maxHeight = 9, maxRate = 15; int minWidth = maxWidth, minHeight = maxHeight; int minAlignment = 16; maxBlocks = 99; maxBlocksPerSecond = 1485; maxBps = 64000; for (CodecProfileLevel profileLevel: profileLevels) { int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0; int MBPS = 0, BR = 0, FR = 0, W = 0, H = 0, minW = minWidth, minH = minHeight; boolean strict = false; // true: support only sQCIF, QCIF (maybe CIF) switch (profileLevel.level) { case CodecProfileLevel.H263Level10: strict = true; // only supports sQCIF & QCIF FR = 15; W = 11; H = 9; BR = 1; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level20: // only supports CIF, 0..QCIF FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * FR; break; strict = true; // only supports sQCIF, QCIF & CIF FR = 30; W = 22; H = 18; BR = 2; MBPS = W * H * 15; break; case CodecProfileLevel.H263Level30: // only supports CIF, 0..QCIF strict = true; // only supports sQCIF, QCIF & CIF FR = 30; W = 22; H = 18; BR = 6; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level40: // only supports CIF, 0..QCIF strict = true; // only supports sQCIF, QCIF & CIF FR = 30; W = 22; H = 18; BR = 32; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level45: // only implies level 10 support FR = 30; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; strict = profileLevel.profile == CodecProfileLevel.H263ProfileBaseline || profileLevel.profile == CodecProfileLevel.H263ProfileBackwardCompatible; if (!strict) { minW = 1; minH = 1; minAlignment = 4; } FR = 15; W = 11; H = 9; BR = 2; MBPS = W * H * FR; break; case CodecProfileLevel.H263Level50: // only supports 50fps for H > 15 minW = 1; minH = 1; minAlignment = 4; FR = 60; W = 22; H = 18; BR = 64; MBPS = W * H * 50; break; case CodecProfileLevel.H263Level60: // only supports 50fps for H > 15 minW = 1; minH = 1; minAlignment = 4; FR = 60; W = 45; H = 18; BR = 128; MBPS = W * H * 50; break; case CodecProfileLevel.H263Level70: // only supports 50fps for H > 30 minW = 1; minH = 1; minAlignment = 4; FR = 60; W = 45; H = 36; BR = 256; MBPS = W * H * 50; break; default: Log.w(TAG, "Unrecognized profile/level " + profileLevel.profile Loading @@ -2208,6 +2280,18 @@ public final class MediaCodecInfo { + profileLevel.profile + " for " + mime); errors |= ERROR_UNRECOGNIZED; } if (strict) { // Strict levels define sub-QCIF min size and enumerated sizes. We cannot // express support for "only sQCIF & QCIF (& CIF)" using VideoCapabilities // but we can express "only QCIF (& CIF)", so set minimume size at QCIF. // minW = 8; minH = 6; minW = 11; minH = 9; } else { // any support for non-strict levels (including unrecognized profiles or // levels) allow custom frame size support beyond supported limits // (other than bitrate) mAllowMbOverride = true; } errors &= ~ERROR_NONE_SUPPORTED; maxBlocksPerSecond = Math.max(MBPS, maxBlocksPerSecond); maxBlocks = Math.max(W * H, maxBlocks); Loading @@ -2215,11 +2299,21 @@ public final class MediaCodecInfo { maxWidth = Math.max(W, maxWidth); maxHeight = Math.max(H, maxHeight); maxRate = Math.max(FR, maxRate); minWidth = Math.min(minW, minWidth); minHeight = Math.min(minH, minHeight); } applyMacroBlockLimits(maxWidth, maxHeight, // unless we encountered custom frame size support, limit size to QCIF and CIF // using aspect ratio. if (!mAllowMbOverride) { mBlockAspectRatioRange = Range.create(new Rational(11, 9), new Rational(11, 9)); } applyMacroBlockLimits( minWidth, minHeight, maxWidth, maxHeight, maxBlocks, maxBlocksPerSecond, 16 /* blockWidth */, 16 /* blockHeight */, 1 /* widthAlignment */, 1 /* heightAlignment */); minAlignment /* widthAlignment */, minAlignment /* heightAlignment */); mFrameRateRange = Range.create(1, maxRate); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_VP8)) { maxBlocks = Integer.MAX_VALUE; Loading Loading @@ -2307,6 +2401,8 @@ public final class MediaCodecInfo { case CodecProfileLevel.VP9Profile1: case CodecProfileLevel.VP9Profile2: case CodecProfileLevel.VP9Profile3: case CodecProfileLevel.VP9Profile2HDR: case CodecProfileLevel.VP9Profile3HDR: break; default: Log.w(TAG, "Unrecognized profile " Loading @@ -2331,7 +2427,8 @@ public final class MediaCodecInfo { blockSize, blockSize, 1 /* widthAlignment */, 1 /* heightAlignment */); } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_HEVC)) { maxBlocks = 36864; // CTBs are at least 8x8 so use 8x8 block size maxBlocks = 36864 >> 6; // 192x192 pixels == 576 8x8 blocks maxBlocksPerSecond = maxBlocks * 15; maxBps = 128000; for (CodecProfileLevel profileLevel: profileLevels) { Loading @@ -2339,6 +2436,10 @@ public final class MediaCodecInfo { int FS = 0; int BR = 0; switch (profileLevel.level) { /* The HEVC spec talks only in a very convoluted manner about the existence of levels 1-3.1 for High tier, which could also be understood as 'decoders and encoders should treat these levels as if they were Main tier', so we do that. */ case CodecProfileLevel.HEVCMainTierLevel1: case CodecProfileLevel.HEVCHighTierLevel1: FR = 15; FS = 36864; BR = 128; break; Loading Loading @@ -2409,6 +2510,7 @@ public final class MediaCodecInfo { else DPB = 6; */ FS >>= 6; // convert pixels to blocks errors &= ~ERROR_NONE_SUPPORTED; maxBlocksPerSecond = Math.max((int)(FR * FS), maxBlocksPerSecond); maxBlocks = Math.max(FS, maxBlocks); Loading @@ -2416,11 +2518,6 @@ public final class MediaCodecInfo { } int maxLengthInBlocks = (int)(Math.sqrt(maxBlocks * 8)); // CTBs are at least 8x8 maxBlocks = Utils.divUp(maxBlocks, 8 * 8); maxBlocksPerSecond = Utils.divUp(maxBlocksPerSecond, 8 * 8); maxLengthInBlocks = Utils.divUp(maxLengthInBlocks, 8); applyMacroBlockLimits( maxLengthInBlocks, maxLengthInBlocks, maxBlocks, maxBlocksPerSecond, Loading Loading @@ -2834,6 +2931,12 @@ public final class MediaCodecInfo { public static final int HEVCMainTierLevel62 = 0x1000000; public static final int HEVCHighTierLevel62 = 0x2000000; private static final int HEVCHighTierLevels = HEVCHighTierLevel1 | HEVCHighTierLevel2 | HEVCHighTierLevel21 | HEVCHighTierLevel3 | HEVCHighTierLevel31 | HEVCHighTierLevel4 | HEVCHighTierLevel41 | HEVCHighTierLevel5 | HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | HEVCHighTierLevel62; // from OMX_VIDEO_DOLBYVISIONPROFILETYPE public static final int DolbyVisionProfileDvavPer = 0x1; public static final int DolbyVisionProfileDvavPen = 0x2; Loading