Handle alternative DV MIME types

Also detect ISOBMFF brand for DV when sniffing.

PiperOrigin-RevId: 233433449
This commit is contained in:
andrewlewis 2019-02-11 18:29:18 +00:00 committed by Andrew Lewis
parent a21572f0dd
commit ad69a93708
2 changed files with 96 additions and 54 deletions

View File

@ -30,32 +30,34 @@ import java.io.IOException;
/** The maximum number of bytes to peek when sniffing. */
private static final int SEARCH_LENGTH = 4 * 1024;
private static final int[] COMPATIBLE_BRANDS = new int[] {
Util.getIntegerCodeForString("isom"),
Util.getIntegerCodeForString("iso2"),
Util.getIntegerCodeForString("iso3"),
Util.getIntegerCodeForString("iso4"),
Util.getIntegerCodeForString("iso5"),
Util.getIntegerCodeForString("iso6"),
Util.getIntegerCodeForString("avc1"),
Util.getIntegerCodeForString("hvc1"),
Util.getIntegerCodeForString("hev1"),
Util.getIntegerCodeForString("mp41"),
Util.getIntegerCodeForString("mp42"),
Util.getIntegerCodeForString("3g2a"),
Util.getIntegerCodeForString("3g2b"),
Util.getIntegerCodeForString("3gr6"),
Util.getIntegerCodeForString("3gs6"),
Util.getIntegerCodeForString("3ge6"),
Util.getIntegerCodeForString("3gg6"),
Util.getIntegerCodeForString("M4V "),
Util.getIntegerCodeForString("M4A "),
Util.getIntegerCodeForString("f4v "),
Util.getIntegerCodeForString("kddi"),
Util.getIntegerCodeForString("M4VP"),
Util.getIntegerCodeForString("qt "), // Apple QuickTime
Util.getIntegerCodeForString("MSNV"), // Sony PSP
};
private static final int[] COMPATIBLE_BRANDS =
new int[] {
Util.getIntegerCodeForString("isom"),
Util.getIntegerCodeForString("iso2"),
Util.getIntegerCodeForString("iso3"),
Util.getIntegerCodeForString("iso4"),
Util.getIntegerCodeForString("iso5"),
Util.getIntegerCodeForString("iso6"),
Util.getIntegerCodeForString("avc1"),
Util.getIntegerCodeForString("hvc1"),
Util.getIntegerCodeForString("hev1"),
Util.getIntegerCodeForString("mp41"),
Util.getIntegerCodeForString("mp42"),
Util.getIntegerCodeForString("3g2a"),
Util.getIntegerCodeForString("3g2b"),
Util.getIntegerCodeForString("3gr6"),
Util.getIntegerCodeForString("3gs6"),
Util.getIntegerCodeForString("3ge6"),
Util.getIntegerCodeForString("3gg6"),
Util.getIntegerCodeForString("M4V "),
Util.getIntegerCodeForString("M4A "),
Util.getIntegerCodeForString("f4v "),
Util.getIntegerCodeForString("kddi"),
Util.getIntegerCodeForString("M4VP"),
Util.getIntegerCodeForString("qt "), // Apple QuickTime
Util.getIntegerCodeForString("MSNV"), // Sony PSP
Util.getIntegerCodeForString("dby1"), // Dolby Vision
};
/**
* Returns whether data peeked from the current position in {@code input} is consistent with the

View File

@ -250,34 +250,34 @@ public final class MediaCodecUtil {
for (int i = 0; i < numberOfCodecs; i++) {
android.media.MediaCodecInfo codecInfo = mediaCodecList.getCodecInfoAt(i);
String codecName = codecInfo.getName();
if (isCodecUsableDecoder(codecInfo, codecName, secureDecodersExplicit, requestedMimeType)) {
for (String supportedType : codecInfo.getSupportedTypes()) {
if (supportedType.equalsIgnoreCase(mimeType)) {
try {
CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(supportedType);
boolean secure = mediaCodecList.isSecurePlaybackSupported(mimeType, capabilities);
boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(codecName);
if ((secureDecodersExplicit && key.secure == secure)
|| (!secureDecodersExplicit && !key.secure)) {
decoderInfos.add(MediaCodecInfo.newInstance(codecName, mimeType, capabilities,
forceDisableAdaptive, false));
} else if (!secureDecodersExplicit && secure) {
decoderInfos.add(MediaCodecInfo.newInstance(codecName + ".secure", mimeType,
capabilities, forceDisableAdaptive, true));
// It only makes sense to have one synthesized secure decoder, return immediately.
return decoderInfos;
}
} catch (Exception e) {
if (Util.SDK_INT <= 23 && !decoderInfos.isEmpty()) {
// Suppress error querying secondary codec capabilities up to API level 23.
Log.e(TAG, "Skipping codec " + codecName + " (failed to query capabilities)");
} else {
// Rethrow error querying primary codec capabilities, or secondary codec
// capabilities if API level is greater than 23.
Log.e(TAG, "Failed to query codec " + codecName + " (" + supportedType + ")");
throw e;
}
}
String codecSupportedType =
getCodecSupportedType(codecInfo, codecName, secureDecodersExplicit, requestedMimeType);
if (codecSupportedType != null) {
try {
CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(codecSupportedType);
boolean secure = mediaCodecList.isSecurePlaybackSupported(mimeType, capabilities);
boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(codecName);
if ((secureDecodersExplicit && key.secure == secure)
|| (!secureDecodersExplicit && !key.secure)) {
decoderInfos.add(
MediaCodecInfo.newInstance(
codecName, mimeType, capabilities, forceDisableAdaptive, false));
} else if (!secureDecodersExplicit && secure) {
decoderInfos.add(
MediaCodecInfo.newInstance(
codecName + ".secure", mimeType, capabilities, forceDisableAdaptive, true));
// It only makes sense to have one synthesized secure decoder, return immediately.
return decoderInfos;
}
} catch (Exception e) {
if (Util.SDK_INT <= 23 && !decoderInfos.isEmpty()) {
// Suppress error querying secondary codec capabilities up to API level 23.
Log.e(TAG, "Skipping codec " + codecName + " (failed to query capabilities)");
} else {
// Rethrow error querying primary codec capabilities, or secondary codec
// capabilities if API level is greater than 23.
Log.e(TAG, "Failed to query codec " + codecName + " (" + codecSupportedType + ")");
throw e;
}
}
}
@ -290,6 +290,46 @@ public final class MediaCodecUtil {
}
}
/**
* Returns the codec's supported type for decoding {@code requestedMimeType} on the current
* device, or {@code null} if the codec can't be used.
*
* @param info The codec information.
* @param name The name of the codec
* @param secureDecodersExplicit Whether secure decoders were explicitly listed, if present.
* @param requestedMimeType The originally requested MIME type, which may differ from the codec
* key MIME type if the codec key is being considered as a fallback.
* @return The codec's supported type for decoding {@code requestedMimeType}, or {@code null} if
* the codec can't be used.
*/
@Nullable
private static String getCodecSupportedType(
android.media.MediaCodecInfo info,
String name,
boolean secureDecodersExplicit,
String requestedMimeType) {
if (isCodecUsableDecoder(info, name, secureDecodersExplicit, requestedMimeType)) {
if (requestedMimeType.equals(MimeTypes.VIDEO_DOLBY_VISION)) {
// Handle decoders that declare support for DV via MIME types that aren't
// video/dolby-vision.
if ("OMX.MS.HEVCDV.Decoder".equals(name)) {
return "video/hevcdv";
} else if ("OMX.RTK.video.decoder".equals(name)
|| "OMX.realtek.video.decoder.tunneled".equals(name)) {
return "video/dv_hevc";
}
}
String[] supportedTypes = info.getSupportedTypes();
for (String supportedType : supportedTypes) {
if (supportedType.equalsIgnoreCase(requestedMimeType)) {
return supportedType;
}
}
}
return null;
}
/**
* Returns whether the specified codec is usable for decoding on the current device.
*