diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 924c38b1ba..ae2901d2be 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -96,6 +96,9 @@ * Use full BCP 47 language tags in `Format`. * Take byte offset into account when unsynchronizing an id3 frame ([#5673](https://github.com/google/ExoPlayer/issues/5673)). +* Handle meta atom as a full box when parsing mp4 + ([#5698](https://github.com/google/ExoPlayer/issues/5698), + [#5694](https://github.com/google/ExoPlayer/issues/5694)). ### 2.9.6 ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java index 60613cf818..75966bff66 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java @@ -309,6 +309,9 @@ public final class Mp4Extractor implements Extractor, SeekMap { if (atomSize == atomHeaderBytesRead) { processAtomEnded(endPosition); } else { + if (atomType == Atom.TYPE_meta) { + maybeSkipRemainingMetaAtomHeaderBytes(input); + } // Start reading the first child atom. enterReadingAtomHeaderState(); } @@ -643,6 +646,32 @@ public final class Mp4Extractor implements Extractor, SeekMap { } } + /** + * Possibly skips the version and flags fields (1+3 byte) of a full meta atom of the {@code + * input}. + * + *
Atoms of type {@link Atom#TYPE_meta} are defined to be full atoms which have four additional + * bytes for a version and a flags field (see 4.2 'Object Structure' in ISO/IEC 14496-12:2005). + * QuickTime do not have such a full box structure. Since some of these files are encoded wrongly, + * we can't rely on the file type though. Instead we must check the 8 bytes after the common + * header bytes ourselves. + */ + private void maybeSkipRemainingMetaAtomHeaderBytes(ExtractorInput input) + throws IOException, InterruptedException { + scratch.reset(8); + // Peek the next 8 bytes which can be either + // (iso) [1 byte version + 3 bytes flags][4 byte size of next atom] + // (qt) [4 byte size of next atom ][4 byte hdlr atom type ] + // In case of (iso) we need to skip the next 4 bytes. + input.peekFully(scratch.data, 0, 8); + scratch.skipBytes(4); + if (scratch.readInt() == Atom.TYPE_hdlr) { + input.resetPeekPosition(); + } else { + input.skipFully(4); + } + } + /** * For each sample of each track, calculates accumulated size of all samples which need to be read * before this sample can be used.