diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java index df5ca05972..6a967a359b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java @@ -25,10 +25,12 @@ import androidx.annotation.Nullable; import android.text.TextUtils; import android.util.Pair; import android.util.SparseIntArray; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; +import com.google.android.exoplayer2.video.ColorInfo; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -255,7 +257,7 @@ public final class MediaCodecUtil { case CODEC_ID_DVH1: return getDolbyVisionProfileAndLevel(format.codecs, parts); case CODEC_ID_AV01: - return getAv1ProfileAndLevel(format.codecs, parts); + return getAv1ProfileAndLevel(format.codecs, parts, format.colorInfo); case CODEC_ID_MP4A: return getAacCodecProfileAndLevel(format.codecs, parts); default: @@ -686,7 +688,8 @@ public final class MediaCodecUtil { return new Pair<>(profile, level); } - private static Pair getAv1ProfileAndLevel(String codec, String[] parts) { + private static Pair getAv1ProfileAndLevel( + String codec, String[] parts, @Nullable ColorInfo colorInfo) { if (parts.length < 4) { Log.w(TAG, "Ignoring malformed AV1 codec string: " + codec); return null; @@ -703,8 +706,6 @@ public final class MediaCodecUtil { 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; @@ -716,6 +717,11 @@ public final class MediaCodecUtil { int profile; if (bitDepthInteger == 8) { profile = CodecProfileLevel.AV1ProfileMain8; + } else if (colorInfo != null + && (colorInfo.hdrStaticInfo != null + || colorInfo.colorTransfer == C.COLOR_TRANSFER_HLG + || colorInfo.colorTransfer == C.COLOR_TRANSFER_ST2084)) { + profile = CodecProfileLevel.AV1ProfileMain10HDR10; } else { profile = CodecProfileLevel.AV1ProfileMain10; } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtilTest.java b/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtilTest.java index c485ff49f6..e8d65255c3 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtilTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtilTest.java @@ -20,8 +20,10 @@ import static com.google.common.truth.Truth.assertThat; import android.media.MediaCodecInfo; import android.util.Pair; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.video.ColorInfo; import org.junit.Test; import org.junit.runner.RunWith; @@ -78,6 +80,68 @@ public final class MediaCodecUtilTest { MediaCodecInfo.CodecProfileLevel.AV1Level7); } + @Test + public void getCodecProfileAndLevel_handlesAv1ProfileMain10HDRWithHdrInfoSet() { + ColorInfo colorInfo = + new ColorInfo( + /* colorSpace= */ C.COLOR_SPACE_BT709, + /* colorRange= */ C.COLOR_RANGE_LIMITED, + /* colorTransfer= */ C.COLOR_TRANSFER_SDR, + /* hdrStaticInfo= */ new byte[] {1, 2, 3, 4, 5, 6, 7}); + Format format = + Format.createVideoSampleFormat( + /* id= */ null, + /* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN, + /* codecs= */ "av01.0.21M.10", + /* bitrate= */ Format.NO_VALUE, + /* maxInputSize= */ Format.NO_VALUE, + /* width= */ 1024, + /* height= */ 768, + /* frameRate= */ Format.NO_VALUE, + /* initializationData= */ null, + /* rotationDegrees= */ Format.NO_VALUE, + /* pixelWidthHeightRatio= */ 0, + /* projectionData= */ null, + /* stereoMode= */ Format.NO_VALUE, + /* colorInfo= */ colorInfo, + /* drmInitData */ null); + assertCodecProfileAndLevelForFormat( + format, + MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10, + MediaCodecInfo.CodecProfileLevel.AV1Level71); + } + + @Test + public void getCodecProfileAndLevel_handlesAv1ProfileMain10HDRWithoutHdrInfoSet() { + ColorInfo colorInfo = + new ColorInfo( + /* colorSpace= */ C.COLOR_SPACE_BT709, + /* colorRange= */ C.COLOR_RANGE_LIMITED, + /* colorTransfer= */ C.COLOR_TRANSFER_HLG, + /* hdrStaticInfo= */ null); + Format format = + Format.createVideoSampleFormat( + /* id= */ null, + /* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN, + /* codecs= */ "av01.0.21M.10", + /* bitrate= */ Format.NO_VALUE, + /* maxInputSize= */ Format.NO_VALUE, + /* width= */ 1024, + /* height= */ 768, + /* frameRate= */ Format.NO_VALUE, + /* initializationData= */ null, + /* rotationDegrees= */ Format.NO_VALUE, + /* pixelWidthHeightRatio= */ 0, + /* projectionData= */ null, + /* stereoMode= */ Format.NO_VALUE, + /* colorInfo= */ colorInfo, + /* drmInitData */ null); + assertCodecProfileAndLevelForFormat( + format, + MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10HDR10, + MediaCodecInfo.CodecProfileLevel.AV1Level71); + } + @Test public void getCodecProfileAndLevel_handlesFullAv1CodecString() { // Example from https://aomediacodec.github.io/av1-isobmff/#codecsparam. @@ -135,6 +199,10 @@ public final class MediaCodecUtilTest { /* frameRate= */ Format.NO_VALUE, /* initializationData= */ null, /* drmInitData= */ null); + assertCodecProfileAndLevelForFormat(format, profile, level); + } + + private static void assertCodecProfileAndLevelForFormat(Format format, int profile, int level) { Pair codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format); assertThat(codecProfileAndLevel).isNotNull(); assertThat(codecProfileAndLevel.first).isEqualTo(profile);