Fix Dolby Vision fallback to AVC and HEVC

PiperOrigin-RevId: 267979637
This commit is contained in:
andrewlewis 2019-09-09 13:58:59 +01:00 committed by Oliver Woodman
parent 0aba89b60e
commit e21467f653
4 changed files with 24 additions and 12 deletions

View File

@ -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 ###

View File

@ -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:

View File

@ -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));

View File

@ -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);