mirror of
https://github.com/samsonjs/media.git
synced 2026-04-01 10:35:48 +00:00
Check codec profile/level for AV1
Add appropriate unit tests. PiperOrigin-RevId: 258552404
This commit is contained in:
parent
5e4f52541d
commit
a3ded59f28
2 changed files with 99 additions and 3 deletions
|
|
@ -81,10 +81,13 @@ public final class MediaCodecUtil {
|
|||
private static final Map<String, Integer> DOLBY_VISION_STRING_TO_LEVEL;
|
||||
private static final String CODEC_ID_DVHE = "dvhe";
|
||||
private static final String CODEC_ID_DVH1 = "dvh1";
|
||||
// AV1.
|
||||
private static final SparseIntArray AV1_LEVEL_NUMBER_TO_CONST;
|
||||
private static final String CODEC_ID_AV01 = "av01";
|
||||
// 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;
|
||||
|
||||
|
|
@ -239,8 +242,6 @@ public final class MediaCodecUtil {
|
|||
if (codec == null) {
|
||||
return null;
|
||||
}
|
||||
// TODO: Check codec profile/level for AV1 once targeting Android Q and [Internal: b/128552878]
|
||||
// has been fixed.
|
||||
String[] parts = codec.split("\\.");
|
||||
switch (parts[0]) {
|
||||
case CODEC_ID_AVC1:
|
||||
|
|
@ -254,6 +255,8 @@ public final class MediaCodecUtil {
|
|||
case CODEC_ID_DVHE:
|
||||
case CODEC_ID_DVH1:
|
||||
return getDolbyVisionProfileAndLevel(codec, parts);
|
||||
case CODEC_ID_AV01:
|
||||
return getAv1ProfileAndLevel(codec, parts);
|
||||
case CODEC_ID_MP4A:
|
||||
return getAacCodecProfileAndLevel(codec, parts);
|
||||
default:
|
||||
|
|
@ -684,6 +687,48 @@ public final class MediaCodecUtil {
|
|||
return new Pair<>(profile, level);
|
||||
}
|
||||
|
||||
private static Pair<Integer, Integer> getAv1ProfileAndLevel(String codec, String[] parts) {
|
||||
if (parts.length < 4) {
|
||||
Log.w(TAG, "Ignoring malformed AV1 codec string: " + codec);
|
||||
return null;
|
||||
}
|
||||
int profileInteger;
|
||||
int levelInteger;
|
||||
int bitDepthInteger;
|
||||
try {
|
||||
profileInteger = Integer.parseInt(parts[1]);
|
||||
levelInteger = Integer.parseInt(parts[2].substring(0, 2));
|
||||
bitDepthInteger = Integer.parseInt(parts[3]);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, "Ignoring malformed AV1 codec string: " + codec);
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Recognize HDR profiles. Currently, the profile is assumed to be either Main8 or Main10.
|
||||
// See [Internal: b/124435216].
|
||||
if (profileInteger != 0) {
|
||||
Log.w(TAG, "Unknown AV1 profile: " + profileInteger);
|
||||
return null;
|
||||
}
|
||||
if (bitDepthInteger != 8 && bitDepthInteger != 10) {
|
||||
Log.w(TAG, "Unknown AV1 bit depth: " + bitDepthInteger);
|
||||
return null;
|
||||
}
|
||||
int profile;
|
||||
if (bitDepthInteger == 8) {
|
||||
profile = CodecProfileLevel.AV1ProfileMain8;
|
||||
} else {
|
||||
profile = CodecProfileLevel.AV1ProfileMain10;
|
||||
}
|
||||
|
||||
int level = AV1_LEVEL_NUMBER_TO_CONST.get(levelInteger, -1);
|
||||
if (level == -1) {
|
||||
Log.w(TAG, "Unknown AV1 level: " + levelInteger);
|
||||
return null;
|
||||
}
|
||||
return new Pair<>(profile, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion values taken from ISO 14496-10 Table A-1.
|
||||
*
|
||||
|
|
@ -1010,6 +1055,32 @@ public final class MediaCodecUtil {
|
|||
DOLBY_VISION_STRING_TO_LEVEL.put("08", CodecProfileLevel.DolbyVisionLevelUhd48);
|
||||
DOLBY_VISION_STRING_TO_LEVEL.put("09", CodecProfileLevel.DolbyVisionLevelUhd60);
|
||||
|
||||
AV1_LEVEL_NUMBER_TO_CONST = new SparseIntArray();
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(0, CodecProfileLevel.AV1Level2);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(1, CodecProfileLevel.AV1Level21);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(2, CodecProfileLevel.AV1Level22);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(3, CodecProfileLevel.AV1Level23);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(4, CodecProfileLevel.AV1Level3);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(5, CodecProfileLevel.AV1Level31);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(6, CodecProfileLevel.AV1Level32);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(7, CodecProfileLevel.AV1Level33);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(8, CodecProfileLevel.AV1Level4);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(9, CodecProfileLevel.AV1Level41);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(10, CodecProfileLevel.AV1Level42);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(11, CodecProfileLevel.AV1Level43);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(12, CodecProfileLevel.AV1Level5);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(13, CodecProfileLevel.AV1Level51);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(14, CodecProfileLevel.AV1Level52);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(15, CodecProfileLevel.AV1Level53);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(16, CodecProfileLevel.AV1Level6);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(17, CodecProfileLevel.AV1Level61);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(18, CodecProfileLevel.AV1Level62);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(19, CodecProfileLevel.AV1Level63);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(20, CodecProfileLevel.AV1Level7);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(21, CodecProfileLevel.AV1Level71);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(22, CodecProfileLevel.AV1Level72);
|
||||
AV1_LEVEL_NUMBER_TO_CONST.put(23, CodecProfileLevel.AV1Level73);
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -60,6 +60,31 @@ public final class MediaCodecUtilTest {
|
|||
MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesAv1ProfileMain8CodecString() {
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
"av01.0.10M.08",
|
||||
MediaCodecInfo.CodecProfileLevel.AV1ProfileMain8,
|
||||
MediaCodecInfo.CodecProfileLevel.AV1Level42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesAv1ProfileMain10CodecString() {
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
"av01.0.20M.10",
|
||||
MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10,
|
||||
MediaCodecInfo.CodecProfileLevel.AV1Level7);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesFullAv1CodecString() {
|
||||
// Example from https://aomediacodec.github.io/av1-isobmff/#codecsparam.
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
"av01.0.04M.10.0.112.09.16.09.0",
|
||||
MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10,
|
||||
MediaCodecInfo.CodecProfileLevel.AV1Level3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_rejectsNullCodecString() {
|
||||
assertThat(MediaCodecUtil.getCodecProfileAndLevel(/* codec= */ null)).isNull();
|
||||
|
|
|
|||
Loading…
Reference in a new issue