From c59fc4756501496ffcdc45c0c4725aaae2176f7a Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 26 Oct 2015 15:18:53 +0000 Subject: [PATCH] Throw ParserException from parsers when a parse exception occurs. --- .../android/exoplayer/ParserException.java | 4 ++ .../extractor/mp4/FragmentedMp4Extractor.java | 70 ++++++++++++------- .../extractor/webm/DefaultEbmlReader.java | 9 +-- .../extractor/webm/WebmExtractor.java | 7 +- 4 files changed, 56 insertions(+), 34 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/ParserException.java b/library/src/main/java/com/google/android/exoplayer/ParserException.java index ce47f8aa16..d930701be6 100644 --- a/library/src/main/java/com/google/android/exoplayer/ParserException.java +++ b/library/src/main/java/com/google/android/exoplayer/ParserException.java @@ -22,6 +22,10 @@ import java.io.IOException; */ public class ParserException extends IOException { + public ParserException() { + super(); + } + public ParserException(String message) { super(message); } diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java index 996eab4578..092fc30148 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/mp4/FragmentedMp4Extractor.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer.extractor.mp4; import com.google.android.exoplayer.C; +import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.drm.DrmInitData; import com.google.android.exoplayer.extractor.ChunkIndex; import com.google.android.exoplayer.extractor.Extractor; @@ -26,7 +27,6 @@ import com.google.android.exoplayer.extractor.SeekMap; import com.google.android.exoplayer.extractor.TrackOutput; import com.google.android.exoplayer.extractor.mp4.Atom.ContainerAtom; import com.google.android.exoplayer.extractor.mp4.Atom.LeafAtom; -import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.NalUnitUtil; import com.google.android.exoplayer.util.ParsableByteArray; @@ -234,15 +234,15 @@ public final class FragmentedMp4Extractor implements Extractor { } else { // We don't support parsing of leaf atoms that define extended atom sizes, or that have // lengths greater than Integer.MAX_VALUE. - Assertions.checkState(atomHeaderBytesRead == Atom.HEADER_SIZE); - Assertions.checkState(atomSize <= Integer.MAX_VALUE); + checkState(atomHeaderBytesRead == Atom.HEADER_SIZE); + checkState(atomSize <= Integer.MAX_VALUE); atomData = new ParsableByteArray((int) atomSize); System.arraycopy(atomHeader.data, 0, atomData.data, 0, Atom.HEADER_SIZE); parserState = STATE_READING_ATOM_PAYLOAD; } } else { // We don't support skipping of atoms that have lengths greater than Integer.MAX_VALUE. - Assertions.checkState(atomSize <= Integer.MAX_VALUE); + checkState(atomSize <= Integer.MAX_VALUE); atomData = null; parserState = STATE_READING_ATOM_PAYLOAD; } @@ -265,7 +265,7 @@ public final class FragmentedMp4Extractor implements Extractor { enterReadingAtomHeaderState(); } - private void onLeafAtomRead(LeafAtom leaf, long inputPosition) { + private void onLeafAtomRead(LeafAtom leaf, long inputPosition) throws ParserException { if (!containerAtoms.isEmpty()) { containerAtoms.peek().add(leaf); } else if (leaf.type == Atom.TYPE_sidx) { @@ -275,7 +275,7 @@ public final class FragmentedMp4Extractor implements Extractor { } } - private void onContainerAtomRead(ContainerAtom container) { + private void onContainerAtomRead(ContainerAtom container) throws ParserException { if (container.type == Atom.TYPE_moov) { onMoovContainerAtomRead(container); } else if (container.type == Atom.TYPE_moof) { @@ -285,7 +285,7 @@ public final class FragmentedMp4Extractor implements Extractor { } } - private void onMoovContainerAtomRead(ContainerAtom moov) { + private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException { List moovChildren = moov.leafChildren; int moovChildrenSize = moovChildren.size(); @@ -308,16 +308,28 @@ public final class FragmentedMp4Extractor implements Extractor { extendsDefaults = parseTrex(mvex.getLeafAtomOfType(Atom.TYPE_trex).data); track = AtomParsers.parseTrak(moov.getContainerAtomOfType(Atom.TYPE_trak), moov.getLeafAtomOfType(Atom.TYPE_mvhd)); - Assertions.checkState(track != null); + checkState(track != null); trackOutput.format(track.mediaFormat); } - private void onMoofContainerAtomRead(ContainerAtom moof) { + private void onMoofContainerAtomRead(ContainerAtom moof) throws ParserException { fragmentRun.reset(); parseMoof(track, extendsDefaults, moof, fragmentRun, workaroundFlags, extendedTypeScratch); sampleIndex = 0; } + private static void checkState(boolean expression) throws ParserException { + if (!expression) { + throw new ParserException(); + } + } + + private static void checkState(boolean expression, String errorMessage) throws ParserException { + if (!expression) { + throw new ParserException(errorMessage); + } + } + /** * Parses a trex atom (defined in 14496-12). */ @@ -332,9 +344,10 @@ public final class FragmentedMp4Extractor implements Extractor { } private static void parseMoof(Track track, DefaultSampleValues extendsDefaults, - ContainerAtom moof, TrackFragment out, int workaroundFlags, byte[] extendedTypeScratch) { + ContainerAtom moof, TrackFragment out, int workaroundFlags, byte[] extendedTypeScratch) + throws ParserException { // This extractor only supports one traf per moof. - Assertions.checkArgument(1 == moof.getChildAtomOfTypeCount(Atom.TYPE_traf)); + checkState(1 == moof.getChildAtomOfTypeCount(Atom.TYPE_traf)); parseTraf(track, extendsDefaults, moof.getContainerAtomOfType(Atom.TYPE_traf), out, workaroundFlags, extendedTypeScratch); } @@ -343,9 +356,10 @@ public final class FragmentedMp4Extractor implements Extractor { * Parses a traf atom (defined in 14496-12). */ private static void parseTraf(Track track, DefaultSampleValues extendsDefaults, - ContainerAtom traf, TrackFragment out, int workaroundFlags, byte[] extendedTypeScratch) { + ContainerAtom traf, TrackFragment out, int workaroundFlags, byte[] extendedTypeScratch) + throws ParserException { // This extractor only supports one trun per traf. - Assertions.checkArgument(1 == traf.getChildAtomOfTypeCount(Atom.TYPE_trun)); + checkState(1 == traf.getChildAtomOfTypeCount(Atom.TYPE_trun)); LeafAtom tfdtAtom = traf.getLeafAtomOfType(Atom.TYPE_tfdt); long decodeTime; if (tfdtAtom == null || (workaroundFlags & WORKAROUND_IGNORE_TFDT_BOX) != 0) { @@ -387,7 +401,7 @@ public final class FragmentedMp4Extractor implements Extractor { } private static void parseSaiz(TrackEncryptionBox encryptionBox, ParsableByteArray saiz, - TrackFragment out) { + TrackFragment out) throws ParserException { int vectorSize = encryptionBox.initializationVectorSize; saiz.setPosition(Atom.HEADER_SIZE); int fullAtom = saiz.readInt(); @@ -399,7 +413,7 @@ public final class FragmentedMp4Extractor implements Extractor { int sampleCount = saiz.readUnsignedIntToInt(); if (sampleCount != out.length) { - throw new IllegalStateException("Length mismatch: " + sampleCount + ", " + out.length); + throw new ParserException("Length mismatch: " + sampleCount + ", " + out.length); } int totalSize = 0; @@ -424,7 +438,7 @@ public final class FragmentedMp4Extractor implements Extractor { * @param saio The saio atom to parse. * @param out The track fragment to populate with data from the saio atom. */ - private static void parseSaio(ParsableByteArray saio, TrackFragment out) { + private static void parseSaio(ParsableByteArray saio, TrackFragment out) throws ParserException { saio.setPosition(Atom.HEADER_SIZE); int fullAtom = saio.readInt(); int flags = Atom.parseFullAtomFlags(fullAtom); @@ -435,7 +449,7 @@ public final class FragmentedMp4Extractor implements Extractor { int entryCount = saio.readUnsignedIntToInt(); if (entryCount != 1) { // We only support one trun element currently, so always expect one entry. - throw new IllegalStateException("Unexpected saio entry count: " + entryCount); + throw new ParserException("Unexpected saio entry count: " + entryCount); } int version = Atom.parseFullAtomVersion(fullAtom); @@ -558,7 +572,7 @@ public final class FragmentedMp4Extractor implements Extractor { } private static void parseUuid(ParsableByteArray uuid, TrackFragment out, - byte[] extendedTypeScratch) { + byte[] extendedTypeScratch) throws ParserException { uuid.setPosition(Atom.HEADER_SIZE); uuid.readBytes(extendedTypeScratch, 0, 16); @@ -573,24 +587,25 @@ public final class FragmentedMp4Extractor implements Extractor { parseSenc(uuid, 16, out); } - private static void parseSenc(ParsableByteArray senc, TrackFragment out) { + private static void parseSenc(ParsableByteArray senc, TrackFragment out) throws ParserException { parseSenc(senc, 0, out); } - private static void parseSenc(ParsableByteArray senc, int offset, TrackFragment out) { + private static void parseSenc(ParsableByteArray senc, int offset, TrackFragment out) + throws ParserException { senc.setPosition(Atom.HEADER_SIZE + offset); int fullAtom = senc.readInt(); int flags = Atom.parseFullAtomFlags(fullAtom); if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) { // TODO: Implement this. - throw new IllegalStateException("Overriding TrackEncryptionBox parameters is unsupported"); + throw new ParserException("Overriding TrackEncryptionBox parameters is unsupported."); } boolean subsampleEncryption = (flags & 0x02 /* use_subsample_encryption */) != 0; int sampleCount = senc.readUnsignedIntToInt(); if (sampleCount != out.length) { - throw new IllegalStateException("Length mismatch: " + sampleCount + ", " + out.length); + throw new ParserException("Length mismatch: " + sampleCount + ", " + out.length); } Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption); @@ -601,7 +616,8 @@ public final class FragmentedMp4Extractor implements Extractor { /** * Parses a sidx atom (defined in 14496-12). */ - private static ChunkIndex parseSidx(ParsableByteArray atom, long inputPosition) { + private static ChunkIndex parseSidx(ParsableByteArray atom, long inputPosition) + throws ParserException { atom.setPosition(Atom.HEADER_SIZE); int fullAtom = atom.readInt(); int version = Atom.parseFullAtomVersion(fullAtom); @@ -633,7 +649,7 @@ public final class FragmentedMp4Extractor implements Extractor { int type = 0x80000000 & firstInt; if (type != 0) { - throw new IllegalStateException("Unhandled indirect reference"); + throw new ParserException("Unhandled indirect reference"); } long referenceDuration = atom.readUnsignedInt(); @@ -656,7 +672,7 @@ public final class FragmentedMp4Extractor implements Extractor { private void readEncryptionData(ExtractorInput input) throws IOException, InterruptedException { int bytesToSkip = (int) (fragmentRun.auxiliaryDataPosition - input.getPosition()); - Assertions.checkState(bytesToSkip >= 0, "Offset to encryption data was negative."); + checkState(bytesToSkip >= 0, "Offset to encryption data was negative."); input.skipFully(bytesToSkip); fragmentRun.fillEncryptionData(input); parserState = STATE_READING_SAMPLE_START; @@ -679,13 +695,13 @@ public final class FragmentedMp4Extractor implements Extractor { private boolean readSample(ExtractorInput input) throws IOException, InterruptedException { if (sampleIndex == 0) { int bytesToSkip = (int) (fragmentRun.dataPosition - input.getPosition()); - Assertions.checkState(bytesToSkip >= 0, "Offset to sample data was negative."); + checkState(bytesToSkip >= 0, "Offset to sample data was negative."); input.skipFully(bytesToSkip); } if (sampleIndex >= fragmentRun.length) { int bytesToSkip = (int) (endOfMdatPosition - input.getPosition()); - Assertions.checkState(bytesToSkip >= 0, "Offset to end of mdat was negative."); + checkState(bytesToSkip >= 0, "Offset to end of mdat was negative."); input.skipFully(bytesToSkip); // We've run out of samples in the current mdat atom. enterReadingAtomHeaderState(); diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/webm/DefaultEbmlReader.java b/library/src/main/java/com/google/android/exoplayer/extractor/webm/DefaultEbmlReader.java index 71326412e6..1b73b5dfd2 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/webm/DefaultEbmlReader.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/webm/DefaultEbmlReader.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer.extractor.webm; import com.google.android.exoplayer.C; +import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.extractor.ExtractorInput; import com.google.android.exoplayer.util.Assertions; @@ -100,7 +101,7 @@ import java.util.Stack; return true; case TYPE_UNSIGNED_INT: if (elementContentSize > MAX_INTEGER_ELEMENT_SIZE_BYTES) { - throw new IllegalStateException("Invalid integer size: " + elementContentSize); + throw new ParserException("Invalid integer size: " + elementContentSize); } output.integerElement(elementId, readInteger(input, (int) elementContentSize)); elementState = ELEMENT_STATE_READ_ID; @@ -108,14 +109,14 @@ import java.util.Stack; case TYPE_FLOAT: if (elementContentSize != VALID_FLOAT32_ELEMENT_SIZE_BYTES && elementContentSize != VALID_FLOAT64_ELEMENT_SIZE_BYTES) { - throw new IllegalStateException("Invalid float size: " + elementContentSize); + throw new ParserException("Invalid float size: " + elementContentSize); } output.floatElement(elementId, readFloat(input, (int) elementContentSize)); elementState = ELEMENT_STATE_READ_ID; return true; case TYPE_STRING: if (elementContentSize > Integer.MAX_VALUE) { - throw new IllegalStateException("String element size: " + elementContentSize); + throw new ParserException("String element size: " + elementContentSize); } output.stringElement(elementId, readString(input, (int) elementContentSize)); elementState = ELEMENT_STATE_READ_ID; @@ -129,7 +130,7 @@ import java.util.Stack; elementState = ELEMENT_STATE_READ_ID; break; default: - throw new IllegalStateException("Invalid element type " + type); + throw new ParserException("Invalid element type " + type); } } } diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java index 58d85370ee..38ce691844 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/webm/WebmExtractor.java @@ -26,7 +26,6 @@ import com.google.android.exoplayer.extractor.ExtractorOutput; import com.google.android.exoplayer.extractor.PositionHolder; import com.google.android.exoplayer.extractor.SeekMap; import com.google.android.exoplayer.extractor.TrackOutput; -import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.LongArray; import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.NalUnitUtil; @@ -738,7 +737,7 @@ public final class WebmExtractor implements Extractor { contentSize - blockTrackNumberLength - headerSize - totalSamplesSize; } else { // Lacing is always in the range 0--3. - throw new IllegalStateException("Unexpected lacing value: " + lacing); + throw new ParserException("Unexpected lacing value: " + lacing); } } @@ -1257,7 +1256,9 @@ public final class WebmExtractor implements Extractor { // TODO: Deduplicate with AtomParsers.parseAvcCFromParent. buffer.setPosition(4); int nalUnitLengthFieldLength = (buffer.readUnsignedByte() & 0x03) + 1; - Assertions.checkState(nalUnitLengthFieldLength != 3); + if (nalUnitLengthFieldLength == 3) { + throw new ParserException(); + } List initializationData = new ArrayList<>(); int numSequenceParameterSets = buffer.readUnsignedByte() & 0x1F; for (int i = 0; i < numSequenceParameterSets; i++) {