diff --git a/library/core/src/androidTest/assets/mp4/sample_fragmented_zero_size_atom.mp4 b/library/core/src/androidTest/assets/mp4/sample_fragmented_zero_size_atom.mp4 deleted file mode 100644 index 3d3c63786e..0000000000 Binary files a/library/core/src/androidTest/assets/mp4/sample_fragmented_zero_size_atom.mp4 and /dev/null differ diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java index 76c13495c1..c9364aa605 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4ExtractorTest.java @@ -16,7 +16,6 @@ package com.google.android.exoplayer2.extractor.mp4; import android.test.InstrumentationTestCase; -import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.testutil.ExtractorAsserts; import com.google.android.exoplayer2.testutil.ExtractorAsserts.ExtractorFactory; @@ -38,11 +37,6 @@ public final class FragmentedMp4ExtractorTest extends InstrumentationTestCase { "mp4/sample_fragmented_sei.mp4", getInstrumentation()); } - public void testAtomWithZeroSize() throws Exception { - ExtractorAsserts.assertThrows(getExtractorFactory(), "mp4/sample_fragmented_zero_size_atom.mp4", - getInstrumentation(), ParserException.class); - } - private static ExtractorFactory getExtractorFactory() { return getExtractorFactory(0); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java index cc7e662336..21d861af30 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java @@ -39,9 +39,14 @@ import java.util.List; public static final int LONG_HEADER_SIZE = 16; /** - * Value for the first 32 bits of atomSize when the atom size is actually a long value. + * Value for the size field in an atom that defines its size in the largesize field. */ - public static final int LONG_SIZE_PREFIX = 1; + public static final int DEFINES_LARGE_SIZE = 1; + + /** + * Value for the size field in an atom that extends to the end of the file. + */ + public static final int EXTENDS_TO_END_SIZE = 0; public static final int TYPE_ftyp = Util.getIntegerCodeForString("ftyp"); public static final int TYPE_avc1 = Util.getIntegerCodeForString("avc1"); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index 6b2077ef76..c3f2a9fb38 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -283,12 +283,22 @@ public final class FragmentedMp4Extractor implements Extractor { atomType = atomHeader.readInt(); } - if (atomSize == Atom.LONG_SIZE_PREFIX) { - // Read the extended atom size. + if (atomSize == Atom.DEFINES_LARGE_SIZE) { + // Read the large size. int headerBytesRemaining = Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE; input.readFully(atomHeader.data, Atom.HEADER_SIZE, headerBytesRemaining); atomHeaderBytesRead += headerBytesRemaining; atomSize = atomHeader.readUnsignedLongToLong(); + } else if (atomSize == Atom.EXTENDS_TO_END_SIZE) { + // The atom extends to the end of the file. Note that if the atom is within a container we can + // work out its size even if the input length is unknown. + long endPosition = input.getLength(); + if (endPosition == C.LENGTH_UNSET && !containerAtoms.isEmpty()) { + endPosition = containerAtoms.peek().endPosition; + } + if (endPosition != C.LENGTH_UNSET) { + atomSize = endPosition - input.getPosition() + atomHeaderBytesRead; + } } if (atomSize < atomHeaderBytesRead) { 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 d0e770abdc..d3fe9e0d05 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 @@ -205,12 +205,26 @@ public final class Mp4Extractor implements Extractor, SeekMap { atomType = atomHeader.readInt(); } - if (atomSize == Atom.LONG_SIZE_PREFIX) { - // Read the extended atom size. + if (atomSize == Atom.DEFINES_LARGE_SIZE) { + // Read the large size. int headerBytesRemaining = Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE; input.readFully(atomHeader.data, Atom.HEADER_SIZE, headerBytesRemaining); atomHeaderBytesRead += headerBytesRemaining; atomSize = atomHeader.readUnsignedLongToLong(); + } else if (atomSize == Atom.EXTENDS_TO_END_SIZE) { + // The atom extends to the end of the file. Note that if the atom is within a container we can + // work out its size even if the input length is unknown. + long endPosition = input.getLength(); + if (endPosition == C.LENGTH_UNSET && !containerAtoms.isEmpty()) { + endPosition = containerAtoms.peek().endPosition; + } + if (endPosition != C.LENGTH_UNSET) { + atomSize = endPosition - input.getPosition() + atomHeaderBytesRead; + } + } + + if (atomSize < atomHeaderBytesRead) { + throw new ParserException("Atom size less than header length (unsupported)."); } if (shouldParseContainerAtom(atomType)) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java index 44d5824945..021c9de654 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java @@ -104,11 +104,18 @@ import java.io.IOException; input.peekFully(buffer.data, 0, headerSize); long atomSize = buffer.readUnsignedInt(); int atomType = buffer.readInt(); - if (atomSize == Atom.LONG_SIZE_PREFIX) { + if (atomSize == Atom.DEFINES_LARGE_SIZE) { + // Read the large atom size. headerSize = Atom.LONG_HEADER_SIZE; input.peekFully(buffer.data, Atom.HEADER_SIZE, Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE); buffer.setLimit(Atom.LONG_HEADER_SIZE); atomSize = buffer.readUnsignedLongToLong(); + } else if (atomSize == Atom.EXTENDS_TO_END_SIZE) { + // The atom extends to the end of the file. + long endPosition = input.getLength(); + if (endPosition != C.LENGTH_UNSET) { + atomSize = endPosition - input.getPosition() + headerSize; + } } if (atomSize < headerSize) {