Fix Dolby Vision fallback to AVC and HEVC
PiperOrigin-RevId: 267979637
This commit is contained in:
parent
0aba89b60e
commit
e21467f653
@ -67,6 +67,7 @@
|
||||
* Add `uid` to `Timeline.Window` to uniquely identify window instances.
|
||||
* Fix decoder selection for E-AC3 JOC streams
|
||||
([#6398](https://github.com/google/ExoPlayer/issues/6398)).
|
||||
* Fix Dolby Vision fallback to AVC and HEVC.
|
||||
|
||||
### 2.10.4 ###
|
||||
|
||||
|
@ -81,8 +81,6 @@ public final class MediaCodecUtil {
|
||||
// Dolby Vision.
|
||||
private static final Map<String, Integer> DOLBY_VISION_STRING_TO_PROFILE;
|
||||
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";
|
||||
@ -245,6 +243,10 @@ public final class MediaCodecUtil {
|
||||
return null;
|
||||
}
|
||||
String[] parts = format.codecs.split("\\.");
|
||||
// Dolby Vision can use DV, AVC or HEVC codec IDs, so check the MIME type first.
|
||||
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
|
||||
return getDolbyVisionProfileAndLevel(format.codecs, parts);
|
||||
}
|
||||
switch (parts[0]) {
|
||||
case CODEC_ID_AVC1:
|
||||
case CODEC_ID_AVC2:
|
||||
@ -254,9 +256,6 @@ public final class MediaCodecUtil {
|
||||
case CODEC_ID_HEV1:
|
||||
case CODEC_ID_HVC1:
|
||||
return getHevcProfileAndLevel(format.codecs, parts);
|
||||
case CODEC_ID_DVHE:
|
||||
case CODEC_ID_DVH1:
|
||||
return getDolbyVisionProfileAndLevel(format.codecs, parts);
|
||||
case CODEC_ID_AV01:
|
||||
return getAv1ProfileAndLevel(format.codecs, parts, format.colorInfo);
|
||||
case CODEC_ID_MP4A:
|
||||
|
@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodecInfo.CodecCapabilities;
|
||||
import android.media.MediaCodecInfo.CodecProfileLevel;
|
||||
import android.media.MediaCrypto;
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Bundle;
|
||||
@ -393,15 +394,17 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
||||
format.sampleMimeType, requiresSecureDecoder, requiresTunnelingDecoder);
|
||||
decoderInfos = MediaCodecUtil.getDecoderInfosSortedByFormatSupport(decoderInfos, format);
|
||||
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.
|
||||
// Fall back to H.264/AVC or H.265/HEVC for the relevant DV profiles.
|
||||
@Nullable
|
||||
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
|
||||
if (codecProfileAndLevel != null) {
|
||||
int profile = codecProfileAndLevel.first;
|
||||
if (profile == 4 || profile == 8) {
|
||||
if (profile == CodecProfileLevel.DolbyVisionProfileDvheDtr
|
||||
|| profile == CodecProfileLevel.DolbyVisionProfileDvheSt) {
|
||||
decoderInfos.addAll(
|
||||
mediaCodecSelector.getDecoderInfos(
|
||||
MimeTypes.VIDEO_H265, requiresSecureDecoder, requiresTunnelingDecoder));
|
||||
} else if (profile == 9) {
|
||||
} else if (profile == CodecProfileLevel.DolbyVisionProfileDvavSe) {
|
||||
decoderInfos.addAll(
|
||||
mediaCodecSelector.getDecoderInfos(
|
||||
MimeTypes.VIDEO_H264, requiresSecureDecoder, requiresTunnelingDecoder));
|
||||
|
@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
@ -34,6 +35,7 @@ public final class MediaCodecUtilTest {
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesVp9Profile1CodecString() {
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
MimeTypes.VIDEO_VP9,
|
||||
"vp09.01.51",
|
||||
MediaCodecInfo.CodecProfileLevel.VP9Profile1,
|
||||
MediaCodecInfo.CodecProfileLevel.VP9Level51);
|
||||
@ -42,6 +44,7 @@ public final class MediaCodecUtilTest {
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesVp9Profile2CodecString() {
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
MimeTypes.VIDEO_VP9,
|
||||
"vp09.02.10",
|
||||
MediaCodecInfo.CodecProfileLevel.VP9Profile2,
|
||||
MediaCodecInfo.CodecProfileLevel.VP9Level1);
|
||||
@ -51,6 +54,7 @@ public final class MediaCodecUtilTest {
|
||||
public void getCodecProfileAndLevel_handlesFullVp9CodecString() {
|
||||
// Example from https://www.webmproject.org/vp9/mp4/#codecs-parameter-string.
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
MimeTypes.VIDEO_VP9,
|
||||
"vp09.02.10.10.01.09.16.09.01",
|
||||
MediaCodecInfo.CodecProfileLevel.VP9Profile2,
|
||||
MediaCodecInfo.CodecProfileLevel.VP9Level1);
|
||||
@ -59,6 +63,7 @@ public final class MediaCodecUtilTest {
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesDolbyVisionCodecString() {
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
MimeTypes.VIDEO_DOLBY_VISION,
|
||||
"dvh1.05.05",
|
||||
MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn,
|
||||
MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60);
|
||||
@ -67,6 +72,7 @@ public final class MediaCodecUtilTest {
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesAv1ProfileMain8CodecString() {
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
MimeTypes.VIDEO_AV1,
|
||||
"av01.0.10M.08",
|
||||
MediaCodecInfo.CodecProfileLevel.AV1ProfileMain8,
|
||||
MediaCodecInfo.CodecProfileLevel.AV1Level42);
|
||||
@ -75,6 +81,7 @@ public final class MediaCodecUtilTest {
|
||||
@Test
|
||||
public void getCodecProfileAndLevel_handlesAv1ProfileMain10CodecString() {
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
MimeTypes.VIDEO_AV1,
|
||||
"av01.0.20M.10",
|
||||
MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10,
|
||||
MediaCodecInfo.CodecProfileLevel.AV1Level7);
|
||||
@ -91,7 +98,7 @@ public final class MediaCodecUtilTest {
|
||||
Format format =
|
||||
Format.createVideoSampleFormat(
|
||||
/* id= */ null,
|
||||
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
|
||||
MimeTypes.VIDEO_AV1,
|
||||
/* codecs= */ "av01.0.21M.10",
|
||||
/* bitrate= */ Format.NO_VALUE,
|
||||
/* maxInputSize= */ Format.NO_VALUE,
|
||||
@ -122,7 +129,7 @@ public final class MediaCodecUtilTest {
|
||||
Format format =
|
||||
Format.createVideoSampleFormat(
|
||||
/* id= */ null,
|
||||
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
|
||||
MimeTypes.VIDEO_AV1,
|
||||
/* codecs= */ "av01.0.21M.10",
|
||||
/* bitrate= */ Format.NO_VALUE,
|
||||
/* maxInputSize= */ Format.NO_VALUE,
|
||||
@ -146,6 +153,7 @@ public final class MediaCodecUtilTest {
|
||||
public void getCodecProfileAndLevel_handlesFullAv1CodecString() {
|
||||
// Example from https://aomediacodec.github.io/av1-isobmff/#codecsparam.
|
||||
assertCodecProfileAndLevelForCodecsString(
|
||||
MimeTypes.VIDEO_AV1,
|
||||
"av01.0.04M.10.0.112.09.16.09.0",
|
||||
MediaCodecInfo.CodecProfileLevel.AV1ProfileMain10,
|
||||
MediaCodecInfo.CodecProfileLevel.AV1Level3);
|
||||
@ -186,11 +194,11 @@ public final class MediaCodecUtilTest {
|
||||
}
|
||||
|
||||
private static void assertCodecProfileAndLevelForCodecsString(
|
||||
String codecs, int profile, int level) {
|
||||
String mimeType, String codecs, int profile, int level) {
|
||||
Format format =
|
||||
Format.createVideoSampleFormat(
|
||||
/* id= */ null,
|
||||
/* sampleMimeType= */ MimeTypes.VIDEO_UNKNOWN,
|
||||
mimeType,
|
||||
/* codecs= */ codecs,
|
||||
/* bitrate= */ Format.NO_VALUE,
|
||||
/* maxInputSize= */ Format.NO_VALUE,
|
||||
@ -203,6 +211,7 @@ public final class MediaCodecUtilTest {
|
||||
}
|
||||
|
||||
private static void assertCodecProfileAndLevelForFormat(Format format, int profile, int level) {
|
||||
@Nullable
|
||||
Pair<Integer, Integer> codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
|
||||
assertThat(codecProfileAndLevel).isNotNull();
|
||||
assertThat(codecProfileAndLevel.first).isEqualTo(profile);
|
||||
|
Loading…
x
Reference in New Issue
Block a user