Throw ParserException from parsers when a parse exception occurs.

This commit is contained in:
Oliver Woodman 2015-10-26 15:18:53 +00:00
parent 13aaa5a5db
commit c59fc47565
4 changed files with 56 additions and 34 deletions

View File

@ -22,6 +22,10 @@ import java.io.IOException;
*/ */
public class ParserException extends IOException { public class ParserException extends IOException {
public ParserException() {
super();
}
public ParserException(String message) { public ParserException(String message) {
super(message); super(message);
} }

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer.extractor.mp4; package com.google.android.exoplayer.extractor.mp4;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.drm.DrmInitData; import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.extractor.ChunkIndex; import com.google.android.exoplayer.extractor.ChunkIndex;
import com.google.android.exoplayer.extractor.Extractor; 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.TrackOutput;
import com.google.android.exoplayer.extractor.mp4.Atom.ContainerAtom; import com.google.android.exoplayer.extractor.mp4.Atom.ContainerAtom;
import com.google.android.exoplayer.extractor.mp4.Atom.LeafAtom; 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.MimeTypes;
import com.google.android.exoplayer.util.NalUnitUtil; import com.google.android.exoplayer.util.NalUnitUtil;
import com.google.android.exoplayer.util.ParsableByteArray; import com.google.android.exoplayer.util.ParsableByteArray;
@ -234,15 +234,15 @@ public final class FragmentedMp4Extractor implements Extractor {
} else { } else {
// We don't support parsing of leaf atoms that define extended atom sizes, or that have // We don't support parsing of leaf atoms that define extended atom sizes, or that have
// lengths greater than Integer.MAX_VALUE. // lengths greater than Integer.MAX_VALUE.
Assertions.checkState(atomHeaderBytesRead == Atom.HEADER_SIZE); checkState(atomHeaderBytesRead == Atom.HEADER_SIZE);
Assertions.checkState(atomSize <= Integer.MAX_VALUE); checkState(atomSize <= Integer.MAX_VALUE);
atomData = new ParsableByteArray((int) atomSize); atomData = new ParsableByteArray((int) atomSize);
System.arraycopy(atomHeader.data, 0, atomData.data, 0, Atom.HEADER_SIZE); System.arraycopy(atomHeader.data, 0, atomData.data, 0, Atom.HEADER_SIZE);
parserState = STATE_READING_ATOM_PAYLOAD; parserState = STATE_READING_ATOM_PAYLOAD;
} }
} else { } else {
// We don't support skipping of atoms that have lengths greater than Integer.MAX_VALUE. // 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; atomData = null;
parserState = STATE_READING_ATOM_PAYLOAD; parserState = STATE_READING_ATOM_PAYLOAD;
} }
@ -265,7 +265,7 @@ public final class FragmentedMp4Extractor implements Extractor {
enterReadingAtomHeaderState(); enterReadingAtomHeaderState();
} }
private void onLeafAtomRead(LeafAtom leaf, long inputPosition) { private void onLeafAtomRead(LeafAtom leaf, long inputPosition) throws ParserException {
if (!containerAtoms.isEmpty()) { if (!containerAtoms.isEmpty()) {
containerAtoms.peek().add(leaf); containerAtoms.peek().add(leaf);
} else if (leaf.type == Atom.TYPE_sidx) { } 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) { if (container.type == Atom.TYPE_moov) {
onMoovContainerAtomRead(container); onMoovContainerAtomRead(container);
} else if (container.type == Atom.TYPE_moof) { } 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<Atom.LeafAtom> moovChildren = moov.leafChildren; List<Atom.LeafAtom> moovChildren = moov.leafChildren;
int moovChildrenSize = moovChildren.size(); int moovChildrenSize = moovChildren.size();
@ -308,16 +308,28 @@ public final class FragmentedMp4Extractor implements Extractor {
extendsDefaults = parseTrex(mvex.getLeafAtomOfType(Atom.TYPE_trex).data); extendsDefaults = parseTrex(mvex.getLeafAtomOfType(Atom.TYPE_trex).data);
track = AtomParsers.parseTrak(moov.getContainerAtomOfType(Atom.TYPE_trak), track = AtomParsers.parseTrak(moov.getContainerAtomOfType(Atom.TYPE_trak),
moov.getLeafAtomOfType(Atom.TYPE_mvhd)); moov.getLeafAtomOfType(Atom.TYPE_mvhd));
Assertions.checkState(track != null); checkState(track != null);
trackOutput.format(track.mediaFormat); trackOutput.format(track.mediaFormat);
} }
private void onMoofContainerAtomRead(ContainerAtom moof) { private void onMoofContainerAtomRead(ContainerAtom moof) throws ParserException {
fragmentRun.reset(); fragmentRun.reset();
parseMoof(track, extendsDefaults, moof, fragmentRun, workaroundFlags, extendedTypeScratch); parseMoof(track, extendsDefaults, moof, fragmentRun, workaroundFlags, extendedTypeScratch);
sampleIndex = 0; 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). * 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, 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. // 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), parseTraf(track, extendsDefaults, moof.getContainerAtomOfType(Atom.TYPE_traf),
out, workaroundFlags, extendedTypeScratch); out, workaroundFlags, extendedTypeScratch);
} }
@ -343,9 +356,10 @@ public final class FragmentedMp4Extractor implements Extractor {
* Parses a traf atom (defined in 14496-12). * Parses a traf atom (defined in 14496-12).
*/ */
private static void parseTraf(Track track, DefaultSampleValues extendsDefaults, 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. // 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); LeafAtom tfdtAtom = traf.getLeafAtomOfType(Atom.TYPE_tfdt);
long decodeTime; long decodeTime;
if (tfdtAtom == null || (workaroundFlags & WORKAROUND_IGNORE_TFDT_BOX) != 0) { 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, private static void parseSaiz(TrackEncryptionBox encryptionBox, ParsableByteArray saiz,
TrackFragment out) { TrackFragment out) throws ParserException {
int vectorSize = encryptionBox.initializationVectorSize; int vectorSize = encryptionBox.initializationVectorSize;
saiz.setPosition(Atom.HEADER_SIZE); saiz.setPosition(Atom.HEADER_SIZE);
int fullAtom = saiz.readInt(); int fullAtom = saiz.readInt();
@ -399,7 +413,7 @@ public final class FragmentedMp4Extractor implements Extractor {
int sampleCount = saiz.readUnsignedIntToInt(); int sampleCount = saiz.readUnsignedIntToInt();
if (sampleCount != out.length) { if (sampleCount != out.length) {
throw new IllegalStateException("Length mismatch: " + sampleCount + ", " + out.length); throw new ParserException("Length mismatch: " + sampleCount + ", " + out.length);
} }
int totalSize = 0; int totalSize = 0;
@ -424,7 +438,7 @@ public final class FragmentedMp4Extractor implements Extractor {
* @param saio The saio atom to parse. * @param saio The saio atom to parse.
* @param out The track fragment to populate with data from the saio atom. * @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); saio.setPosition(Atom.HEADER_SIZE);
int fullAtom = saio.readInt(); int fullAtom = saio.readInt();
int flags = Atom.parseFullAtomFlags(fullAtom); int flags = Atom.parseFullAtomFlags(fullAtom);
@ -435,7 +449,7 @@ public final class FragmentedMp4Extractor implements Extractor {
int entryCount = saio.readUnsignedIntToInt(); int entryCount = saio.readUnsignedIntToInt();
if (entryCount != 1) { if (entryCount != 1) {
// We only support one trun element currently, so always expect one entry. // 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); int version = Atom.parseFullAtomVersion(fullAtom);
@ -558,7 +572,7 @@ public final class FragmentedMp4Extractor implements Extractor {
} }
private static void parseUuid(ParsableByteArray uuid, TrackFragment out, private static void parseUuid(ParsableByteArray uuid, TrackFragment out,
byte[] extendedTypeScratch) { byte[] extendedTypeScratch) throws ParserException {
uuid.setPosition(Atom.HEADER_SIZE); uuid.setPosition(Atom.HEADER_SIZE);
uuid.readBytes(extendedTypeScratch, 0, 16); uuid.readBytes(extendedTypeScratch, 0, 16);
@ -573,24 +587,25 @@ public final class FragmentedMp4Extractor implements Extractor {
parseSenc(uuid, 16, out); 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); 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); senc.setPosition(Atom.HEADER_SIZE + offset);
int fullAtom = senc.readInt(); int fullAtom = senc.readInt();
int flags = Atom.parseFullAtomFlags(fullAtom); int flags = Atom.parseFullAtomFlags(fullAtom);
if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) { if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) {
// TODO: Implement this. // 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; boolean subsampleEncryption = (flags & 0x02 /* use_subsample_encryption */) != 0;
int sampleCount = senc.readUnsignedIntToInt(); int sampleCount = senc.readUnsignedIntToInt();
if (sampleCount != out.length) { 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); 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). * 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); atom.setPosition(Atom.HEADER_SIZE);
int fullAtom = atom.readInt(); int fullAtom = atom.readInt();
int version = Atom.parseFullAtomVersion(fullAtom); int version = Atom.parseFullAtomVersion(fullAtom);
@ -633,7 +649,7 @@ public final class FragmentedMp4Extractor implements Extractor {
int type = 0x80000000 & firstInt; int type = 0x80000000 & firstInt;
if (type != 0) { if (type != 0) {
throw new IllegalStateException("Unhandled indirect reference"); throw new ParserException("Unhandled indirect reference");
} }
long referenceDuration = atom.readUnsignedInt(); long referenceDuration = atom.readUnsignedInt();
@ -656,7 +672,7 @@ public final class FragmentedMp4Extractor implements Extractor {
private void readEncryptionData(ExtractorInput input) throws IOException, InterruptedException { private void readEncryptionData(ExtractorInput input) throws IOException, InterruptedException {
int bytesToSkip = (int) (fragmentRun.auxiliaryDataPosition - input.getPosition()); 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); input.skipFully(bytesToSkip);
fragmentRun.fillEncryptionData(input); fragmentRun.fillEncryptionData(input);
parserState = STATE_READING_SAMPLE_START; parserState = STATE_READING_SAMPLE_START;
@ -679,13 +695,13 @@ public final class FragmentedMp4Extractor implements Extractor {
private boolean readSample(ExtractorInput input) throws IOException, InterruptedException { private boolean readSample(ExtractorInput input) throws IOException, InterruptedException {
if (sampleIndex == 0) { if (sampleIndex == 0) {
int bytesToSkip = (int) (fragmentRun.dataPosition - input.getPosition()); 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); input.skipFully(bytesToSkip);
} }
if (sampleIndex >= fragmentRun.length) { if (sampleIndex >= fragmentRun.length) {
int bytesToSkip = (int) (endOfMdatPosition - input.getPosition()); 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); input.skipFully(bytesToSkip);
// We've run out of samples in the current mdat atom. // We've run out of samples in the current mdat atom.
enterReadingAtomHeaderState(); enterReadingAtomHeaderState();

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer.extractor.webm; package com.google.android.exoplayer.extractor.webm;
import com.google.android.exoplayer.C; import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.extractor.ExtractorInput; import com.google.android.exoplayer.extractor.ExtractorInput;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
@ -100,7 +101,7 @@ import java.util.Stack;
return true; return true;
case TYPE_UNSIGNED_INT: case TYPE_UNSIGNED_INT:
if (elementContentSize > MAX_INTEGER_ELEMENT_SIZE_BYTES) { 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)); output.integerElement(elementId, readInteger(input, (int) elementContentSize));
elementState = ELEMENT_STATE_READ_ID; elementState = ELEMENT_STATE_READ_ID;
@ -108,14 +109,14 @@ import java.util.Stack;
case TYPE_FLOAT: case TYPE_FLOAT:
if (elementContentSize != VALID_FLOAT32_ELEMENT_SIZE_BYTES if (elementContentSize != VALID_FLOAT32_ELEMENT_SIZE_BYTES
&& elementContentSize != VALID_FLOAT64_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)); output.floatElement(elementId, readFloat(input, (int) elementContentSize));
elementState = ELEMENT_STATE_READ_ID; elementState = ELEMENT_STATE_READ_ID;
return true; return true;
case TYPE_STRING: case TYPE_STRING:
if (elementContentSize > Integer.MAX_VALUE) { 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)); output.stringElement(elementId, readString(input, (int) elementContentSize));
elementState = ELEMENT_STATE_READ_ID; elementState = ELEMENT_STATE_READ_ID;
@ -129,7 +130,7 @@ import java.util.Stack;
elementState = ELEMENT_STATE_READ_ID; elementState = ELEMENT_STATE_READ_ID;
break; break;
default: default:
throw new IllegalStateException("Invalid element type " + type); throw new ParserException("Invalid element type " + type);
} }
} }
} }

View File

@ -26,7 +26,6 @@ import com.google.android.exoplayer.extractor.ExtractorOutput;
import com.google.android.exoplayer.extractor.PositionHolder; import com.google.android.exoplayer.extractor.PositionHolder;
import com.google.android.exoplayer.extractor.SeekMap; import com.google.android.exoplayer.extractor.SeekMap;
import com.google.android.exoplayer.extractor.TrackOutput; 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.LongArray;
import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.NalUnitUtil; import com.google.android.exoplayer.util.NalUnitUtil;
@ -738,7 +737,7 @@ public final class WebmExtractor implements Extractor {
contentSize - blockTrackNumberLength - headerSize - totalSamplesSize; contentSize - blockTrackNumberLength - headerSize - totalSamplesSize;
} else { } else {
// Lacing is always in the range 0--3. // 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. // TODO: Deduplicate with AtomParsers.parseAvcCFromParent.
buffer.setPosition(4); buffer.setPosition(4);
int nalUnitLengthFieldLength = (buffer.readUnsignedByte() & 0x03) + 1; int nalUnitLengthFieldLength = (buffer.readUnsignedByte() & 0x03) + 1;
Assertions.checkState(nalUnitLengthFieldLength != 3); if (nalUnitLengthFieldLength == 3) {
throw new ParserException();
}
List<byte[]> initializationData = new ArrayList<>(); List<byte[]> initializationData = new ArrayList<>();
int numSequenceParameterSets = buffer.readUnsignedByte() & 0x1F; int numSequenceParameterSets = buffer.readUnsignedByte() & 0x1F;
for (int i = 0; i < numSequenceParameterSets; i++) { for (int i = 0; i < numSequenceParameterSets; i++) {