Merge #5438: Dolby Vision
Imported from GitHub PR https://github.com/google/ExoPlayer/pull/5438 Plus the following changes: - Only support profile 5 (handling other profiles requires backward-compatibility changes in the renderer which are left for a later change.) - Only add KEY_PROFILE to the codec configuration MediaFormat for Dolby Vision. - In MediaCodecUtil support all DV profiles that Android has constants for. This includes ones that are "not supported for new applications". Since we don't extract these profiles, this is currently only for the benefit of custom extractors. - Misc code style fixes and reordering for consistency. Merge 37878b975c2bc082b0568e21cbe62bfcef97c10d into 67be9e77834c0dc9d2b5d462c01c2f39718c8817 PiperOrigin-RevId: 233066799
This commit is contained in:
parent
434b5a3029
commit
9b6caf9eda
@ -14,6 +14,7 @@
|
|||||||
* Update `TrackSelection.Factory` interface to support creating all track
|
* Update `TrackSelection.Factory` interface to support creating all track
|
||||||
selections together.
|
selections together.
|
||||||
* Do not retry failed loads whose error is `FileNotFoundException`.
|
* Do not retry failed loads whose error is `FileNotFoundException`.
|
||||||
|
* Support Dolby Vision extraction in MP4 and fMP4.
|
||||||
* Offline:
|
* Offline:
|
||||||
* Speed up removal of segmented downloads
|
* Speed up removal of segmented downloads
|
||||||
([#5136](https://github.com/google/ExoPlayer/issues/5136)).
|
([#5136](https://github.com/google/ExoPlayer/issues/5136)).
|
||||||
|
@ -53,8 +53,16 @@ import java.util.List;
|
|||||||
public static final int TYPE_ftyp = Util.getIntegerCodeForString("ftyp");
|
public static final int TYPE_ftyp = Util.getIntegerCodeForString("ftyp");
|
||||||
public static final int TYPE_avc1 = Util.getIntegerCodeForString("avc1");
|
public static final int TYPE_avc1 = Util.getIntegerCodeForString("avc1");
|
||||||
public static final int TYPE_avc3 = Util.getIntegerCodeForString("avc3");
|
public static final int TYPE_avc3 = Util.getIntegerCodeForString("avc3");
|
||||||
|
public static final int TYPE_avcC = Util.getIntegerCodeForString("avcC");
|
||||||
public static final int TYPE_hvc1 = Util.getIntegerCodeForString("hvc1");
|
public static final int TYPE_hvc1 = Util.getIntegerCodeForString("hvc1");
|
||||||
public static final int TYPE_hev1 = Util.getIntegerCodeForString("hev1");
|
public static final int TYPE_hev1 = Util.getIntegerCodeForString("hev1");
|
||||||
|
public static final int TYPE_hvcC = Util.getIntegerCodeForString("hvcC");
|
||||||
|
public static final int TYPE_dvav = Util.getIntegerCodeForString("dvav");
|
||||||
|
public static final int TYPE_dva1 = Util.getIntegerCodeForString("dva1");
|
||||||
|
public static final int TYPE_dvhe = Util.getIntegerCodeForString("dvhe");
|
||||||
|
public static final int TYPE_dvh1 = Util.getIntegerCodeForString("dvh1");
|
||||||
|
public static final int TYPE_dvcC = Util.getIntegerCodeForString("dvcC");
|
||||||
|
public static final int TYPE_dvvC = Util.getIntegerCodeForString("dvvC");
|
||||||
public static final int TYPE_s263 = Util.getIntegerCodeForString("s263");
|
public static final int TYPE_s263 = Util.getIntegerCodeForString("s263");
|
||||||
public static final int TYPE_d263 = Util.getIntegerCodeForString("d263");
|
public static final int TYPE_d263 = Util.getIntegerCodeForString("d263");
|
||||||
public static final int TYPE_mdat = Util.getIntegerCodeForString("mdat");
|
public static final int TYPE_mdat = Util.getIntegerCodeForString("mdat");
|
||||||
@ -83,8 +91,6 @@ import java.util.List;
|
|||||||
public static final int TYPE_mdia = Util.getIntegerCodeForString("mdia");
|
public static final int TYPE_mdia = Util.getIntegerCodeForString("mdia");
|
||||||
public static final int TYPE_minf = Util.getIntegerCodeForString("minf");
|
public static final int TYPE_minf = Util.getIntegerCodeForString("minf");
|
||||||
public static final int TYPE_stbl = Util.getIntegerCodeForString("stbl");
|
public static final int TYPE_stbl = Util.getIntegerCodeForString("stbl");
|
||||||
public static final int TYPE_avcC = Util.getIntegerCodeForString("avcC");
|
|
||||||
public static final int TYPE_hvcC = Util.getIntegerCodeForString("hvcC");
|
|
||||||
public static final int TYPE_esds = Util.getIntegerCodeForString("esds");
|
public static final int TYPE_esds = Util.getIntegerCodeForString("esds");
|
||||||
public static final int TYPE_moof = Util.getIntegerCodeForString("moof");
|
public static final int TYPE_moof = Util.getIntegerCodeForString("moof");
|
||||||
public static final int TYPE_traf = Util.getIntegerCodeForString("traf");
|
public static final int TYPE_traf = Util.getIntegerCodeForString("traf");
|
||||||
|
@ -33,6 +33,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
|
|||||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.android.exoplayer2.video.AvcConfig;
|
import com.google.android.exoplayer2.video.AvcConfig;
|
||||||
|
import com.google.android.exoplayer2.video.DolbyVisionConfig;
|
||||||
import com.google.android.exoplayer2.video.HevcConfig;
|
import com.google.android.exoplayer2.video.HevcConfig;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -735,11 +736,19 @@ import java.util.List;
|
|||||||
int childAtomSize = stsd.readInt();
|
int childAtomSize = stsd.readInt();
|
||||||
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
|
Assertions.checkArgument(childAtomSize > 0, "childAtomSize should be positive");
|
||||||
int childAtomType = stsd.readInt();
|
int childAtomType = stsd.readInt();
|
||||||
if (childAtomType == Atom.TYPE_avc1 || childAtomType == Atom.TYPE_avc3
|
if (childAtomType == Atom.TYPE_avc1
|
||||||
|| childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v
|
|| childAtomType == Atom.TYPE_avc3
|
||||||
|| childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1
|
|| childAtomType == Atom.TYPE_encv
|
||||||
|| childAtomType == Atom.TYPE_s263 || childAtomType == Atom.TYPE_vp08
|
|| childAtomType == Atom.TYPE_mp4v
|
||||||
|| childAtomType == Atom.TYPE_vp09) {
|
|| childAtomType == Atom.TYPE_hvc1
|
||||||
|
|| childAtomType == Atom.TYPE_hev1
|
||||||
|
|| childAtomType == Atom.TYPE_s263
|
||||||
|
|| childAtomType == Atom.TYPE_vp08
|
||||||
|
|| childAtomType == Atom.TYPE_vp09
|
||||||
|
|| childAtomType == Atom.TYPE_dvav
|
||||||
|
|| childAtomType == Atom.TYPE_dva1
|
||||||
|
|| childAtomType == Atom.TYPE_dvhe
|
||||||
|
|| childAtomType == Atom.TYPE_dvh1) {
|
||||||
parseVideoSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId,
|
parseVideoSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, trackId,
|
||||||
rotationDegrees, drmInitData, out, i);
|
rotationDegrees, drmInitData, out, i);
|
||||||
} else if (childAtomType == Atom.TYPE_mp4a
|
} else if (childAtomType == Atom.TYPE_mp4a
|
||||||
@ -852,6 +861,7 @@ import java.util.List;
|
|||||||
|
|
||||||
List<byte[]> initializationData = null;
|
List<byte[]> initializationData = null;
|
||||||
String mimeType = null;
|
String mimeType = null;
|
||||||
|
String codecs = null;
|
||||||
byte[] projectionData = null;
|
byte[] projectionData = null;
|
||||||
@C.StereoMode
|
@C.StereoMode
|
||||||
int stereoMode = Format.NO_VALUE;
|
int stereoMode = Format.NO_VALUE;
|
||||||
@ -882,6 +892,13 @@ import java.util.List;
|
|||||||
HevcConfig hevcConfig = HevcConfig.parse(parent);
|
HevcConfig hevcConfig = HevcConfig.parse(parent);
|
||||||
initializationData = hevcConfig.initializationData;
|
initializationData = hevcConfig.initializationData;
|
||||||
out.nalUnitLengthFieldLength = hevcConfig.nalUnitLengthFieldLength;
|
out.nalUnitLengthFieldLength = hevcConfig.nalUnitLengthFieldLength;
|
||||||
|
} else if (childAtomType == Atom.TYPE_dvcC || childAtomType == Atom.TYPE_dvvC) {
|
||||||
|
DolbyVisionConfig dolbyVisionConfig = DolbyVisionConfig.parse(parent);
|
||||||
|
// TODO: Support profiles 4, 8 and 9 once we have a way to fall back to AVC/HEVC decoding.
|
||||||
|
if (dolbyVisionConfig != null && dolbyVisionConfig.profile == 5) {
|
||||||
|
codecs = dolbyVisionConfig.codecs;
|
||||||
|
mimeType = MimeTypes.VIDEO_DOLBY_VISION;
|
||||||
|
}
|
||||||
} else if (childAtomType == Atom.TYPE_vpcC) {
|
} else if (childAtomType == Atom.TYPE_vpcC) {
|
||||||
Assertions.checkState(mimeType == null);
|
Assertions.checkState(mimeType == null);
|
||||||
mimeType = (atomType == Atom.TYPE_vp08) ? MimeTypes.VIDEO_VP8 : MimeTypes.VIDEO_VP9;
|
mimeType = (atomType == Atom.TYPE_vp08) ? MimeTypes.VIDEO_VP8 : MimeTypes.VIDEO_VP9;
|
||||||
@ -930,9 +947,23 @@ import java.util.List;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.format = Format.createVideoSampleFormat(Integer.toString(trackId), mimeType, null,
|
out.format =
|
||||||
Format.NO_VALUE, Format.NO_VALUE, width, height, Format.NO_VALUE, initializationData,
|
Format.createVideoSampleFormat(
|
||||||
rotationDegrees, pixelWidthHeightRatio, projectionData, stereoMode, null, drmInitData);
|
Integer.toString(trackId),
|
||||||
|
mimeType,
|
||||||
|
codecs,
|
||||||
|
/* bitrate= */ Format.NO_VALUE,
|
||||||
|
/* maxInputSize= */ Format.NO_VALUE,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
/* frameRate= */ Format.NO_VALUE,
|
||||||
|
initializationData,
|
||||||
|
rotationDegrees,
|
||||||
|
pixelWidthHeightRatio,
|
||||||
|
projectionData,
|
||||||
|
stereoMode,
|
||||||
|
/* colorInfo= */ null,
|
||||||
|
drmInitData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,6 +71,11 @@ public final class MediaCodecUtil {
|
|||||||
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";
|
||||||
private static final String CODEC_ID_HVC1 = "hvc1";
|
private static final String CODEC_ID_HVC1 = "hvc1";
|
||||||
|
// 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";
|
||||||
// MP4A AAC.
|
// MP4A AAC.
|
||||||
private static final SparseIntArray MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE;
|
private static final SparseIntArray MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE;
|
||||||
private static final String CODEC_ID_MP4A = "mp4a";
|
private static final String CODEC_ID_MP4A = "mp4a";
|
||||||
@ -208,6 +213,9 @@ public final class MediaCodecUtil {
|
|||||||
case CODEC_ID_HEV1:
|
case CODEC_ID_HEV1:
|
||||||
case CODEC_ID_HVC1:
|
case CODEC_ID_HVC1:
|
||||||
return getHevcProfileAndLevel(codec, parts);
|
return getHevcProfileAndLevel(codec, parts);
|
||||||
|
case CODEC_ID_DVHE:
|
||||||
|
case CODEC_ID_DVH1:
|
||||||
|
return getDolbyVisionProfileAndLevel(codec, parts);
|
||||||
case CODEC_ID_AVC1:
|
case CODEC_ID_AVC1:
|
||||||
case CODEC_ID_AVC2:
|
case CODEC_ID_AVC2:
|
||||||
return getAvcProfileAndLevel(codec, parts);
|
return getAvcProfileAndLevel(codec, parts);
|
||||||
@ -423,6 +431,34 @@ public final class MediaCodecUtil {
|
|||||||
&& ("OMX.Exynos.AVC.Decoder".equals(name) || "OMX.Exynos.AVC.Decoder.secure".equals(name));
|
&& ("OMX.Exynos.AVC.Decoder".equals(name) || "OMX.Exynos.AVC.Decoder.secure".equals(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Pair<Integer, Integer> getDolbyVisionProfileAndLevel(
|
||||||
|
String codec, String[] parts) {
|
||||||
|
if (parts.length < 3) {
|
||||||
|
// The codec has fewer parts than required by the Dolby Vision codec string format.
|
||||||
|
Log.w(TAG, "Ignoring malformed Dolby Vision codec string: " + codec);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// The profile_space gets ignored.
|
||||||
|
Matcher matcher = PROFILE_PATTERN.matcher(parts[1]);
|
||||||
|
if (!matcher.matches()) {
|
||||||
|
Log.w(TAG, "Ignoring malformed Dolby Vision codec string: " + codec);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String profileString = matcher.group(1);
|
||||||
|
Integer profile = DOLBY_VISION_STRING_TO_PROFILE.get(profileString);
|
||||||
|
if (profile == null) {
|
||||||
|
Log.w(TAG, "Unknown Dolby Vision profile string: " + profileString);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String levelString = parts[2];
|
||||||
|
Integer level = DOLBY_VISION_STRING_TO_LEVEL.get(levelString);
|
||||||
|
if (level == null) {
|
||||||
|
Log.w(TAG, "Unknown Dolby Vision level string: " + levelString);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Pair<>(profile, level);
|
||||||
|
}
|
||||||
|
|
||||||
private static Pair<Integer, Integer> getHevcProfileAndLevel(String codec, String[] parts) {
|
private static Pair<Integer, Integer> getHevcProfileAndLevel(String codec, String[] parts) {
|
||||||
if (parts.length < 4) {
|
if (parts.length < 4) {
|
||||||
// The codec has fewer parts than required by the HEVC codec string format.
|
// The codec has fewer parts than required by the HEVC codec string format.
|
||||||
@ -783,6 +819,29 @@ public final class MediaCodecUtil {
|
|||||||
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("H183", CodecProfileLevel.HEVCHighTierLevel61);
|
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("H183", CodecProfileLevel.HEVCHighTierLevel61);
|
||||||
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("H186", CodecProfileLevel.HEVCHighTierLevel62);
|
HEVC_CODEC_STRING_TO_PROFILE_LEVEL.put("H186", CodecProfileLevel.HEVCHighTierLevel62);
|
||||||
|
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE = new HashMap<>();
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("00", CodecProfileLevel.DolbyVisionProfileDvavPer);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("01", CodecProfileLevel.DolbyVisionProfileDvavPen);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("02", CodecProfileLevel.DolbyVisionProfileDvheDer);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("03", CodecProfileLevel.DolbyVisionProfileDvheDen);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("04", CodecProfileLevel.DolbyVisionProfileDvheDtr);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("05", CodecProfileLevel.DolbyVisionProfileDvheStn);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("06", CodecProfileLevel.DolbyVisionProfileDvheDth);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("07", CodecProfileLevel.DolbyVisionProfileDvheDtb);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("08", CodecProfileLevel.DolbyVisionProfileDvheSt);
|
||||||
|
DOLBY_VISION_STRING_TO_PROFILE.put("09", CodecProfileLevel.DolbyVisionProfileDvavSe);
|
||||||
|
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL = new HashMap<>();
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("01", CodecProfileLevel.DolbyVisionLevelHd24);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("02", CodecProfileLevel.DolbyVisionLevelHd30);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("03", CodecProfileLevel.DolbyVisionLevelFhd24);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("04", CodecProfileLevel.DolbyVisionLevelFhd30);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("05", CodecProfileLevel.DolbyVisionLevelFhd60);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("06", CodecProfileLevel.DolbyVisionLevelUhd24);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("07", CodecProfileLevel.DolbyVisionLevelUhd30);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("08", CodecProfileLevel.DolbyVisionLevelUhd48);
|
||||||
|
DOLBY_VISION_STRING_TO_LEVEL.put("09", CodecProfileLevel.DolbyVisionLevelUhd60);
|
||||||
|
|
||||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE = new SparseIntArray();
|
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE = new SparseIntArray();
|
||||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(1, CodecProfileLevel.AACObjectMain);
|
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(1, CodecProfileLevel.AACObjectMain);
|
||||||
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(2, CodecProfileLevel.AACObjectLC);
|
MP4A_AUDIO_OBJECT_TYPE_TO_PROFILE.put(2, CodecProfileLevel.AACObjectLC);
|
||||||
|
@ -41,6 +41,7 @@ public final class MimeTypes {
|
|||||||
public static final String VIDEO_MPEG = BASE_TYPE_VIDEO + "/mpeg";
|
public static final String VIDEO_MPEG = BASE_TYPE_VIDEO + "/mpeg";
|
||||||
public static final String VIDEO_MPEG2 = BASE_TYPE_VIDEO + "/mpeg2";
|
public static final String VIDEO_MPEG2 = BASE_TYPE_VIDEO + "/mpeg2";
|
||||||
public static final String VIDEO_VC1 = BASE_TYPE_VIDEO + "/wvc1";
|
public static final String VIDEO_VC1 = BASE_TYPE_VIDEO + "/wvc1";
|
||||||
|
public static final String VIDEO_DOLBY_VISION = BASE_TYPE_VIDEO + "/dolby-vision";
|
||||||
public static final String VIDEO_UNKNOWN = BASE_TYPE_VIDEO + "/x-unknown";
|
public static final String VIDEO_UNKNOWN = BASE_TYPE_VIDEO + "/x-unknown";
|
||||||
|
|
||||||
public static final String AUDIO_MP4 = BASE_TYPE_AUDIO + "/mp4";
|
public static final String AUDIO_MP4 = BASE_TYPE_AUDIO + "/mp4";
|
||||||
@ -213,6 +214,11 @@ public final class MimeTypes {
|
|||||||
return MimeTypes.VIDEO_H264;
|
return MimeTypes.VIDEO_H264;
|
||||||
} else if (codec.startsWith("hev1") || codec.startsWith("hvc1")) {
|
} else if (codec.startsWith("hev1") || codec.startsWith("hvc1")) {
|
||||||
return MimeTypes.VIDEO_H265;
|
return MimeTypes.VIDEO_H265;
|
||||||
|
} else if (codec.startsWith("dvav")
|
||||||
|
|| codec.startsWith("dva1")
|
||||||
|
|| codec.startsWith("dvhe")
|
||||||
|
|| codec.startsWith("dvh1")) {
|
||||||
|
return MimeTypes.VIDEO_DOLBY_VISION;
|
||||||
} else if (codec.startsWith("vp9") || codec.startsWith("vp09")) {
|
} else if (codec.startsWith("vp9") || codec.startsWith("vp09")) {
|
||||||
return MimeTypes.VIDEO_VP9;
|
return MimeTypes.VIDEO_VP9;
|
||||||
} else if (codec.startsWith("vp8") || codec.startsWith("vp08")) {
|
} else if (codec.startsWith("vp8") || codec.startsWith("vp08")) {
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.video;
|
||||||
|
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||||
|
|
||||||
|
/** Dolby Vision configuration data. */
|
||||||
|
public final class DolbyVisionConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses Dolby Vision configuration data.
|
||||||
|
*
|
||||||
|
* @param data A {@link ParsableByteArray}, whose position is set to the start of the Dolby Vision
|
||||||
|
* configuration data to parse.
|
||||||
|
* @return The {@link DolbyVisionConfig} corresponding to the configuration, or {@code null} if
|
||||||
|
* the configuration isn't supported.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static DolbyVisionConfig parse(ParsableByteArray data) {
|
||||||
|
data.skipBytes(2); // dv_version_major, dv_version_minor
|
||||||
|
int profileData = data.readUnsignedByte();
|
||||||
|
int dvProfile = (profileData >> 1);
|
||||||
|
int dvLevel = ((profileData & 0x1) << 5) | ((data.readUnsignedByte() >> 3) & 0x1F);
|
||||||
|
String codecsPrefix;
|
||||||
|
if (dvProfile == 4 || dvProfile == 5) {
|
||||||
|
codecsPrefix = "dvhe";
|
||||||
|
} else if (dvProfile == 8) {
|
||||||
|
codecsPrefix = "hev1";
|
||||||
|
} else if (dvProfile == 9) {
|
||||||
|
codecsPrefix = "avc3";
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String codecs = codecsPrefix + ".0" + dvProfile + ".0" + dvLevel;
|
||||||
|
return new DolbyVisionConfig(dvProfile, dvLevel, codecs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The profile number. */
|
||||||
|
public final int profile;
|
||||||
|
/** The level number. */
|
||||||
|
public final int level;
|
||||||
|
/** The RFC 6381 codecs string. */
|
||||||
|
public final String codecs;
|
||||||
|
|
||||||
|
private DolbyVisionConfig(int profile, int level, String codecs) {
|
||||||
|
this.profile = profile;
|
||||||
|
this.level = level;
|
||||||
|
this.codecs = codecs;
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,7 @@ import android.os.SystemClock;
|
|||||||
import android.support.annotation.CallSuper;
|
import android.support.annotation.CallSuper;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
@ -1057,6 +1058,16 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||||||
MediaFormatUtil.maybeSetFloat(mediaFormat, MediaFormat.KEY_FRAME_RATE, format.frameRate);
|
MediaFormatUtil.maybeSetFloat(mediaFormat, MediaFormat.KEY_FRAME_RATE, format.frameRate);
|
||||||
MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_ROTATION, format.rotationDegrees);
|
MediaFormatUtil.maybeSetInteger(mediaFormat, MediaFormat.KEY_ROTATION, format.rotationDegrees);
|
||||||
MediaFormatUtil.maybeSetColorInfo(mediaFormat, format.colorInfo);
|
MediaFormatUtil.maybeSetColorInfo(mediaFormat, format.colorInfo);
|
||||||
|
if (MimeTypes.VIDEO_DOLBY_VISION.equals(format.sampleMimeType)) {
|
||||||
|
// Some phones require the profile to be set on the codec.
|
||||||
|
// See https://github.com/google/ExoPlayer/pull/5438.
|
||||||
|
Pair<Integer, Integer> codecProfileAndLevel =
|
||||||
|
MediaCodecUtil.getCodecProfileAndLevel(format.codecs);
|
||||||
|
if (codecProfileAndLevel != null) {
|
||||||
|
MediaFormatUtil.maybeSetInteger(
|
||||||
|
mediaFormat, MediaFormat.KEY_PROFILE, codecProfileAndLevel.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Set codec max values.
|
// Set codec max values.
|
||||||
mediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, codecMaxValues.width);
|
mediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, codecMaxValues.width);
|
||||||
mediaFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, codecMaxValues.height);
|
mediaFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, codecMaxValues.height);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user