From 78a975c268809b847ddd0aa938ddcf19e4c6837b Mon Sep 17 00:00:00 2001 From: Alexey Rochev Date: Thu, 24 Dec 2020 16:22:25 +0300 Subject: [PATCH] Initialize Format.codecs from AVC SPS NAL unit (#8393) This will allow ExoPlayer to check if video track's profile and level are supported by decoder when playing progressive media sources. Also fix typo in AvcConfig. --- .../google/android/exoplayer2/video/AvcConfig.java | 12 +++++++++--- .../extractor/flv/VideoTagPayloadReader.java | 1 + .../exoplayer2/extractor/mkv/MatroskaExtractor.java | 1 + .../exoplayer2/extractor/mp4/AtomParsers.java | 1 + 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java b/library/common/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java index b794d2db90..7f963ea5a5 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/video/AvcConfig.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.video; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.util.CodecSpecificDataUtil; @@ -34,13 +35,14 @@ public final class AvcConfig { public final int width; public final int height; public final float pixelWidthAspectRatio; + @Nullable public final String codecs; /** * Parses AVC configuration data. * * @param data A {@link ParsableByteArray}, whose position is set to the start of the AVC * configuration data to parse. - * @return A parsed representation of the HEVC configuration data. + * @return A parsed representation of the AVC configuration data. * @throws ParserException If an error occurred parsing the data. */ public static AvcConfig parse(ParsableByteArray data) throws ParserException { @@ -63,6 +65,7 @@ public final class AvcConfig { int width = Format.NO_VALUE; int height = Format.NO_VALUE; float pixelWidthAspectRatio = 1; + @Nullable String codecs = null; if (numSequenceParameterSets > 0) { byte[] sps = initializationData.get(0); SpsData spsData = NalUnitUtil.parseSpsNalUnit(initializationData.get(0), @@ -70,21 +73,24 @@ public final class AvcConfig { width = spsData.width; height = spsData.height; pixelWidthAspectRatio = spsData.pixelWidthAspectRatio; + codecs = CodecSpecificDataUtil.buildAvcCodecString(spsData.profileIdc, spsData.constraintsFlagsAndReservedZero2Bits, spsData.levelIdc); } + return new AvcConfig(initializationData, nalUnitLengthFieldLength, width, height, - pixelWidthAspectRatio); + pixelWidthAspectRatio, codecs); } catch (ArrayIndexOutOfBoundsException e) { throw new ParserException("Error parsing AVC config", e); } } private AvcConfig(List initializationData, int nalUnitLengthFieldLength, - int width, int height, float pixelWidthAspectRatio) { + int width, int height, float pixelWidthAspectRatio, @Nullable String codecs) { this.initializationData = initializationData; this.nalUnitLengthFieldLength = nalUnitLengthFieldLength; this.width = width; this.height = height; this.pixelWidthAspectRatio = pixelWidthAspectRatio; + this.codecs = codecs; } private static byte[] buildNalUnitForChild(ParsableByteArray data) { diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java index c91f6ce037..6ab4da1acf 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/VideoTagPayloadReader.java @@ -93,6 +93,7 @@ import com.google.android.exoplayer2.video.AvcConfig; Format format = new Format.Builder() .setSampleMimeType(MimeTypes.VIDEO_H264) + .setCodecs(avcConfig.codecs) .setWidth(avcConfig.width) .setHeight(avcConfig.height) .setPixelWidthHeightRatio(avcConfig.pixelWidthAspectRatio) diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 733d10e767..568385ad3b 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -2086,6 +2086,7 @@ public class MatroskaExtractor implements Extractor { AvcConfig avcConfig = AvcConfig.parse(new ParsableByteArray(getCodecPrivate(codecId))); initializationData = avcConfig.initializationData; nalUnitLengthFieldLength = avcConfig.nalUnitLengthFieldLength; + codecs = avcConfig.codecs; break; case CODEC_ID_H265: mimeType = MimeTypes.VIDEO_H265; diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 2ff749db75..9d285fe8dc 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -1058,6 +1058,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; if (!pixelWidthHeightRatioFromPasp) { pixelWidthHeightRatio = avcConfig.pixelWidthAspectRatio; } + codecs = avcConfig.codecs; } else if (childAtomType == Atom.TYPE_hvcC) { Assertions.checkState(mimeType == null); mimeType = MimeTypes.VIDEO_H265;