diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 50b7bb0f99..840876c749 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -106,6 +106,8 @@ * Populate codecs string for H.265/HEVC in MP4, Matroska and MPEG-TS streams to allow decoder capability checks based on codec profile/level ([#8393](https://github.com/google/ExoPlayer/issues/8393)). + * Handle sample size mismatches between raw audio PCM encoding and `stsz` + sample size in MP4 extractors. * Track selection: * Allow parallel adaptation for video and audio ([#5111](https://github.com/google/ExoPlayer/issues/5111)). diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java index c4af6bd2fc..43a13ed1e8 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -1673,6 +1673,31 @@ public final class Util { } } + /** + * Returns the sample size for audio in the specified encoding. + * + * @param pcmEncoding The encoding of the audio data. + * @return The size of one audio sample in bytes. + */ + public static int getPcmSampleSize(@C.PcmEncoding int pcmEncoding) { + switch (pcmEncoding) { + case C.ENCODING_PCM_8BIT: + return 1; + case C.ENCODING_PCM_16BIT: + case C.ENCODING_PCM_16BIT_BIG_ENDIAN: + return 2; + case C.ENCODING_PCM_24BIT: + return 3; + case C.ENCODING_PCM_32BIT: + case C.ENCODING_PCM_FLOAT: + return 4; + case C.ENCODING_INVALID: + case Format.NO_VALUE: + default: + throw new IllegalArgumentException(); + } + } + /** * Returns the frame size for audio with {@code channelCount} channels in the specified encoding. * @@ -1681,22 +1706,7 @@ public final class Util { * @return The size of one audio frame in bytes. */ public static int getPcmFrameSize(@C.PcmEncoding int pcmEncoding, int channelCount) { - switch (pcmEncoding) { - case C.ENCODING_PCM_8BIT: - return channelCount; - case C.ENCODING_PCM_16BIT: - case C.ENCODING_PCM_16BIT_BIG_ENDIAN: - return channelCount * 2; - case C.ENCODING_PCM_24BIT: - return channelCount * 3; - case C.ENCODING_PCM_32BIT: - case C.ENCODING_PCM_FLOAT: - return channelCount * 4; - case C.ENCODING_INVALID: - case Format.NO_VALUE: - default: - throw new IllegalArgumentException(); - } + return getPcmSampleSize(pcmEncoding) * channelCount; } /** 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 ff63798583..488dcec0bc 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 @@ -315,7 +315,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; SampleSizeBox sampleSizeBox; @Nullable Atom.LeafAtom stszAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stsz); if (stszAtom != null) { - sampleSizeBox = new StszSampleSizeBox(stszAtom); + sampleSizeBox = new StszSampleSizeBox(stszAtom, track.format); } else { @Nullable Atom.LeafAtom stz2Atom = stblAtom.getLeafAtomOfType(Atom.TYPE_stz2); if (stz2Atom == null) { @@ -1720,10 +1720,25 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private final int sampleCount; private final ParsableByteArray data; - public StszSampleSizeBox(Atom.LeafAtom stszAtom) { + public StszSampleSizeBox(Atom.LeafAtom stszAtom, Format trackFormat) { data = stszAtom.data; data.setPosition(Atom.FULL_HEADER_SIZE); int fixedSampleSize = data.readUnsignedIntToInt(); + if (MimeTypes.AUDIO_RAW.equals(trackFormat.sampleMimeType)) { + @C.PcmEncoding int pcmEncoding = trackFormat.pcmEncoding; + int pcmSampleSize = Util.getPcmSampleSize(pcmEncoding); + if (pcmSampleSize != fixedSampleSize) { + // The sample size from the stsz box is inconsistent with the PCM encoding derived from + // the stsd box. Choose the PCM encoding as source of truth [Internal ref: b/171627904]. + Log.w( + TAG, + "Audio sample size mismatch. PCM encoding: " + + pcmEncoding + + ", stsz sample size = " + + fixedSampleSize); + fixedSampleSize = pcmSampleSize; + } + } this.fixedSampleSize = fixedSampleSize == 0 ? C.LENGTH_UNSET : fixedSampleSize; sampleCount = data.readUnsignedIntToInt(); }