Commit 009d6296 by andrewlewis Committed by Oliver Woodman

Check codec profiles/levels for VP9

Also add some unit tests for codecs strings parsing.

PiperOrigin-RevId: 245210490
parent 0ff47a8c
...@@ -68,6 +68,10 @@ public final class MediaCodecUtil { ...@@ -68,6 +68,10 @@ public final class MediaCodecUtil {
private static final SparseIntArray AVC_LEVEL_NUMBER_TO_CONST; private static final SparseIntArray AVC_LEVEL_NUMBER_TO_CONST;
private static final String CODEC_ID_AVC1 = "avc1"; private static final String CODEC_ID_AVC1 = "avc1";
private static final String CODEC_ID_AVC2 = "avc2"; private static final String CODEC_ID_AVC2 = "avc2";
// VP9
private static final SparseIntArray VP9_PROFILE_NUMBER_TO_CONST;
private static final SparseIntArray VP9_LEVEL_NUMBER_TO_CONST;
private static final String CODEC_ID_VP09 = "vp09";
// HEVC. // HEVC.
private static final Map<String, Integer> HEVC_CODEC_STRING_TO_PROFILE_LEVEL; 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_HEV1 = "hev1";
...@@ -242,6 +246,8 @@ public final class MediaCodecUtil { ...@@ -242,6 +246,8 @@ public final class MediaCodecUtil {
case CODEC_ID_AVC1: case CODEC_ID_AVC1:
case CODEC_ID_AVC2: case CODEC_ID_AVC2:
return getAvcProfileAndLevel(codec, parts); return getAvcProfileAndLevel(codec, parts);
case CODEC_ID_VP09:
return getVp9ProfileAndLevel(codec, parts);
case CODEC_ID_HEV1: case CODEC_ID_HEV1:
case CODEC_ID_HVC1: case CODEC_ID_HVC1:
return getHevcProfileAndLevel(codec, parts); return getHevcProfileAndLevel(codec, parts);
...@@ -640,6 +646,34 @@ public final class MediaCodecUtil { ...@@ -640,6 +646,34 @@ public final class MediaCodecUtil {
return new Pair<>(profile, level); return new Pair<>(profile, level);
} }
private static Pair<Integer, Integer> getVp9ProfileAndLevel(String codec, String[] parts) {
if (parts.length < 3) {
Log.w(TAG, "Ignoring malformed VP9 codec string: " + codec);
return null;
}
int profileInteger;
int levelInteger;
try {
profileInteger = Integer.parseInt(parts[1]);
levelInteger = Integer.parseInt(parts[2]);
} catch (NumberFormatException e) {
Log.w(TAG, "Ignoring malformed VP9 codec string: " + codec);
return null;
}
int profile = VP9_PROFILE_NUMBER_TO_CONST.get(profileInteger, -1);
if (profile == -1) {
Log.w(TAG, "Unknown VP9 profile: " + profileInteger);
return null;
}
int level = VP9_LEVEL_NUMBER_TO_CONST.get(levelInteger, -1);
if (level == -1) {
Log.w(TAG, "Unknown VP9 level: " + levelInteger);
return null;
}
return new Pair<>(profile, level);
}
/** /**
* Conversion values taken from ISO 14496-10 Table A-1. * Conversion values taken from ISO 14496-10 Table A-1.
* *
...@@ -895,6 +929,26 @@ public final class MediaCodecUtil { ...@@ -895,6 +929,26 @@ public final class MediaCodecUtil {
AVC_LEVEL_NUMBER_TO_CONST.put(51, CodecProfileLevel.AVCLevel51); AVC_LEVEL_NUMBER_TO_CONST.put(51, CodecProfileLevel.AVCLevel51);
AVC_LEVEL_NUMBER_TO_CONST.put(52, CodecProfileLevel.AVCLevel52); AVC_LEVEL_NUMBER_TO_CONST.put(52, CodecProfileLevel.AVCLevel52);
VP9_PROFILE_NUMBER_TO_CONST = new SparseIntArray();
VP9_PROFILE_NUMBER_TO_CONST.put(0, CodecProfileLevel.VP9Profile0);
VP9_PROFILE_NUMBER_TO_CONST.put(1, CodecProfileLevel.VP9Profile1);
VP9_PROFILE_NUMBER_TO_CONST.put(2, CodecProfileLevel.VP9Profile2);
VP9_PROFILE_NUMBER_TO_CONST.put(3, CodecProfileLevel.VP9Profile3);
VP9_LEVEL_NUMBER_TO_CONST = new SparseIntArray();
VP9_LEVEL_NUMBER_TO_CONST.put(10, CodecProfileLevel.VP9Level1);
VP9_LEVEL_NUMBER_TO_CONST.put(11, CodecProfileLevel.VP9Level11);
VP9_LEVEL_NUMBER_TO_CONST.put(20, CodecProfileLevel.VP9Level2);
VP9_LEVEL_NUMBER_TO_CONST.put(21, CodecProfileLevel.VP9Level21);
VP9_LEVEL_NUMBER_TO_CONST.put(30, CodecProfileLevel.VP9Level3);
VP9_LEVEL_NUMBER_TO_CONST.put(31, CodecProfileLevel.VP9Level31);
VP9_LEVEL_NUMBER_TO_CONST.put(40, CodecProfileLevel.VP9Level4);
VP9_LEVEL_NUMBER_TO_CONST.put(41, CodecProfileLevel.VP9Level41);
VP9_LEVEL_NUMBER_TO_CONST.put(50, CodecProfileLevel.VP9Level5);
VP9_LEVEL_NUMBER_TO_CONST.put(51, CodecProfileLevel.VP9Level51);
VP9_LEVEL_NUMBER_TO_CONST.put(60, CodecProfileLevel.VP9Level6);
VP9_LEVEL_NUMBER_TO_CONST.put(61, CodecProfileLevel.VP9Level61);
VP9_LEVEL_NUMBER_TO_CONST.put(62, CodecProfileLevel.VP9Level62);
HEVC_CODEC_STRING_TO_PROFILE_LEVEL = new HashMap<>(); HEVC_CODEC_STRING_TO_PROFILE_LEVEL = new HashMap<>();
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("L30", CodecProfileLevel.HEVCMainTierLevel1); HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("L30", CodecProfileLevel.HEVCMainTierLevel1);
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("L60", CodecProfileLevel.HEVCMainTierLevel2); HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("L60", CodecProfileLevel.HEVCMainTierLevel2);
......
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.mediacodec;
import static com.google.common.truth.Truth.assertThat;
import android.media.MediaCodecInfo;
import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link MediaCodecUtil}. */
@RunWith(AndroidJUnit4.class)
public final class MediaCodecUtilTest {
@Test
public void getCodecProfileAndLevel_handlesVp9Profile1CodecString() {
assertCodecProfileAndLevelForCodecsString(
"vp09.01.51",
MediaCodecInfo.CodecProfileLevel.VP9Profile1,
MediaCodecInfo.CodecProfileLevel.VP9Level51);
}
@Test
public void getCodecProfileAndLevel_handlesVp9Profile2CodecString() {
assertCodecProfileAndLevelForCodecsString(
"vp09.02.10",
MediaCodecInfo.CodecProfileLevel.VP9Profile2,
MediaCodecInfo.CodecProfileLevel.VP9Level1);
}
@Test
public void getCodecProfileAndLevel_handlesFullVp9CodecString() {
// Example from https://www.webmproject.org/vp9/mp4/#codecs-parameter-string.
assertCodecProfileAndLevelForCodecsString(
"vp09.02.10.10.01.09.16.09.01",
MediaCodecInfo.CodecProfileLevel.VP9Profile2,
MediaCodecInfo.CodecProfileLevel.VP9Level1);
}
@Test
public void getCodecProfileAndLevel_handlesDolbyVisionCodecString() {
assertCodecProfileAndLevelForCodecsString(
"dvh1.05.05",
MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn,
MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60);
}
@Test
public void getCodecProfileAndLevel_rejectsNullCodecString() {
assertThat(MediaCodecUtil.getCodecProfileAndLevel(/* codec= */ null)).isNull();
}
@Test
public void getCodecProfileAndLevel_rejectsEmptyCodecString() {
assertThat(MediaCodecUtil.getCodecProfileAndLevel("")).isNull();
}
private static void assertCodecProfileAndLevelForCodecsString(
String codecs, int profile, int level) {
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(codecs);
assertThat(codecProfileAndLevel).isNotNull();
assertThat(codecProfileAndLevel.first).isEqualTo(profile);
assertThat(codecProfileAndLevel.second).isEqualTo(level);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment