Check CodecProfileLevels for audio decoders
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=208796064
This commit is contained in:
parent
e7ef75342c
commit
80f5b7e7b2
@ -287,13 +287,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
||||
}
|
||||
// Check capabilities for the first decoder in the list, which takes priority.
|
||||
MediaCodecInfo decoderInfo = decoderInfos.get(0);
|
||||
// Note: We assume support for unknown sampleRate and channelCount.
|
||||
boolean decoderCapable = Util.SDK_INT < 21
|
||||
|| ((format.sampleRate == Format.NO_VALUE
|
||||
|| decoderInfo.isAudioSampleRateSupportedV21(format.sampleRate))
|
||||
&& (format.channelCount == Format.NO_VALUE
|
||||
|| decoderInfo.isAudioChannelCountSupportedV21(format.channelCount)));
|
||||
int formatSupport = decoderCapable ? FORMAT_HANDLED : FORMAT_EXCEEDS_CAPABILITIES;
|
||||
boolean isFormatSupported = decoderInfo.isFormatSupported(format);
|
||||
int formatSupport = isFormatSupported ? FORMAT_HANDLED : FORMAT_EXCEEDS_CAPABILITIES;
|
||||
return ADAPTIVE_NOT_SEAMLESS | tunnelingSupport | formatSupport;
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,8 @@ public final class MediaCodecInfo {
|
||||
/** Whether this instance describes a passthrough codec. */
|
||||
public final boolean passthrough;
|
||||
|
||||
private final boolean isVideo;
|
||||
|
||||
/**
|
||||
* Creates an instance representing an audio passthrough decoder.
|
||||
*
|
||||
@ -157,6 +159,7 @@ public final class MediaCodecInfo {
|
||||
adaptive = !forceDisableAdaptive && capabilities != null && isAdaptive(capabilities);
|
||||
tunneling = capabilities != null && isTunneling(capabilities);
|
||||
secure = forceSecure || (capabilities != null && isSecure(capabilities));
|
||||
isVideo = MimeTypes.isVideo(mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -187,6 +190,41 @@ public final class MediaCodecInfo {
|
||||
: getMaxSupportedInstancesV23(capabilities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the decoder may support decoding the given {@code format}.
|
||||
*
|
||||
* @param format The input media format.
|
||||
* @return Whether the decoder may support decoding the given {@code format}.
|
||||
* @throws MediaCodecUtil.DecoderQueryException Thrown if an error occurs while querying decoders.
|
||||
*/
|
||||
public boolean isFormatSupported(Format format) throws MediaCodecUtil.DecoderQueryException {
|
||||
if (!isCodecSupported(format.codecs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isVideo) {
|
||||
if (format.width <= 0 || format.height <= 0) {
|
||||
return true;
|
||||
}
|
||||
if (Util.SDK_INT >= 21) {
|
||||
return isVideoSizeAndRateSupportedV21(format.width, format.height, format.frameRate);
|
||||
} else {
|
||||
boolean isFormatSupported =
|
||||
format.width * format.height <= MediaCodecUtil.maxH264DecodableFrameSize();
|
||||
if (!isFormatSupported) {
|
||||
logNoSupport("legacyFrameSize, " + format.width + "x" + format.height);
|
||||
}
|
||||
return isFormatSupported;
|
||||
}
|
||||
} else { // Audio
|
||||
return Util.SDK_INT < 21
|
||||
|| ((format.sampleRate == Format.NO_VALUE
|
||||
|| isAudioSampleRateSupportedV21(format.sampleRate))
|
||||
&& (format.channelCount == Format.NO_VALUE
|
||||
|| isAudioChannelCountSupportedV21(format.channelCount)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the decoder supports the given {@code codec}. If there is insufficient information to
|
||||
* decide, returns true.
|
||||
|
@ -74,6 +74,9 @@ public final class MediaCodecUtil {
|
||||
private static final Map<String, Integer> HEVC_CODEC_STRING_TO_PROFILE_LEVEL;
|
||||
private static final String CODEC_ID_HEV1 = "hev1";
|
||||
private static final String CODEC_ID_HVC1 = "hvc1";
|
||||
// MP4A AAC.
|
||||
private static final SparseIntArray MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE;
|
||||
private static final String CODEC_ID_MP4A = "mp4a";
|
||||
|
||||
// Lazily initialized.
|
||||
private static int maxH264DecodableFrameSize = -1;
|
||||
@ -199,7 +202,7 @@ public final class MediaCodecUtil {
|
||||
* @return A pair (profile constant, level constant) if {@code codec} is well-formed and
|
||||
* recognized, or null otherwise
|
||||
*/
|
||||
public static Pair<Integer, Integer> getCodecProfileAndLevel(String codec) {
|
||||
public static @Nullable Pair<Integer, Integer> getCodecProfileAndLevel(String codec) {
|
||||
if (codec == null) {
|
||||
return null;
|
||||
}
|
||||
@ -211,6 +214,8 @@ public final class MediaCodecUtil {
|
||||
case CODEC_ID_AVC1:
|
||||
case CODEC_ID_AVC2:
|
||||
return getAvcProfileAndLevel(codec, parts);
|
||||
case CODEC_ID_MP4A:
|
||||
return getAacCodecProfileAndLevel(codec, parts);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -445,8 +450,8 @@ public final class MediaCodecUtil {
|
||||
return new Pair<>(profile, level);
|
||||
}
|
||||
|
||||
private static Pair<Integer, Integer> getAvcProfileAndLevel(String codec, String[] codecsParts) {
|
||||
if (codecsParts.length < 2) {
|
||||
private static Pair<Integer, Integer> getAvcProfileAndLevel(String codec, String[] parts) {
|
||||
if (parts.length < 2) {
|
||||
// The codec has fewer parts than required by the AVC codec string format.
|
||||
Log.w(TAG, "Ignoring malformed AVC codec string: " + codec);
|
||||
return null;
|
||||
@ -454,14 +459,14 @@ public final class MediaCodecUtil {
|
||||
Integer profileInteger;
|
||||
Integer levelInteger;
|
||||
try {
|
||||
if (codecsParts[1].length() == 6) {
|
||||
if (parts[1].length() == 6) {
|
||||
// Format: avc1.xxccyy, where xx is profile and yy level, both hexadecimal.
|
||||
profileInteger = Integer.parseInt(codecsParts[1].substring(0, 2), 16);
|
||||
levelInteger = Integer.parseInt(codecsParts[1].substring(4), 16);
|
||||
} else if (codecsParts.length >= 3) {
|
||||
profileInteger = Integer.parseInt(parts[1].substring(0, 2), 16);
|
||||
levelInteger = Integer.parseInt(parts[1].substring(4), 16);
|
||||
} else if (parts.length >= 3) {
|
||||
// Format: avc1.xx.[y]yy where xx is profile and [y]yy level, both decimal.
|
||||
profileInteger = Integer.parseInt(codecsParts[1]);
|
||||
levelInteger = Integer.parseInt(codecsParts[2]);
|
||||
profileInteger = Integer.parseInt(parts[1]);
|
||||
levelInteger = Integer.parseInt(parts[2]);
|
||||
} else {
|
||||
// We don't recognize the format.
|
||||
Log.w(TAG, "Ignoring malformed AVC codec string: " + codec);
|
||||
@ -514,6 +519,31 @@ public final class MediaCodecUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Pair<Integer, Integer> getAacCodecProfileAndLevel(
|
||||
String codec, String[] parts) {
|
||||
if (parts.length != 3) {
|
||||
Log.w(TAG, "Ignoring malformed MP4A codec string: " + codec);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// Get the object type indication, which is a hexadecimal value (see RFC 6381/ISO 14496-1).
|
||||
int objectTypeIndication = Integer.parseInt(parts[1], 16);
|
||||
String mimeType = MimeTypes.getMimeTypeFromMp4ObjectType(objectTypeIndication);
|
||||
if (MimeTypes.AUDIO_AAC.equals(mimeType)) {
|
||||
// For MPEG-4 audio this is followed by an audio object type indication as a decimal number.
|
||||
int audioObjectTypeIndication = Integer.parseInt(parts[2]);
|
||||
int profile = MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.get(audioObjectTypeIndication, -1);
|
||||
if (profile != -1) {
|
||||
// Level is set to zero in AAC decoder CodecProfileLevels.
|
||||
return new Pair<>(profile, 0);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, "Ignoring malformed MP4A codec string: " + codec);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private interface MediaCodecListCompat {
|
||||
|
||||
/**
|
||||
@ -725,6 +755,20 @@ public final class MediaCodecUtil {
|
||||
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("H180", CodecProfileLevel.HEVCHighTierLevel6);
|
||||
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("H183", CodecProfileLevel.HEVCHighTierLevel61);
|
||||
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("H186", CodecProfileLevel.HEVCHighTierLevel62);
|
||||
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE = new SparseIntArray();
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(1, CodecProfileLevel.AACObjectMain);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(2, CodecProfileLevel.AACObjectLC);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(3, CodecProfileLevel.AACObjectSSR);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(4, CodecProfileLevel.AACObjectLTP);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(5, CodecProfileLevel.AACObjectHE);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(6, CodecProfileLevel.AACObjectScalable);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(17, CodecProfileLevel.AACObjectERLC);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(20, CodecProfileLevel.AACObjectERScalable);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(23, CodecProfileLevel.AACObjectLD);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(29, CodecProfileLevel.AACObjectHE_PS);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(39, CodecProfileLevel.AACObjectELD);
|
||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(42, CodecProfileLevel.AACObjectXHE);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -265,23 +265,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
||||
}
|
||||
// Check capabilities for the first decoder in the list, which takes priority.
|
||||
MediaCodecInfo decoderInfo = decoderInfos.get(0);
|
||||
boolean decoderCapable = decoderInfo.isCodecSupported(format.codecs);
|
||||
if (decoderCapable && format.width > 0 && format.height > 0) {
|
||||
if (Util.SDK_INT >= 21) {
|
||||
decoderCapable = decoderInfo.isVideoSizeAndRateSupportedV21(format.width, format.height,
|
||||
format.frameRate);
|
||||
} else {
|
||||
decoderCapable = format.width * format.height <= MediaCodecUtil.maxH264DecodableFrameSize();
|
||||
if (!decoderCapable) {
|
||||
Log.d(TAG, "FalseCheck [legacyFrameSize, " + format.width + "x" + format.height + "] ["
|
||||
+ Util.DEVICE_DEBUG_INFO + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isFormatSupported = decoderInfo.isFormatSupported(format);
|
||||
int adaptiveSupport = decoderInfo.adaptive ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS;
|
||||
int tunnelingSupport = decoderInfo.tunneling ? TUNNELING_SUPPORTED : TUNNELING_NOT_SUPPORTED;
|
||||
int formatSupport = decoderCapable ? FORMAT_HANDLED : FORMAT_EXCEEDS_CAPABILITIES;
|
||||
int formatSupport = isFormatSupported ? FORMAT_HANDLED : FORMAT_EXCEEDS_CAPABILITIES;
|
||||
return adaptiveSupport | tunnelingSupport | formatSupport;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user