diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java index 3cde946ce3..45e094f69d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H264Reader.java @@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator; +import com.google.android.exoplayer2.util.CodecSpecificDataUtil; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.NalUnitUtil; import com.google.android.exoplayer2.util.NalUnitUtil.SpsData; @@ -180,9 +181,23 @@ public final class H264Reader implements ElementaryStreamReader { initializationData.add(Arrays.copyOf(pps.nalData, pps.nalLength)); NalUnitUtil.SpsData spsData = NalUnitUtil.parseSpsNalUnit(sps.nalData, 3, sps.nalLength); NalUnitUtil.PpsData ppsData = NalUnitUtil.parsePpsNalUnit(pps.nalData, 3, pps.nalLength); - output.format(Format.createVideoSampleFormat(formatId, MimeTypes.VIDEO_H264, null, - Format.NO_VALUE, Format.NO_VALUE, spsData.width, spsData.height, Format.NO_VALUE, - initializationData, Format.NO_VALUE, spsData.pixelWidthAspectRatio, null)); + output.format( + Format.createVideoSampleFormat( + formatId, + MimeTypes.VIDEO_H264, + CodecSpecificDataUtil.buildAvcCodecString( + spsData.profileIdc, + spsData.constraintsFlagsAndReservedZero2Bits, + spsData.levelIdc), + /* bitrate= */ Format.NO_VALUE, + /* maxInputSize= */ Format.NO_VALUE, + spsData.width, + spsData.height, + /* frameRate= */ Format.NO_VALUE, + initializationData, + /* rotationDegrees= */ Format.NO_VALUE, + spsData.pixelWidthAspectRatio, + /* drmInitData= */ null)); hasOutputFormat = true; sampleReader.putSps(spsData); sampleReader.putPps(ppsData); 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 a78105c0bd..817a6b0f68 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 @@ -674,6 +674,9 @@ public final class MediaCodecUtil { AVC_PROFILE_NUMBER_TO_CONST.put(77, CodecProfileLevel.AVCProfileMain); AVC_PROFILE_NUMBER_TO_CONST.put(88, CodecProfileLevel.AVCProfileExtended); AVC_PROFILE_NUMBER_TO_CONST.put(100, CodecProfileLevel.AVCProfileHigh); + AVC_PROFILE_NUMBER_TO_CONST.put(110, CodecProfileLevel.AVCProfileHigh10); + AVC_PROFILE_NUMBER_TO_CONST.put(122, CodecProfileLevel.AVCProfileHigh422); + AVC_PROFILE_NUMBER_TO_CONST.put(244, CodecProfileLevel.AVCProfileHigh444); AVC_LEVEL_NUMBER_TO_CONST = new SparseIntArray(); AVC_LEVEL_NUMBER_TO_CONST.put(10, CodecProfileLevel.AVCLevel1); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java index e1ffa1024d..627cf7e070 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/CodecSpecificDataUtil.java @@ -205,6 +205,21 @@ public final class CodecSpecificDataUtil { return specificConfig; } + /** + * Builds an RFC 6381 AVC codec string using the provided parameters. + * + * @param profileIdc The encoding profile. + * @param constraintsFlagsAndReservedZero2Bits The constraint flags followed by the reserved zero + * 2 bits, all contained in the least significant byte of the integer. + * @param levelIdc The encoding level. + * @return An RFC 6381 AVC codec string built using the provided parameters. + */ + public static String buildAvcCodecString( + int profileIdc, int constraintsFlagsAndReservedZero2Bits, int levelIdc) { + return String.format( + "avc1.%02X%02X%02X", profileIdc, constraintsFlagsAndReservedZero2Bits, levelIdc); + } + /** * Constructs a NAL unit consisting of the NAL start code followed by the specified data. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java index c4ed20546d..b3fbe43194 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java @@ -31,6 +31,9 @@ public final class NalUnitUtil { */ public static final class SpsData { + public final int profileIdc; + public final int constraintsFlagsAndReservedZero2Bits; + public final int levelIdc; public final int seqParameterSetId; public final int width; public final int height; @@ -42,9 +45,23 @@ public final class NalUnitUtil { public final int picOrderCntLsbLength; public final boolean deltaPicOrderAlwaysZeroFlag; - public SpsData(int seqParameterSetId, int width, int height, float pixelWidthAspectRatio, - boolean separateColorPlaneFlag, boolean frameMbsOnlyFlag, int frameNumLength, - int picOrderCountType, int picOrderCntLsbLength, boolean deltaPicOrderAlwaysZeroFlag) { + public SpsData( + int profileIdc, + int constraintsFlagsAndReservedZero2Bits, + int levelIdc, + int seqParameterSetId, + int width, + int height, + float pixelWidthAspectRatio, + boolean separateColorPlaneFlag, + boolean frameMbsOnlyFlag, + int frameNumLength, + int picOrderCountType, + int picOrderCntLsbLength, + boolean deltaPicOrderAlwaysZeroFlag) { + this.profileIdc = profileIdc; + this.constraintsFlagsAndReservedZero2Bits = constraintsFlagsAndReservedZero2Bits; + this.levelIdc = levelIdc; this.seqParameterSetId = seqParameterSetId; this.width = width; this.height = height; @@ -251,7 +268,8 @@ public final class NalUnitUtil { ParsableNalUnitBitArray data = new ParsableNalUnitBitArray(nalData, nalOffset, nalLimit); data.skipBits(8); // nal_unit int profileIdc = data.readBits(8); - data.skipBits(16); // constraint bits (6), reserved (2) and level_idc (8) + int constraintsFlagsAndReservedZero2Bits = data.readBits(8); + int levelIdc = data.readBits(8); int seqParameterSetId = data.readUnsignedExpGolombCodedInt(); int chromaFormatIdc = 1; // Default is 4:2:0 @@ -349,9 +367,20 @@ public final class NalUnitUtil { } } - return new SpsData(seqParameterSetId, frameWidth, frameHeight, pixelWidthHeightRatio, - separateColorPlaneFlag, frameMbsOnlyFlag, frameNumLength, picOrderCntType, - picOrderCntLsbLength, deltaPicOrderAlwaysZeroFlag); + return new SpsData( + profileIdc, + constraintsFlagsAndReservedZero2Bits, + levelIdc, + seqParameterSetId, + frameWidth, + frameHeight, + pixelWidthHeightRatio, + separateColorPlaneFlag, + frameMbsOnlyFlag, + frameNumLength, + picOrderCntType, + picOrderCntLsbLength, + deltaPicOrderAlwaysZeroFlag); } /**