mirror of
https://github.com/samsonjs/media.git
synced 2026-04-19 13:35:47 +00:00
Improve profile/level check support for AVC
Issue:#1772 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=132078273
This commit is contained in:
parent
da0bc33251
commit
32867217a3
3 changed files with 63 additions and 50 deletions
|
|
@ -113,9 +113,6 @@ public final class MediaCodecInfo {
|
|||
if (!mimeType.equals(codecMimeType)) {
|
||||
return false;
|
||||
}
|
||||
if (!codecMimeType.equals(MimeTypes.VIDEO_H265)) {
|
||||
return true;
|
||||
}
|
||||
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(codec);
|
||||
if (codecProfileAndLevel == null) {
|
||||
// If we don't know any better, we assume that the profile and level are supported.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
|
@ -58,16 +57,21 @@ public final class MediaCodecUtil {
|
|||
private static final String TAG = "MediaCodecUtil";
|
||||
private static final MediaCodecInfo PASSTHROUGH_DECODER_INFO =
|
||||
MediaCodecInfo.newPassthroughInstance("OMX.google.raw.decoder");
|
||||
private static final Map<String, Integer> HEVC_CODEC_STRING_TO_PROFILE_LEVEL;
|
||||
private static final Map<String, Integer> AVC_CODEC_STRING_TO_PROFILE_LEVEL;
|
||||
private static final String CODEC_ID_HEV1 = "hev1";
|
||||
private static final String CODEC_ID_HVC1 = "hvc1";
|
||||
private static final String CODEC_ID_AVC1 = "avc1";
|
||||
private static final String CODEC_ID_AVC2 = "avc2";
|
||||
private static final Pattern PROFILE_PATTERN = Pattern.compile("^\\D?(\\d+)$");
|
||||
|
||||
private static final HashMap<CodecKey, List<MediaCodecInfo>> decoderInfosCache = new HashMap<>();
|
||||
|
||||
// Codecs to constant mappings.
|
||||
// AVC.
|
||||
private static final Map<Integer, Integer> AVC_PROFILE_NUMBER_TO_CONST;
|
||||
private static final Map<Integer, Integer> AVC_LEVEL_NUMBER_TO_CONST;
|
||||
private static final String CODEC_ID_AVC1 = "avc1";
|
||||
private static final String CODEC_ID_AVC2 = "avc2";
|
||||
// HEVC.
|
||||
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";
|
||||
|
||||
// Lazily initialized.
|
||||
private static int maxH264DecodableFrameSize = -1;
|
||||
|
||||
|
|
@ -305,7 +309,7 @@ public final class MediaCodecUtil {
|
|||
*
|
||||
* @param codec A codec description string, as defined by RFC 6381.
|
||||
* @return A pair (profile constant, level constant) if {@code codec} is well-formed and
|
||||
* supported, null otherwise.
|
||||
* recognized, or null otherwise
|
||||
*/
|
||||
public static Pair<Integer, Integer> getCodecProfileAndLevel(String codec) {
|
||||
if (codec == null) {
|
||||
|
|
@ -360,25 +364,35 @@ public final class MediaCodecUtil {
|
|||
Log.w(TAG, "Ignoring malformed AVC codec string: " + codec);
|
||||
return null;
|
||||
}
|
||||
int profile;
|
||||
String profileString = codecsParts[1].substring(0, 2).toUpperCase(Locale.US);
|
||||
if ("42".equals(profileString)) {
|
||||
profile = CodecProfileLevel.AVCProfileBaseline;
|
||||
} else if ("4D".equals(profileString)) {
|
||||
profile = CodecProfileLevel.AVCProfileMain;
|
||||
} else if ("58".equals(profileString)) {
|
||||
profile = CodecProfileLevel.AVCProfileExtended;
|
||||
} else if ("64".equals(profileString)) {
|
||||
profile = CodecProfileLevel.AVCProfileHigh;
|
||||
} else {
|
||||
Log.w(TAG, "Unknown AVC profile string: " + profileString);
|
||||
Integer profileInteger = null;
|
||||
Integer levelInteger = null;
|
||||
try {
|
||||
if (codecsParts[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) {
|
||||
// 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]);
|
||||
} else {
|
||||
// We don't recognize the format.
|
||||
Log.w(TAG, "Ignoring malformed AVC codec string: " + codec);
|
||||
return null;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, "Ignoring malformed AVC codec string: " + codec);
|
||||
return null;
|
||||
}
|
||||
|
||||
String levelString = codecsParts[1].substring(4).toUpperCase(Locale.US);
|
||||
Integer level = AVC_CODEC_STRING_TO_PROFILE_LEVEL.get(levelString);
|
||||
Integer profile = AVC_PROFILE_NUMBER_TO_CONST.get(profileInteger);
|
||||
if (profile == null) {
|
||||
Log.w(TAG, "Unknown AVC profile: " + profileInteger);
|
||||
return null;
|
||||
}
|
||||
Integer level = AVC_LEVEL_NUMBER_TO_CONST.get(levelInteger);
|
||||
if (level == null) {
|
||||
Log.w(TAG, "Unknown AVC level string: " + levelString);
|
||||
Log.w(TAG, "Unknown AVC level: " + levelInteger);
|
||||
return null;
|
||||
}
|
||||
return new Pair<>(profile, level);
|
||||
|
|
@ -541,24 +555,30 @@ public final class MediaCodecUtil {
|
|||
}
|
||||
|
||||
static {
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL = new HashMap<>();
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("01", CodecProfileLevel.AVCLevel1);
|
||||
// TODO: Find string for CodecProfileLevel.AVCLevel1b.
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("0B", CodecProfileLevel.AVCLevel11);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("0C", CodecProfileLevel.AVCLevel12);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("0D", CodecProfileLevel.AVCLevel13);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("14", CodecProfileLevel.AVCLevel2);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("15", CodecProfileLevel.AVCLevel21);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("16", CodecProfileLevel.AVCLevel22);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("1E", CodecProfileLevel.AVCLevel3);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("1F", CodecProfileLevel.AVCLevel31);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("20", CodecProfileLevel.AVCLevel32);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("32", CodecProfileLevel.AVCLevel4);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("33", CodecProfileLevel.AVCLevel41);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("34", CodecProfileLevel.AVCLevel42);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("3C", CodecProfileLevel.AVCLevel5);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("3D", CodecProfileLevel.AVCLevel51);
|
||||
AVC_CODEC_STRING_TO_PROFILE_LEVEL.put("3E", CodecProfileLevel.AVCLevel52);
|
||||
AVC_PROFILE_NUMBER_TO_CONST = new HashMap<>();
|
||||
AVC_PROFILE_NUMBER_TO_CONST.put(66, CodecProfileLevel.AVCProfileBaseline);
|
||||
AVC_PROFILE_NUMBER_TO_CONST.put(77, CodecProfileLevel.AVCProfileMain);
|
||||
AVC_PROFILE_NUMBER_TO_CONST.put(88, CodecProfileLevel.AVCProfileExtended);
|
||||
AVC_PROFILE_NUMBER_TO_CONST.put(100, CodecProfileLevel.AVCProfileHigh);
|
||||
|
||||
AVC_LEVEL_NUMBER_TO_CONST = new HashMap<>();
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(10, CodecProfileLevel.AVCLevel1);
|
||||
// TODO: Find int for CodecProfileLevel.AVCLevel1b.
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(11, CodecProfileLevel.AVCLevel11);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(12, CodecProfileLevel.AVCLevel12);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(13, CodecProfileLevel.AVCLevel13);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(20, CodecProfileLevel.AVCLevel2);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(21, CodecProfileLevel.AVCLevel21);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(22, CodecProfileLevel.AVCLevel22);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(30, CodecProfileLevel.AVCLevel3);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(31, CodecProfileLevel.AVCLevel31);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(32, CodecProfileLevel.AVCLevel32);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(40, CodecProfileLevel.AVCLevel4);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(41, CodecProfileLevel.AVCLevel41);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(42, CodecProfileLevel.AVCLevel42);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(50, CodecProfileLevel.AVCLevel5);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(51, CodecProfileLevel.AVCLevel51);
|
||||
AVC_LEVEL_NUMBER_TO_CONST.put(52, CodecProfileLevel.AVCLevel52);
|
||||
|
||||
HEVC_CODEC_STRING_TO_PROFILE_LEVEL = new HashMap<>();
|
||||
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("L30", CodecProfileLevel.HEVCMainTierLevel1);
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||
return FORMAT_UNSUPPORTED_SUBTYPE;
|
||||
}
|
||||
|
||||
boolean decoderCapable;
|
||||
if (format.width > 0 && format.height > 0) {
|
||||
boolean decoderCapable = decoderInfo.isCodecSupported(format.codecs);
|
||||
if (decoderCapable && format.width > 0 && format.height > 0) {
|
||||
if (Util.SDK_INT >= 21) {
|
||||
if (format.frameRate > 0) {
|
||||
decoderCapable = decoderInfo.isVideoSizeAndRateSupportedV21(format.width, format.height,
|
||||
|
|
@ -196,13 +196,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||
} else {
|
||||
decoderCapable = decoderInfo.isVideoSizeSupportedV21(format.width, format.height);
|
||||
}
|
||||
decoderCapable &= decoderInfo.isCodecSupported(format.codecs);
|
||||
} else {
|
||||
decoderCapable = format.width * format.height <= MediaCodecUtil.maxH264DecodableFrameSize();
|
||||
}
|
||||
} else {
|
||||
// We don't know any better, so assume true.
|
||||
decoderCapable = true;
|
||||
}
|
||||
|
||||
int adaptiveSupport = decoderInfo.adaptive ? ADAPTIVE_SEAMLESS : ADAPTIVE_NOT_SEAMLESS;
|
||||
|
|
|
|||
Loading…
Reference in a new issue