Commit e25340be by olly Committed by Oliver Woodman

Pass format instead of codec string when getting profile and level

AV1 profile recognition requires additional info contained in format.

PiperOrigin-RevId: 258746315
parent c779e84c
...@@ -198,7 +198,7 @@ public final class MediaCodecInfo { ...@@ -198,7 +198,7 @@ public final class MediaCodecInfo {
* @throws MediaCodecUtil.DecoderQueryException Thrown if an error occurs while querying decoders. * @throws MediaCodecUtil.DecoderQueryException Thrown if an error occurs while querying decoders.
*/ */
public boolean isFormatSupported(Format format) throws MediaCodecUtil.DecoderQueryException { public boolean isFormatSupported(Format format) throws MediaCodecUtil.DecoderQueryException {
if (!isCodecSupported(format.codecs)) { if (!isCodecSupported(format)) {
return false; return false;
} }
...@@ -226,25 +226,25 @@ public final class MediaCodecInfo { ...@@ -226,25 +226,25 @@ public final class MediaCodecInfo {
} }
/** /**
* Whether the decoder supports the given {@code codec}. If there is insufficient information to * Whether the decoder supports the codec of the given {@code format}. If there is insufficient
* decide, returns true. * information to decide, returns true.
* *
* @param codec Codec string as defined in RFC 6381. * @param format The input media format.
* @return True if the given codec is supported by the decoder. * @return True if the codec of the given {@code format} is supported by the decoder.
*/ */
public boolean isCodecSupported(String codec) { public boolean isCodecSupported(Format format) {
if (codec == null || mimeType == null) { if (format.codecs == null || mimeType == null) {
return true; return true;
} }
String codecMimeType = MimeTypes.getMediaMimeType(codec); String codecMimeType = MimeTypes.getMediaMimeType(format.codecs);
if (codecMimeType == null) { if (codecMimeType == null) {
return true; return true;
} }
if (!mimeType.equals(codecMimeType)) { if (!mimeType.equals(codecMimeType)) {
logNoSupport("codec.mime " + codec + ", " + codecMimeType); logNoSupport("codec.mime " + format.codecs + ", " + codecMimeType);
return false; return false;
} }
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(codec); Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
if (codecProfileAndLevel == null) { if (codecProfileAndLevel == null) {
// If we don't know any better, we assume that the profile and level are supported. // If we don't know any better, we assume that the profile and level are supported.
return true; return true;
...@@ -261,7 +261,7 @@ public final class MediaCodecInfo { ...@@ -261,7 +261,7 @@ public final class MediaCodecInfo {
return true; return true;
} }
} }
logNoSupport("codec.profileLevel, " + codec + ", " + codecMimeType); logNoSupport("codec.profileLevel, " + format.codecs + ", " + codecMimeType);
return false; return false;
} }
...@@ -279,8 +279,7 @@ public final class MediaCodecInfo { ...@@ -279,8 +279,7 @@ public final class MediaCodecInfo {
if (isVideo) { if (isVideo) {
return adaptive; return adaptive;
} else { } else {
Pair<Integer, Integer> codecProfileLevel = Pair<Integer, Integer> codecProfileLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
MediaCodecUtil.getCodecProfileAndLevel(format.codecs);
return codecProfileLevel != null && codecProfileLevel.first == CodecProfileLevel.AACObjectXHE; return codecProfileLevel != null && codecProfileLevel.first == CodecProfileLevel.AACObjectXHE;
} }
} }
...@@ -314,9 +313,9 @@ public final class MediaCodecInfo { ...@@ -314,9 +313,9 @@ public final class MediaCodecInfo {
} }
// Check the codec profile levels support adaptation. // Check the codec profile levels support adaptation.
Pair<Integer, Integer> oldCodecProfileLevel = Pair<Integer, Integer> oldCodecProfileLevel =
MediaCodecUtil.getCodecProfileAndLevel(oldFormat.codecs); MediaCodecUtil.getCodecProfileAndLevel(oldFormat);
Pair<Integer, Integer> newCodecProfileLevel = Pair<Integer, Integer> newCodecProfileLevel =
MediaCodecUtil.getCodecProfileAndLevel(newFormat.codecs); MediaCodecUtil.getCodecProfileAndLevel(newFormat);
if (oldCodecProfileLevel == null || newCodecProfileLevel == null) { if (oldCodecProfileLevel == null || newCodecProfileLevel == null) {
return false; return false;
} }
......
...@@ -230,35 +230,34 @@ public final class MediaCodecUtil { ...@@ -230,35 +230,34 @@ public final class MediaCodecUtil {
} }
/** /**
* Returns profile and level (as defined by {@link CodecProfileLevel}) corresponding to the given * Returns profile and level (as defined by {@link CodecProfileLevel}) corresponding to the codec
* codec description string (as defined by RFC 6381). * description string (as defined by RFC 6381) of the given format.
* *
* @param codec A codec description string, as defined by RFC 6381, or {@code null} if not known. * @param format Media format with a codec description string, as defined by RFC 6381.
* @return A pair (profile constant, level constant) if {@code codec} is well-formed and * @return A pair (profile constant, level constant) if the codec of the {@code format} is
* recognized, or null otherwise * well-formed and recognized, or null otherwise.
*/ */
@Nullable public static Pair<Integer, Integer> getCodecProfileAndLevel(Format format) {
public static Pair<Integer, Integer> getCodecProfileAndLevel(@Nullable String codec) { if (format.codecs == null) {
if (codec == null) {
return null; return null;
} }
String[] parts = codec.split("\\."); String[] parts = format.codecs.split("\\.");
switch (parts[0]) { switch (parts[0]) {
case CODEC_ID_AVC1: case CODEC_ID_AVC1:
case CODEC_ID_AVC2: case CODEC_ID_AVC2:
return getAvcProfileAndLevel(codec, parts); return getAvcProfileAndLevel(format.codecs, parts);
case CODEC_ID_VP09: case CODEC_ID_VP09:
return getVp9ProfileAndLevel(codec, parts); return getVp9ProfileAndLevel(format.codecs, parts);
case CODEC_ID_HEV1: case CODEC_ID_HEV1:
case CODEC_ID_HVC1: case CODEC_ID_HVC1:
return getHevcProfileAndLevel(codec, parts); return getHevcProfileAndLevel(format.codecs, parts);
case CODEC_ID_DVHE: case CODEC_ID_DVHE:
case CODEC_ID_DVH1: case CODEC_ID_DVH1:
return getDolbyVisionProfileAndLevel(codec, parts); return getDolbyVisionProfileAndLevel(format.codecs, parts);
case CODEC_ID_AV01: case CODEC_ID_AV01:
return getAv1ProfileAndLevel(codec, parts); return getAv1ProfileAndLevel(format.codecs, parts);
case CODEC_ID_MP4A: case CODEC_ID_MP4A:
return getAacCodecProfileAndLevel(codec, parts); return getAacCodecProfileAndLevel(format.codecs, parts);
default: default:
return null; return null;
} }
......
...@@ -390,8 +390,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -390,8 +390,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
decoderInfos = MediaCodecUtil.getDecoderInfosSortedByFormatSupport(decoderInfos, format); decoderInfos = MediaCodecUtil.getDecoderInfosSortedByFormatSupport(decoderInfos, format);
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) { if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
// Fallback to primary decoders for H.265/HEVC or H.264/AVC for the relevant DV profiles. // Fallback to primary decoders for H.265/HEVC or H.264/AVC for the relevant DV profiles.
Pair<Integer, Integer> codecProfileAndLevel = Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
MediaCodecUtil.getCodecProfileAndLevel(format.codecs);
if (codecProfileAndLevel != null) { if (codecProfileAndLevel != null) {
int profile = codecProfileAndLevel.first; int profile = codecProfileAndLevel.first;
if (profile == 4 || profile == 8) { if (profile == 4 || profile == 8) {
...@@ -1194,8 +1193,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { ...@@ -1194,8 +1193,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) { if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
// Some phones require the profile to be set on the codec. // Some phones require the profile to be set on the codec.
// See https://github.com/google/ExoPlayer/pull/5438. // See https://github.com/google/ExoPlayer/pull/5438.
Pair<Integer, Integer> codecProfileAndLevel = Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
MediaCodecUtil.getCodecProfileAndLevel(format.codecs);
if (codecProfileAndLevel != null) { if (codecProfileAndLevel != null) {
MediaFormatUtil.maybeSetInteger( MediaFormatUtil.maybeSetInteger(
mediaFormat, MediaFormat.KEY_PROFILE, codecProfileAndLevel.first); mediaFormat, MediaFormat.KEY_PROFILE, codecProfileAndLevel.first);
......
...@@ -20,6 +20,8 @@ import static com.google.common.truth.Truth.assertThat; ...@@ -20,6 +20,8 @@ import static com.google.common.truth.Truth.assertThat;
import android.media.MediaCodecInfo; import android.media.MediaCodecInfo;
import android.util.Pair; import android.util.Pair;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.util.MimeTypes;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -87,17 +89,53 @@ public final class MediaCodecUtilTest { ...@@ -87,17 +89,53 @@ public final class MediaCodecUtilTest {
@Test @Test
public void getCodecProfileAndLevel_rejectsNullCodecString() { public void getCodecProfileAndLevel_rejectsNullCodecString() {
assertThat(MediaCodecUtil.getCodecProfileAndLevel(/* codec= */ null)).isNull(); Format format =
Format.createVideoSampleFormat(
/* id= */ null,
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
/* codecs= */ null,
/* bitrate= */ Format.NO_VALUE,
/* maxInputSize= */ Format.NO_VALUE,
/* width= */ 1024,
/* height= */ 768,
/* frameRate= */ Format.NO_VALUE,
/* initializationData= */ null,
/* drmInitData= */ null);
assertThat(MediaCodecUtil.getCodecProfileAndLevel(format)).isNull();
} }
@Test @Test
public void getCodecProfileAndLevel_rejectsEmptyCodecString() { public void getCodecProfileAndLevel_rejectsEmptyCodecString() {
assertThat(MediaCodecUtil.getCodecProfileAndLevel("")).isNull(); Format format =
Format.createVideoSampleFormat(
/* id= */ null,
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
/* codecs= */ "",
/* bitrate= */ Format.NO_VALUE,
/* maxInputSize= */ Format.NO_VALUE,
/* width= */ 1024,
/* height= */ 768,
/* frameRate= */ Format.NO_VALUE,
/* initializationData= */ null,
/* drmInitData= */ null);
assertThat(MediaCodecUtil.getCodecProfileAndLevel(format)).isNull();
} }
private static void assertCodecProfileAndLevelForCodecsString( private static void assertCodecProfileAndLevelForCodecsString(
String codecs, int profile, int level) { String codecs, int profile, int level) {
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(codecs); Format format =
Format.createVideoSampleFormat(
/* id= */ null,
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
/* codecs= */ codecs,
/* bitrate= */ Format.NO_VALUE,
/* maxInputSize= */ Format.NO_VALUE,
/* width= */ 1024,
/* height= */ 768,
/* frameRate= */ Format.NO_VALUE,
/* initializationData= */ null,
/* drmInitData= */ null);
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
assertThat(codecProfileAndLevel).isNotNull(); assertThat(codecProfileAndLevel).isNotNull();
assertThat(codecProfileAndLevel.first).isEqualTo(profile); assertThat(codecProfileAndLevel.first).isEqualTo(profile);
assertThat(codecProfileAndLevel.second).isEqualTo(level); 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