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. */ /** The maximum number of bytes to peek when sniffing. */
private static final int SEARCH_LENGTH = 4 * 1024; private static final int SEARCH_LENGTH = 4 * 1024;
private static final int[] COMPATIBLE_BRANDS = new int[] { private static final int[] COMPATIBLE_BRANDS =
Util.getIntegerCodeForString("isom"), new int[] {
Util.getIntegerCodeForString("iso2"), Util.getIntegerCodeForString("isom"),
Util.getIntegerCodeForString("iso3"), Util.getIntegerCodeForString("iso2"),
Util.getIntegerCodeForString("iso4"), Util.getIntegerCodeForString("iso3"),
Util.getIntegerCodeForString("iso5"), Util.getIntegerCodeForString("iso4"),
Util.getIntegerCodeForString("iso6"), Util.getIntegerCodeForString("iso5"),
Util.getIntegerCodeForString("avc1"), Util.getIntegerCodeForString("iso6"),
Util.getIntegerCodeForString("hvc1"), Util.getIntegerCodeForString("avc1"),
Util.getIntegerCodeForString("hev1"), Util.getIntegerCodeForString("hvc1"),
Util.getIntegerCodeForString("mp41"), Util.getIntegerCodeForString("hev1"),
Util.getIntegerCodeForString("mp42"), Util.getIntegerCodeForString("mp41"),
Util.getIntegerCodeForString("3g2a"), Util.getIntegerCodeForString("mp42"),
Util.getIntegerCodeForString("3g2b"), Util.getIntegerCodeForString("3g2a"),
Util.getIntegerCodeForString("3gr6"), Util.getIntegerCodeForString("3g2b"),
Util.getIntegerCodeForString("3gs6"), Util.getIntegerCodeForString("3gr6"),
Util.getIntegerCodeForString("3ge6"), Util.getIntegerCodeForString("3gs6"),
Util.getIntegerCodeForString("3gg6"), Util.getIntegerCodeForString("3ge6"),
Util.getIntegerCodeForString("M4V "), Util.getIntegerCodeForString("3gg6"),
Util.getIntegerCodeForString("M4A "), Util.getIntegerCodeForString("M4V "),
Util.getIntegerCodeForString("f4v "), Util.getIntegerCodeForString("M4A "),
Util.getIntegerCodeForString("kddi"), Util.getIntegerCodeForString("f4v "),
Util.getIntegerCodeForString("M4VP"), Util.getIntegerCodeForString("kddi"),
Util.getIntegerCodeForString("qt "), // Apple QuickTime Util.getIntegerCodeForString("M4VP"),
Util.getIntegerCodeForString("MSNV"), // Sony PSP 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 * 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++) { for (int i = 0; i < numberOfCodecs; i++) {
android.media.MediaCodecInfo codecInfo = mediaCodecList.getCodecInfoAt(i); android.media.MediaCodecInfo codecInfo = mediaCodecList.getCodecInfoAt(i);
String codecName = codecInfo.getName(); String codecName = codecInfo.getName();
if (isCodecUsableDecoder(codecInfo, codecName, secureDecodersExplicit, requestedMimeType)) { String codecSupportedType =
for (String supportedType : codecInfo.getSupportedTypes()) { getCodecSupportedType(codecInfo, codecName, secureDecodersExplicit, requestedMimeType);
if (supportedType.equalsIgnoreCase(mimeType)) { if (codecSupportedType != null) {
try { try {
CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(supportedType); CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(codecSupportedType);
boolean secure = mediaCodecList.isSecurePlaybackSupported(mimeType, capabilities); boolean secure = mediaCodecList.isSecurePlaybackSupported(mimeType, capabilities);
boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(codecName); boolean forceDisableAdaptive = codecNeedsDisableAdaptationWorkaround(codecName);
if ((secureDecodersExplicit && key.secure == secure) if ((secureDecodersExplicit && key.secure == secure)
|| (!secureDecodersExplicit && !key.secure)) { || (!secureDecodersExplicit && !key.secure)) {
decoderInfos.add(MediaCodecInfo.newInstance(codecName, mimeType, capabilities, decoderInfos.add(
forceDisableAdaptive, false)); MediaCodecInfo.newInstance(
} else if (!secureDecodersExplicit && secure) { codecName, mimeType, capabilities, forceDisableAdaptive, false));
decoderInfos.add(MediaCodecInfo.newInstance(codecName + ".secure", mimeType, } else if (!secureDecodersExplicit && secure) {
capabilities, forceDisableAdaptive, true)); decoderInfos.add(
// It only makes sense to have one synthesized secure decoder, return immediately. MediaCodecInfo.newInstance(
return decoderInfos; codecName + ".secure", mimeType, capabilities, forceDisableAdaptive, true));
} // It only makes sense to have one synthesized secure decoder, return immediately.
} catch (Exception e) { return decoderInfos;
if (Util.SDK_INT <= 23 && !decoderInfos.isEmpty()) { }
// Suppress error querying secondary codec capabilities up to API level 23. } catch (Exception e) {
Log.e(TAG, "Skipping codec " + codecName + " (failed to query capabilities)"); if (Util.SDK_INT <= 23 && !decoderInfos.isEmpty()) {
} else { // Suppress error querying secondary codec capabilities up to API level 23.
// Rethrow error querying primary codec capabilities, or secondary codec Log.e(TAG, "Skipping codec " + codecName + " (failed to query capabilities)");
// capabilities if API level is greater than 23. } else {
Log.e(TAG, "Failed to query codec " + codecName + " (" + supportedType + ")"); // Rethrow error querying primary codec capabilities, or secondary codec
throw e; // 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. * Returns whether the specified codec is usable for decoding on the current device.
* *