diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java index 0f61d51bfe..c655179fe3 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java @@ -327,7 +327,8 @@ public class SampleChooserActivity extends AppCompatActivity reader.nextString(); // Ignore. break; default: - throw new ParserException("Unsupported name: " + name); + throw ParserException.createForMalformedManifest( + "Unsupported name: " + name, /* cause= */ null); } } reader.endObject(); @@ -415,7 +416,8 @@ public class SampleChooserActivity extends AppCompatActivity reader.endArray(); break; default: - throw new ParserException("Unsupported attribute name: " + name); + throw ParserException.createForMalformedManifest( + "Unsupported attribute name: " + name, /* cause= */ null); } } reader.endObject(); diff --git a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java index 4b416c565e..c4e5e4e710 100644 --- a/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java +++ b/extensions/flac/src/main/java/com/google/android/exoplayer2/ext/flac/FlacDecoderJni.java @@ -148,7 +148,8 @@ import java.nio.ByteBuffer; public FlacStreamMetadata decodeStreamMetadata() throws IOException { FlacStreamMetadata streamMetadata = flacDecodeMetadata(nativeDecoderContext); if (streamMetadata == null) { - throw new ParserException("Failed to decode stream metadata"); + throw ParserException.createForMalformedContainer( + "Failed to decode stream metadata", /* cause= */ null); } return streamMetadata; } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/ParserException.java b/library/common/src/main/java/com/google/android/exoplayer2/ParserException.java index 1d305c5454..1e6c3a88f2 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/ParserException.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/ParserException.java @@ -96,18 +96,6 @@ public class ParserException extends IOException { /** The {@link DataType data type} of the parsed bitstream. */ public final int dataType; - /** - * Creates a new instance. - * - * @param message The detail message for the exception. - * @deprecated Use a factory method which initializes {@link #contentIsMalformed}, and {@link - * #dataType} instead. - */ - @Deprecated - public ParserException(String message) { - this(message, /* cause= */ null, /* contentIsMalformed= */ true, C.DATA_TYPE_UNKNOWN); - } - protected ParserException( @Nullable String message, @Nullable Throwable cause, diff --git a/library/common/src/main/java/com/google/android/exoplayer2/audio/AacUtil.java b/library/common/src/main/java/com/google/android/exoplayer2/audio/AacUtil.java index d28f8baa08..2684273b2e 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/audio/AacUtil.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/audio/AacUtil.java @@ -229,7 +229,8 @@ public final class AacUtil { parseGaSpecificConfig(bitArray, audioObjectType, channelConfiguration); break; default: - throw new ParserException("Unsupported audio object type: " + audioObjectType); + throw ParserException.createForUnsupportedContainerFeature( + "Unsupported audio object type: " + audioObjectType); } switch (audioObjectType) { case 17: @@ -240,7 +241,8 @@ public final class AacUtil { case 23: int epConfig = bitArray.readBits(2); if (epConfig == 2 || epConfig == 3) { - throw new ParserException("Unsupported epConfig: " + epConfig); + throw ParserException.createForUnsupportedContainerFeature( + "Unsupported epConfig: " + epConfig); } break; default: 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 5f914d529d..3c888a5da3 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 @@ -1216,7 +1216,8 @@ public final class Util { public static long parseXsDateTime(String value) throws ParserException { Matcher matcher = XS_DATE_TIME_PATTERN.matcher(value); if (!matcher.matches()) { - throw new ParserException("Invalid date/time format: " + value); + throw ParserException.createForMalformedContainer( + "Invalid date/time format: " + value, /* cause= */ null); } int timezoneShift; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java index a944569d42..2ffe134fa4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java @@ -237,7 +237,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public void maybeThrowPrepareError() throws IOException { maybeThrowError(); if (loadingFinished && !prepared) { - throw new ParserException("Loading finished before preparation is complete."); + throw ParserException.createForMalformedContainer( + "Loading finished before preparation is complete.", /* cause= */ null); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttParserUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttParserUtil.java index 02d2d3bcac..52f0cdb8d1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttParserUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttParserUtil.java @@ -40,7 +40,8 @@ public final class WebvttParserUtil { int startPosition = input.getPosition(); if (!isWebvttHeaderLine(input)) { input.setPosition(startPosition); - throw new ParserException("Expected WEBVTT. Got " + input.readLine()); + throw ParserException.createForMalformedContainer( + "Expected WEBVTT. Got " + input.readLine(), /* cause= */ null); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSchemeDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSchemeDataSource.java index c914517777..134af0c29c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSchemeDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DataSchemeDataSource.java @@ -23,6 +23,7 @@ import android.util.Base64; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; import com.google.common.base.Charsets; import java.io.IOException; @@ -48,12 +49,11 @@ public final class DataSchemeDataSource extends BaseDataSource { this.dataSpec = dataSpec; Uri uri = dataSpec.uri; String scheme = uri.getScheme(); - if (!SCHEME_DATA.equals(scheme)) { - throw new ParserException("Unsupported scheme: " + scheme); - } + Assertions.checkArgument(SCHEME_DATA.equals(scheme), "Unsupported scheme: " + scheme); String[] uriParts = Util.split(uri.getSchemeSpecificPart(), ","); if (uriParts.length != 2) { - throw new ParserException("Unexpected URI format: " + uri); + throw ParserException.createForMalformedDataOfUnknownType( + "Unexpected URI format: " + uri, /* cause= */ null); } String dataString = uriParts[1]; if (uriParts[0].contains(";base64")) { diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java index 119d473e7d..1894dca414 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/DataSchemeDataSourceTest.java @@ -108,11 +108,11 @@ public final class DataSchemeDataSourceTest { } @Test - public void incorrectScheme() { + public void incorrectScheme() throws IOException { try { schemeDataDataSource.open(buildDataSpec("http://www.google.com")); fail(); - } catch (IOException e) { + } catch (IllegalArgumentException e) { // Expected. } } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 36ba4fea48..6921245cac 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -1443,7 +1443,8 @@ public final class DashMediaSource extends BaseMediaSource { try { Matcher matcher = TIMESTAMP_WITH_TIMEZONE_PATTERN.matcher(firstLine); if (!matcher.matches()) { - throw new ParserException("Couldn't parse timestamp: " + firstLine); + throw ParserException.createForMalformedManifest( + "Couldn't parse timestamp: " + firstLine, /* cause= */ null); } // Parse the timestamp. String timestampWithoutTimezone = matcher.group(1); diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index 3db266f6df..961cf15195 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -169,7 +169,8 @@ public class DashManifestParser extends DefaultHandler // early access. seenEarlyAccessPeriod = true; } else { - throw new ParserException("Unable to determine start of period " + periods.size()); + throw ParserException.createForMalformedManifest( + "Unable to determine start of period " + periods.size(), /* cause= */ null); } } else { long periodDurationMs = periodWithDurationMs.second; @@ -187,12 +188,13 @@ public class DashManifestParser extends DefaultHandler // If we know the end time of the final period, we can use it as the duration. durationMs = nextPeriodStartMs; } else if (!dynamic) { - throw new ParserException("Unable to determine duration of static manifest."); + throw ParserException.createForMalformedManifest( + "Unable to determine duration of static manifest.", /* cause= */ null); } } if (periods.isEmpty()) { - throw new ParserException("No periods found."); + throw ParserException.createForMalformedManifest("No periods found.", /* cause= */ null); } return buildMediaPresentationDescription( diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java index 922ef0f3da..01d2def12d 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java @@ -120,7 +120,8 @@ public final class FlacMetadataReader { ParsableByteArray scratch = new ParsableByteArray(FlacConstants.STREAM_MARKER_SIZE); input.readFully(scratch.getData(), 0, FlacConstants.STREAM_MARKER_SIZE); if (scratch.readUnsignedInt() != STREAM_MARKER) { - throw new ParserException("Failed to read FLAC stream marker."); + throw ParserException.createForMalformedContainer( + "Failed to read FLAC stream marker.", /* cause= */ null); } } @@ -234,7 +235,8 @@ public final class FlacMetadataReader { int syncCode = frameStartMarker >> 2; if (syncCode != SYNC_CODE) { input.resetPeekPosition(); - throw new ParserException("First frame does not start with sync code."); + throw ParserException.createForMalformedContainer( + "First frame does not start with sync code.", /* cause= */ null); } input.resetPeekPosition(); diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java index 201400259d..5fbd0e4ae4 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java @@ -241,7 +241,8 @@ public final class VorbisUtil { length += comments[i].length(); } if (hasFramingBit && (headerData.readUnsignedByte() & 0x01) == 0) { - throw new ParserException("framing bit expected to be set"); + throw ParserException.createForMalformedContainer( + "framing bit expected to be set", /* cause= */ null); } length += 1; return new CommentHeader(vendor, comments, length); @@ -263,7 +264,8 @@ public final class VorbisUtil { if (quiet) { return false; } else { - throw new ParserException("too short header: " + header.bytesLeft()); + throw ParserException.createForMalformedContainer( + "too short header: " + header.bytesLeft(), /* cause= */ null); } } @@ -271,7 +273,8 @@ public final class VorbisUtil { if (quiet) { return false; } else { - throw new ParserException("expected header type " + Integer.toHexString(headerType)); + throw ParserException.createForMalformedContainer( + "expected header type " + Integer.toHexString(headerType), /* cause= */ null); } } @@ -284,7 +287,8 @@ public final class VorbisUtil { if (quiet) { return false; } else { - throw new ParserException("expected characters 'vorbis'"); + throw ParserException.createForMalformedContainer( + "expected characters 'vorbis'", /* cause= */ null); } } return true; @@ -319,7 +323,8 @@ public final class VorbisUtil { int timeCount = bitArray.readBits(6) + 1; for (int i = 0; i < timeCount; i++) { if (bitArray.readBits(16) != 0x00) { - throw new ParserException("placeholder of time domain transforms not zeroed out"); + throw ParserException.createForMalformedContainer( + "placeholder of time domain transforms not zeroed out", /* cause= */ null); } } readFloors(bitArray); @@ -328,7 +333,8 @@ public final class VorbisUtil { Mode[] modes = readModes(bitArray); if (!bitArray.readBit()) { - throw new ParserException("framing bit after modes not set as expected"); + throw ParserException.createForMalformedContainer( + "framing bit after modes not set as expected", /* cause= */ null); } return modes; } @@ -371,7 +377,8 @@ public final class VorbisUtil { couplingSteps = 0; }*/ if (bitArray.readBits(2) != 0x00) { - throw new ParserException("to reserved bits must be zero after mapping coupling steps"); + throw ParserException.createForMalformedContainer( + "to reserved bits must be zero after mapping coupling steps", /* cause= */ null); } if (submaps > 1) { for (int j = 0; j < channels; j++) { @@ -391,7 +398,8 @@ public final class VorbisUtil { for (int i = 0; i < residueCount; i++) { int residueType = bitArray.readBits(16); if (residueType > 2) { - throw new ParserException("residueType greater than 2 is not decodable"); + throw ParserException.createForMalformedContainer( + "residueType greater than 2 is not decodable", /* cause= */ null); } else { bitArray.skipBits(24); // begin bitArray.skipBits(24); // end @@ -467,15 +475,17 @@ public final class VorbisUtil { } break; default: - throw new ParserException("floor type greater than 1 not decodable: " + floorType); + throw ParserException.createForMalformedContainer( + "floor type greater than 1 not decodable: " + floorType, /* cause= */ null); } } } private static CodeBook readBook(VorbisBitArray bitArray) throws ParserException { if (bitArray.readBits(24) != 0x564342) { - throw new ParserException( - "expected code book to start with [0x56, 0x43, 0x42] at " + bitArray.getPosition()); + throw ParserException.createForMalformedContainer( + "expected code book to start with [0x56, 0x43, 0x42] at " + bitArray.getPosition(), + /* cause= */ null); } int dimensions = bitArray.readBits(16); int entries = bitArray.readBits(24); @@ -508,7 +518,8 @@ public final class VorbisUtil { int lookupType = bitArray.readBits(4); if (lookupType > 2) { - throw new ParserException("lookup type greater than 2 not decodable: " + lookupType); + throw ParserException.createForMalformedContainer( + "lookup type greater than 2 not decodable: " + lookupType, /* cause= */ null); } else if (lookupType == 1 || lookupType == 2) { bitArray.skipBits(32); // minimumValue bitArray.skipBits(32); // deltaValue diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/amr/AmrExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/amr/AmrExtractor.java index 4d8ef18448..ab72539595 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/amr/AmrExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/amr/AmrExtractor.java @@ -176,7 +176,8 @@ public final class AmrExtractor implements Extractor { assertInitialized(); if (input.getPosition() == 0) { if (!readAmrHeader(input)) { - throw new ParserException("Could not find AMR header."); + throw ParserException.createForMalformedContainer( + "Could not find AMR header.", /* cause= */ null); } } maybeOutputFormat(); @@ -311,7 +312,8 @@ public final class AmrExtractor implements Extractor { if ((frameHeader & 0x83) > 0) { // The padding bits are at bit-1 positions in the following pattern: 1000 0011 // Padding bits must be 0. - throw new ParserException("Invalid padding bits for frame header " + frameHeader); + throw ParserException.createForMalformedContainer( + "Invalid padding bits for frame header " + frameHeader, /* cause= */ null); } int frameType = (frameHeader >> 3) & 0x0f; @@ -320,8 +322,9 @@ public final class AmrExtractor implements Extractor { private int getFrameSizeInBytes(int frameType) throws ParserException { if (!isValidFrameType(frameType)) { - throw new ParserException( - "Illegal AMR " + (isWideBand ? "WB" : "NB") + " frame type " + frameType); + throw ParserException.createForMalformedContainer( + "Illegal AMR " + (isWideBand ? "WB" : "NB") + " frame type " + frameType, + /* cause= */ null); } return isWideBand ? frameSizeBytesByTypeWb[frameType] : frameSizeBytesByTypeNb[frameType]; diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/TagPayloadReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/TagPayloadReader.java index d80e029704..8d56951b20 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/TagPayloadReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/flv/TagPayloadReader.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.extractor.flv; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.util.ParsableByteArray; @@ -26,7 +27,7 @@ import com.google.android.exoplayer2.util.ParsableByteArray; public static final class UnsupportedFormatException extends ParserException { public UnsupportedFormatException(String msg) { - super(msg); + super(msg, /* cause= */ null, /* contentIsMalformed= */ false, C.DATA_TYPE_MEDIA); } } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/jpeg/XmpMotionPhotoDescriptionParser.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/jpeg/XmpMotionPhotoDescriptionParser.java index 0972c00567..17fa7756ab 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/jpeg/XmpMotionPhotoDescriptionParser.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/jpeg/XmpMotionPhotoDescriptionParser.java @@ -85,7 +85,8 @@ import org.xmlpull.v1.XmlPullParserFactory; xpp.setInput(new StringReader(xmpString)); xpp.next(); if (!XmlPullParserUtil.isStartTag(xpp, "x:xmpmeta")) { - throw new ParserException("Couldn't find xmp metadata"); + throw ParserException.createForMalformedContainer( + "Couldn't find xmp metadata", /* cause= */ null); } long motionPhotoPresentationTimestampUs = C.TIME_UNSET; List containerItems = ImmutableList.of(); diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/DefaultEbmlReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/DefaultEbmlReader.java index 0e56a0d197..de4c9e23c6 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/DefaultEbmlReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/DefaultEbmlReader.java @@ -114,7 +114,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; return true; case EbmlProcessor.ELEMENT_TYPE_UNSIGNED_INT: if (elementContentSize > MAX_INTEGER_ELEMENT_SIZE_BYTES) { - throw new ParserException("Invalid integer size: " + elementContentSize); + throw ParserException.createForMalformedContainer( + "Invalid integer size: " + elementContentSize, /* cause= */ null); } processor.integerElement(elementId, readInteger(input, (int) elementContentSize)); elementState = ELEMENT_STATE_READ_ID; @@ -122,14 +123,16 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; case EbmlProcessor.ELEMENT_TYPE_FLOAT: if (elementContentSize != VALID_FLOAT32_ELEMENT_SIZE_BYTES && elementContentSize != VALID_FLOAT64_ELEMENT_SIZE_BYTES) { - throw new ParserException("Invalid float size: " + elementContentSize); + throw ParserException.createForMalformedContainer( + "Invalid float size: " + elementContentSize, /* cause= */ null); } processor.floatElement(elementId, readFloat(input, (int) elementContentSize)); elementState = ELEMENT_STATE_READ_ID; return true; case EbmlProcessor.ELEMENT_TYPE_STRING: if (elementContentSize > Integer.MAX_VALUE) { - throw new ParserException("String element size: " + elementContentSize); + throw ParserException.createForMalformedContainer( + "String element size: " + elementContentSize, /* cause= */ null); } processor.stringElement(elementId, readString(input, (int) elementContentSize)); elementState = ELEMENT_STATE_READ_ID; @@ -143,7 +146,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; elementState = ELEMENT_STATE_READ_ID; break; default: - throw new ParserException("Invalid element type " + type); + throw ParserException.createForMalformedContainer( + "Invalid element type " + type, /* cause= */ null); } } } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 6da428a42c..e1c68726b3 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -626,7 +626,8 @@ public class MatroskaExtractor implements Extractor { case ID_SEGMENT: if (segmentContentPosition != C.POSITION_UNSET && segmentContentPosition != contentPosition) { - throw new ParserException("Multiple Segment elements not supported"); + throw ParserException.createForMalformedContainer( + "Multiple Segment elements not supported", /* cause= */ null); } segmentContentPosition = contentPosition; segmentContentSize = contentSize; @@ -696,7 +697,8 @@ public class MatroskaExtractor implements Extractor { break; case ID_SEEK: if (seekEntryId == UNSET_ENTRY_ID || seekEntryPosition == C.POSITION_UNSET) { - throw new ParserException("Mandatory element SeekID or SeekPosition not found"); + throw ParserException.createForMalformedContainer( + "Mandatory element SeekID or SeekPosition not found", /* cause= */ null); } if (seekEntryId == ID_CUES) { cuesContentPosition = seekEntryPosition; @@ -742,7 +744,8 @@ public class MatroskaExtractor implements Extractor { assertInTrackEntry(id); if (currentTrack.hasContentEncryption) { if (currentTrack.cryptoData == null) { - throw new ParserException("Encrypted Track found but ContentEncKeyID was not found"); + throw ParserException.createForMalformedContainer( + "Encrypted Track found but ContentEncKeyID was not found", /* cause= */ null); } currentTrack.drmInitData = new DrmInitData( @@ -753,13 +756,15 @@ public class MatroskaExtractor implements Extractor { case ID_CONTENT_ENCODINGS: assertInTrackEntry(id); if (currentTrack.hasContentEncryption && currentTrack.sampleStrippedBytes != null) { - throw new ParserException("Combining encryption and compression is not supported"); + throw ParserException.createForMalformedContainer( + "Combining encryption and compression is not supported", /* cause= */ null); } break; case ID_TRACK_ENTRY: Track currentTrack = checkStateNotNull(this.currentTrack); if (currentTrack.codecId == null) { - throw new ParserException("CodecId is missing in TrackEntry element"); + throw ParserException.createForMalformedContainer( + "CodecId is missing in TrackEntry element", /* cause= */ null); } else { if (isCodecSupported(currentTrack.codecId)) { currentTrack.initializeOutput(extractorOutput, currentTrack.number); @@ -770,7 +775,8 @@ public class MatroskaExtractor implements Extractor { break; case ID_TRACKS: if (tracks.size() == 0) { - throw new ParserException("No valid tracks were found"); + throw ParserException.createForMalformedContainer( + "No valid tracks were found", /* cause= */ null); } extractorOutput.endTracks(); break; @@ -790,13 +796,15 @@ public class MatroskaExtractor implements Extractor { case ID_EBML_READ_VERSION: // Validate that EBMLReadVersion is supported. This extractor only supports v1. if (value != 1) { - throw new ParserException("EBMLReadVersion " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "EBMLReadVersion " + value + " not supported", /* cause= */ null); } break; case ID_DOC_TYPE_READ_VERSION: // Validate that DocTypeReadVersion is supported. This extractor only supports up to v2. if (value < 1 || value > 2) { - throw new ParserException("DocTypeReadVersion " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "DocTypeReadVersion " + value + " not supported", /* cause= */ null); } break; case ID_SEEK_POSITION: @@ -861,31 +869,36 @@ public class MatroskaExtractor implements Extractor { case ID_CONTENT_ENCODING_ORDER: // This extractor only supports one ContentEncoding element and hence the order has to be 0. if (value != 0) { - throw new ParserException("ContentEncodingOrder " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "ContentEncodingOrder " + value + " not supported", /* cause= */ null); } break; case ID_CONTENT_ENCODING_SCOPE: // This extractor only supports the scope of all frames. if (value != 1) { - throw new ParserException("ContentEncodingScope " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "ContentEncodingScope " + value + " not supported", /* cause= */ null); } break; case ID_CONTENT_COMPRESSION_ALGORITHM: // This extractor only supports header stripping. if (value != 3) { - throw new ParserException("ContentCompAlgo " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "ContentCompAlgo " + value + " not supported", /* cause= */ null); } break; case ID_CONTENT_ENCRYPTION_ALGORITHM: // Only the value 5 (AES) is allowed according to the WebM specification. if (value != 5) { - throw new ParserException("ContentEncAlgo " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "ContentEncAlgo " + value + " not supported", /* cause= */ null); } break; case ID_CONTENT_ENCRYPTION_AES_SETTINGS_CIPHER_MODE: // Only the value 1 is allowed according to the WebM specification. if (value != 1) { - throw new ParserException("AESSettingsCipherMode " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "AESSettingsCipherMode " + value + " not supported", /* cause= */ null); } break; case ID_CUE_TIME: @@ -1058,7 +1071,8 @@ public class MatroskaExtractor implements Extractor { case ID_DOC_TYPE: // Validate that DocType is supported. if (!DOC_TYPE_WEBM.equals(value) && !DOC_TYPE_MATROSKA.equals(value)) { - throw new ParserException("DocType " + value + " not supported"); + throw ParserException.createForMalformedContainer( + "DocType " + value + " not supported", /* cause= */ null); } break; case ID_NAME: @@ -1180,7 +1194,8 @@ public class MatroskaExtractor implements Extractor { blockSampleSizes[sampleIndex] = 0; readScratch(input, ++headerSize); if (scratch.getData()[headerSize - 1] == 0) { - throw new ParserException("No valid varint length mask found"); + throw ParserException.createForMalformedContainer( + "No valid varint length mask found", /* cause= */ null); } long readValue = 0; for (int i = 0; i < 8; i++) { @@ -1202,7 +1217,8 @@ public class MatroskaExtractor implements Extractor { } } if (readValue < Integer.MIN_VALUE || readValue > Integer.MAX_VALUE) { - throw new ParserException("EBML lacing sample size out of range."); + throw ParserException.createForMalformedContainer( + "EBML lacing sample size out of range.", /* cause= */ null); } int intReadValue = (int) readValue; blockSampleSizes[sampleIndex] = @@ -1215,7 +1231,8 @@ public class MatroskaExtractor implements Extractor { contentSize - blockTrackNumberLength - headerSize - totalSamplesSize; } else { // Lacing is always in the range 0--3. - throw new ParserException("Unexpected lacing value: " + lacing); + throw ParserException.createForMalformedContainer( + "Unexpected lacing value: " + lacing, /* cause= */ null); } } @@ -1262,7 +1279,8 @@ public class MatroskaExtractor implements Extractor { tracks.get(blockTrackNumber), blockAdditionalId, input, contentSize); break; default: - throw new ParserException("Unexpected id: " + id); + throw ParserException.createForMalformedContainer( + "Unexpected id: " + id, /* cause= */ null); } } @@ -1294,14 +1312,16 @@ public class MatroskaExtractor implements Extractor { @EnsuresNonNull("currentTrack") private void assertInTrackEntry(int id) throws ParserException { if (currentTrack == null) { - throw new ParserException("Element " + id + " must be in a TrackEntry"); + throw ParserException.createForMalformedContainer( + "Element " + id + " must be in a TrackEntry", /* cause= */ null); } } @EnsuresNonNull({"cueTimesUs", "cueClusterPositions"}) private void assertInCues(int id) throws ParserException { if (cueTimesUs == null || cueClusterPositions == null) { - throw new ParserException("Element " + id + " must be in a Cues"); + throw ParserException.createForMalformedContainer( + "Element " + id + " must be in a Cues", /* cause= */ null); } } @@ -1401,7 +1421,8 @@ public class MatroskaExtractor implements Extractor { input.readFully(scratch.getData(), 0, 1); sampleBytesRead++; if ((scratch.getData()[0] & 0x80) == 0x80) { - throw new ParserException("Extension bit is set in signal byte"); + throw ParserException.createForMalformedContainer( + "Extension bit is set in signal byte", /* cause= */ null); } sampleSignalByte = scratch.getData()[0]; sampleSignalByteRead = true; @@ -1766,7 +1787,8 @@ public class MatroskaExtractor implements Extractor { private long scaleTimecodeToUs(long unscaledTimecode) throws ParserException { if (timecodeScale == C.TIME_UNSET) { - throw new ParserException("Can't scale timecode prior to timecodeScale being set."); + throw ParserException.createForMalformedContainer( + "Can't scale timecode prior to timecodeScale being set.", /* cause= */ null); } return Util.scaleLargeTimestamp(unscaledTimecode, timecodeScale, 1000); } @@ -2207,7 +2229,8 @@ public class MatroskaExtractor implements Extractor { initializationData = ImmutableList.of(initializationDataBytes); break; default: - throw new ParserException("Unrecognized codec identifier."); + throw ParserException.createForMalformedContainer( + "Unrecognized codec identifier.", /* cause= */ null); } if (dolbyVisionConfigBytes != null) { @@ -2284,7 +2307,8 @@ public class MatroskaExtractor implements Extractor { || MimeTypes.APPLICATION_DVBSUBS.equals(mimeType)) { type = C.TRACK_TYPE_TEXT; } else { - throw new ParserException("Unexpected MIME type."); + throw ParserException.createForMalformedContainer( + "Unexpected MIME type.", /* cause= */ null); } if (name != null && !TRACK_NAME_TO_ROTATION_DEGREES.containsKey(name)) { @@ -2389,10 +2413,12 @@ public class MatroskaExtractor implements Extractor { return new Pair<>(MimeTypes.VIDEO_VC1, Collections.singletonList(initializationData)); } } - throw new ParserException("Failed to find FourCC VC1 initialization data"); + throw ParserException.createForMalformedContainer( + "Failed to find FourCC VC1 initialization data", /* cause= */ null); } } catch (ArrayIndexOutOfBoundsException e) { - throw new ParserException("Error parsing FourCC private data"); + throw ParserException.createForMalformedContainer( + "Error parsing FourCC private data", /* cause= */ null); } Log.w(TAG, "Unknown FourCC. Setting mimeType to " + MimeTypes.VIDEO_UNKNOWN); @@ -2409,7 +2435,8 @@ public class MatroskaExtractor implements Extractor { throws ParserException { try { if (codecPrivate[0] != 0x02) { - throw new ParserException("Error parsing vorbis codec private"); + throw ParserException.createForMalformedContainer( + "Error parsing vorbis codec private", /* cause= */ null); } int offset = 1; int vorbisInfoLength = 0; @@ -2427,17 +2454,20 @@ public class MatroskaExtractor implements Extractor { vorbisSkipLength += codecPrivate[offset++] & 0xFF; if (codecPrivate[offset] != 0x01) { - throw new ParserException("Error parsing vorbis codec private"); + throw ParserException.createForMalformedContainer( + "Error parsing vorbis codec private", /* cause= */ null); } byte[] vorbisInfo = new byte[vorbisInfoLength]; System.arraycopy(codecPrivate, offset, vorbisInfo, 0, vorbisInfoLength); offset += vorbisInfoLength; if (codecPrivate[offset] != 0x03) { - throw new ParserException("Error parsing vorbis codec private"); + throw ParserException.createForMalformedContainer( + "Error parsing vorbis codec private", /* cause= */ null); } offset += vorbisSkipLength; if (codecPrivate[offset] != 0x05) { - throw new ParserException("Error parsing vorbis codec private"); + throw ParserException.createForMalformedContainer( + "Error parsing vorbis codec private", /* cause= */ null); } byte[] vorbisBooks = new byte[codecPrivate.length - offset]; System.arraycopy(codecPrivate, offset, vorbisBooks, 0, codecPrivate.length - offset); @@ -2446,7 +2476,8 @@ public class MatroskaExtractor implements Extractor { initializationData.add(vorbisBooks); return initializationData; } catch (ArrayIndexOutOfBoundsException e) { - throw new ParserException("Error parsing vorbis codec private"); + throw ParserException.createForMalformedContainer( + "Error parsing vorbis codec private", /* cause= */ null); } } @@ -2469,7 +2500,8 @@ public class MatroskaExtractor implements Extractor { return false; } } catch (ArrayIndexOutOfBoundsException e) { - throw new ParserException("Error parsing MS/ACM codec private"); + throw ParserException.createForMalformedContainer( + "Error parsing MS/ACM codec private", /* cause= */ null); } } @@ -2488,7 +2520,8 @@ public class MatroskaExtractor implements Extractor { @EnsuresNonNull("codecPrivate") private byte[] getCodecPrivate(String codecId) throws ParserException { if (codecPrivate == null) { - throw new ParserException("Missing CodecPrivate for codec " + codecId); + throw ParserException.createForMalformedContainer( + "Missing CodecPrivate for codec " + codecId, /* cause= */ null); } return codecPrivate; } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java index 7879d97bcb..468e31e30a 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp3/Mp3Extractor.java @@ -357,7 +357,8 @@ public final class Mp3Extractor implements Extractor { // The header doesn't match the candidate header or is invalid. Try the next byte offset. if (searchedBytes++ == searchLimitBytes) { if (!sniffing) { - throw new ParserException("Searched too many bytes."); + throw ParserException.createForMalformedContainer( + "Searched too many bytes.", /* cause= */ null); } return false; } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index 0ec5bd48ed..b72159be1d 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -379,7 +379,8 @@ public class FragmentedMp4Extractor implements Extractor { } if (atomSize < atomHeaderBytesRead) { - throw new ParserException("Atom size less than header length (unsupported)."); + throw ParserException.createForUnsupportedContainerFeature( + "Atom size less than header length (unsupported)."); } long atomPosition = input.getPosition() - atomHeaderBytesRead; @@ -420,10 +421,12 @@ public class FragmentedMp4Extractor implements Extractor { } } else if (shouldParseLeafAtom(atomType)) { if (atomHeaderBytesRead != Atom.HEADER_SIZE) { - throw new ParserException("Leaf atom defines extended atom size (unsupported)."); + throw ParserException.createForUnsupportedContainerFeature( + "Leaf atom defines extended atom size (unsupported)."); } if (atomSize > Integer.MAX_VALUE) { - throw new ParserException("Leaf atom with length > 2147483647 (unsupported)."); + throw ParserException.createForUnsupportedContainerFeature( + "Leaf atom with length > 2147483647 (unsupported)."); } ParsableByteArray atomData = new ParsableByteArray((int) atomSize); System.arraycopy(atomHeader.getData(), 0, atomData.getData(), 0, Atom.HEADER_SIZE); @@ -431,7 +434,8 @@ public class FragmentedMp4Extractor implements Extractor { parserState = STATE_READING_ATOM_PAYLOAD; } else { if (atomSize > Integer.MAX_VALUE) { - throw new ParserException("Skipping atom with length > 2147483647 (unsupported)."); + throw ParserException.createForUnsupportedContainerFeature( + "Skipping atom with length > 2147483647 (unsupported)."); } atomData = null; parserState = STATE_READING_ATOM_PAYLOAD; @@ -827,11 +831,12 @@ public class FragmentedMp4Extractor implements Extractor { int sampleCount = saiz.readUnsignedIntToInt(); if (sampleCount > out.sampleCount) { - throw new ParserException( + throw ParserException.createForMalformedContainer( "Saiz sample count " + sampleCount + " is greater than fragment sample count" - + out.sampleCount); + + out.sampleCount, + /* cause= */ null); } int totalSize = 0; @@ -870,7 +875,8 @@ public 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 ParserException("Unexpected saio entry count: " + entryCount); + throw ParserException.createForMalformedContainer( + "Unexpected saio entry count: " + entryCount, /* cause= */ null); } int version = Atom.parseFullAtomVersion(fullAtom); @@ -1055,7 +1061,8 @@ public class FragmentedMp4Extractor implements Extractor { private static int checkNonNegative(int value) throws ParserException { if (value < 0) { - throw new ParserException("Unexpected negative value: " + value); + throw ParserException.createForMalformedContainer( + "Unexpected negative value: " + value, /* cause= */ null); } return value; } @@ -1089,7 +1096,8 @@ public class FragmentedMp4Extractor implements Extractor { if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) { // TODO: Implement this. - throw new ParserException("Overriding TrackEncryptionBox parameters is unsupported."); + throw ParserException.createForUnsupportedContainerFeature( + "Overriding TrackEncryptionBox parameters is unsupported."); } boolean subsampleEncryption = (flags & 0x02 /* use_subsample_encryption */) != 0; @@ -1099,11 +1107,12 @@ public class FragmentedMp4Extractor implements Extractor { Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, out.sampleCount, false); return; } else if (sampleCount != out.sampleCount) { - throw new ParserException( + throw ParserException.createForMalformedContainer( "Senc sample count " + sampleCount + " is different from fragment sample count" - + out.sampleCount); + + out.sampleCount, + /* cause= */ null); } Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption); @@ -1142,7 +1151,8 @@ public class FragmentedMp4Extractor implements Extractor { sbgp.skipBytes(4); // grouping_type_parameter. } if (sbgp.readInt() != 1) { // entry_count. - throw new ParserException("Entry count in sbgp != 1 (unsupported)."); + throw ParserException.createForUnsupportedContainerFeature( + "Entry count in sbgp != 1 (unsupported)."); } sgpd.setPosition(Atom.HEADER_SIZE); @@ -1150,13 +1160,15 @@ public class FragmentedMp4Extractor implements Extractor { sgpd.skipBytes(4); // grouping_type == seig. if (sgpdVersion == 1) { if (sgpd.readUnsignedInt() == 0) { - throw new ParserException("Variable length description in sgpd found (unsupported)"); + throw ParserException.createForUnsupportedContainerFeature( + "Variable length description in sgpd found (unsupported)"); } } else if (sgpdVersion >= 2) { sgpd.skipBytes(4); // default_sample_description_index. } if (sgpd.readUnsignedInt() != 1) { // entry_count. - throw new ParserException("Entry count in sgpd != 1 (unsupported)."); + throw ParserException.createForUnsupportedContainerFeature( + "Entry count in sgpd != 1 (unsupported)."); } // CencSampleEncryptionInformationGroupEntry @@ -1232,7 +1244,8 @@ public class FragmentedMp4Extractor implements Extractor { int type = 0x80000000 & firstInt; if (type != 0) { - throw new ParserException("Unhandled indirect reference"); + throw ParserException.createForMalformedContainer( + "Unhandled indirect reference", /* cause= */ null); } long referenceDuration = atom.readUnsignedInt(); @@ -1272,7 +1285,8 @@ public class FragmentedMp4Extractor implements Extractor { } int bytesToSkip = (int) (nextDataOffset - input.getPosition()); if (bytesToSkip < 0) { - throw new ParserException("Offset to encryption data was negative."); + throw ParserException.createForMalformedContainer( + "Offset to encryption data was negative.", /* cause= */ null); } input.skipFully(bytesToSkip); nextTrackBundle.fragment.fillEncryptionData(input); @@ -1302,7 +1316,8 @@ public class FragmentedMp4Extractor implements Extractor { // read the header of the next atom. int bytesToSkip = (int) (endOfMdatPosition - input.getPosition()); if (bytesToSkip < 0) { - throw new ParserException("Offset to end of mdat was negative."); + throw ParserException.createForMalformedContainer( + "Offset to end of mdat was negative.", /* cause= */ null); } input.skipFully(bytesToSkip); enterReadingAtomHeaderState(); @@ -1380,7 +1395,8 @@ public class FragmentedMp4Extractor implements Extractor { nalPrefix.setPosition(0); int nalLengthInt = nalPrefix.readInt(); if (nalLengthInt < 1) { - throw new ParserException("Invalid NAL length"); + throw ParserException.createForMalformedContainer( + "Invalid NAL length", /* cause= */ null); } sampleCurrentNalBytesRemaining = nalLengthInt - 1; // Write a start code for the current NAL unit. diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java index a3aa195068..9bf29fc22a 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java @@ -360,7 +360,8 @@ public final class Mp4Extractor implements Extractor, SeekMap { } if (atomSize < atomHeaderBytesRead) { - throw new ParserException("Atom size less than header length (unsupported)."); + throw ParserException.createForUnsupportedContainerFeature( + "Atom size less than header length (unsupported)."); } if (shouldParseContainerAtom(atomType)) { @@ -598,7 +599,8 @@ public final class Mp4Extractor implements Extractor, SeekMap { nalLength.setPosition(0); int nalLengthInt = nalLength.readInt(); if (nalLengthInt < 0) { - throw new ParserException("Invalid NAL length"); + throw ParserException.createForMalformedContainer( + "Invalid NAL length", /* cause= */ null); } sampleCurrentNalBytesRemaining = nalLengthInt; // Write a start code for the current NAL unit. diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/SefReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/SefReader.java index 0c980c1e5b..36586e7059 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/SefReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/SefReader.java @@ -260,7 +260,7 @@ import java.util.List; case "Super_SlowMotion_Deflickering_On": return TYPE_SUPER_SLOW_DEFLICKERING_ON; default: - throw new ParserException("Invalid SEF name"); + throw ParserException.createForMalformedContainer("Invalid SEF name", /* cause= */ null); } } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java index a51f463410..32fb588c75 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggExtractor.java @@ -74,7 +74,8 @@ public class OggExtractor implements Extractor { checkStateNotNull(output); // Check that init has been called. if (streamReader == null) { if (!sniffInternal(input)) { - throw new ParserException("Failed to determine bitstream type"); + throw ParserException.createForMalformedContainer( + "Failed to determine bitstream type", /* cause= */ null); } input.resetPeekPosition(); } diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPageHeader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPageHeader.java index 462fbe0c52..6e9102f501 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPageHeader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OggPageHeader.java @@ -140,7 +140,8 @@ import java.io.IOException; if (quiet) { return false; } else { - throw new ParserException("unsupported bit stream revision"); + throw ParserException.createForUnsupportedContainerFeature( + "unsupported bit stream revision"); } } type = scratch.readUnsignedByte(); diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java index d9339fa689..a1c4977745 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java @@ -144,7 +144,8 @@ public final class RawCcExtractor implements Extractor { } timestampUs = dataScratch.readLong(); } else { - throw new ParserException("Unsupported version number: " + version); + throw ParserException.createForMalformedContainer( + "Unsupported version number: " + version, /* cause= */ null); } remainingSampleCount = dataScratch.readUnsignedByte(); diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java index 7c93c210f3..f4fc317fdc 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/AdtsExtractor.java @@ -287,7 +287,8 @@ public final class AdtsExtractor implements Extractor { // Either the stream is malformed OR we're not parsing an ADTS stream. if (currentFrameSize <= 6) { hasCalculatedAverageFrameSize = true; - throw new ParserException("Malformed ADTS stream"); + throw ParserException.createForMalformedContainer( + "Malformed ADTS stream", /* cause= */ null); } totalValidFramesSize += currentFrameSize; if (++numValidFrames == NUM_FRAMES_FOR_AVERAGE_FRAME_SIZE) { diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index 5e0798ae61..1411541e88 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -443,7 +443,8 @@ public final class TsExtractor implements Extractor { if (endOfPacket > limit) { bytesSinceLastSync += syncBytePosition - searchStart; if (mode == MODE_HLS && bytesSinceLastSync > TS_PACKET_SIZE * 2) { - throw new ParserException("Cannot find sync byte. Most likely not a Transport Stream."); + throw ParserException.createForMalformedContainer( + "Cannot find sync byte. Most likely not a Transport Stream.", /* cause= */ null); } } else { // We have found a packet within the buffer. diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java index bb4734f183..c1dd2a6ddc 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavExtractor.java @@ -92,7 +92,8 @@ public final class WavExtractor implements Extractor { WavHeader header = WavHeaderReader.peek(input); if (header == null) { // Should only happen if the media wasn't sniffed. - throw new ParserException("Unsupported or unrecognized wav header."); + throw ParserException.createForMalformedContainer( + "Unsupported or unrecognized wav header.", /* cause= */ null); } if (header.formatType == WavUtil.TYPE_IMA_ADPCM) { @@ -117,7 +118,8 @@ public final class WavExtractor implements Extractor { @C.PcmEncoding int pcmEncoding = WavUtil.getPcmEncodingForType(header.formatType, header.bitsPerSample); if (pcmEncoding == C.ENCODING_INVALID) { - throw new ParserException("Unsupported WAV format type: " + header.formatType); + throw ParserException.createForUnsupportedContainerFeature( + "Unsupported WAV format type: " + header.formatType); } outputWriter = new PassthroughOutputWriter( @@ -217,8 +219,9 @@ public final class WavExtractor implements Extractor { int bytesPerFrame = header.numChannels * header.bitsPerSample / 8; // Validate the header. Blocks are expected to correspond to single frames. if (header.blockSize != bytesPerFrame) { - throw new ParserException( - "Expected block size: " + bytesPerFrame + "; got: " + header.blockSize); + throw ParserException.createForMalformedContainer( + "Expected block size: " + bytesPerFrame + "; got: " + header.blockSize, + /* cause= */ null); } int constantBitrate = header.frameRateHz * bytesPerFrame * 8; @@ -351,8 +354,9 @@ public final class WavExtractor implements Extractor { int expectedFramesPerBlock = (((header.blockSize - (4 * numChannels)) * 8) / (header.bitsPerSample * numChannels)) + 1; if (framesPerBlock != expectedFramesPerBlock) { - throw new ParserException( - "Expected frames per block: " + expectedFramesPerBlock + "; got: " + framesPerBlock); + throw ParserException.createForMalformedContainer( + "Expected frames per block: " + expectedFramesPerBlock + "; got: " + framesPerBlock, + /* cause= */ null); } // Calculate the number of blocks we'll need to decode to obtain an output sample of the diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java index af8ede69aa..f794933d16 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/wav/WavHeaderReader.java @@ -127,7 +127,8 @@ import java.io.IOException; bytesToSkip = ChunkHeader.SIZE_IN_BYTES + 4; } if (bytesToSkip > Integer.MAX_VALUE) { - throw new ParserException("Chunk is too large (~2GB+) to skip; id: " + chunkHeader.id); + throw ParserException.createForUnsupportedContainerFeature( + "Chunk is too large (~2GB+) to skip; id: " + chunkHeader.id); } input.skipFully((int) bytesToSkip); chunkHeader = ChunkHeader.peek(input, scratch); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index fd028caddc..7282ea6df6 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -278,7 +278,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; public void maybeThrowPrepareError() throws IOException { maybeThrowError(); if (loadingFinished && !prepared) { - throw new ParserException("Loading finished before preparation is complete."); + throw ParserException.createForMalformedContainer( + "Loading finished before preparation is complete.", /* cause= */ null); } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java index 53f7421254..7a5771e208 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/WebvttExtractor.java @@ -153,11 +153,13 @@ public final class WebvttExtractor implements Extractor { if (line.startsWith("X-TIMESTAMP-MAP")) { Matcher localTimestampMatcher = LOCAL_TIMESTAMP.matcher(line); if (!localTimestampMatcher.find()) { - throw new ParserException("X-TIMESTAMP-MAP doesn't contain local timestamp: " + line); + throw ParserException.createForMalformedContainer( + "X-TIMESTAMP-MAP doesn't contain local timestamp: " + line, /* cause= */ null); } Matcher mediaTimestampMatcher = MEDIA_TIMESTAMP.matcher(line); if (!mediaTimestampMatcher.find()) { - throw new ParserException("X-TIMESTAMP-MAP doesn't contain media timestamp: " + line); + throw ParserException.createForMalformedContainer( + "X-TIMESTAMP-MAP doesn't contain media timestamp: " + line, /* cause= */ null); } vttTimestampUs = WebvttParserUtil.parseTimestampUs( diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java index 9df0b69b58..ed7a4fe9a1 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/DefaultHlsPlaylistTracker.java @@ -567,7 +567,9 @@ public final class DefaultHlsPlaylistTracker processLoadedPlaylist((HlsMediaPlaylist) result, loadEventInfo); eventDispatcher.loadCompleted(loadEventInfo, C.DATA_TYPE_MANIFEST); } else { - playlistError = new ParserException("Loaded playlist has unexpected type."); + playlistError = + ParserException.createForMalformedManifest( + "Loaded playlist has unexpected type.", /* cause= */ null); eventDispatcher.loadError( loadEventInfo, C.DATA_TYPE_MANIFEST, playlistError, /* wasCanceled= */ true); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index d567852011..52f23448f4 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -286,7 +286,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser { public static class MissingFieldException extends ParserException { public MissingFieldException(String fieldName) { - super("Missing required field: " + fieldName); + super( + "Missing required field: " + fieldName, + /* cause= */ null, + /* contentIsMalformed= */ true, + C.DATA_TYPE_MANIFEST); } } @@ -562,7 +566,8 @@ public class SsManifestParser implements ParsingLoadable.Parser { startTime = startTimes.get(chunkIndex - 1) + lastChunkDuration; } else { // We don't have the start time, and we're unable to infer it. - throw new ParserException("Unable to infer start time"); + throw ParserException.createForMalformedManifest( + "Unable to infer start time", /* cause= */ null); } } chunkIndex++; @@ -571,7 +576,8 @@ public class SsManifestParser implements ParsingLoadable.Parser { // Handle repeated chunks. long repeatCount = parseLong(parser, KEY_FRAGMENT_REPEAT_COUNT, 1L); if (repeatCount > 1 && lastChunkDuration == C.TIME_UNSET) { - throw new ParserException("Repeated chunk with unspecified duration"); + throw ParserException.createForMalformedManifest( + "Repeated chunk with unspecified duration", /* cause= */ null); } for (int i = 1; i < repeatCount; i++) { chunkIndex++; @@ -613,7 +619,8 @@ public class SsManifestParser implements ParsingLoadable.Parser { } else if (KEY_TYPE_TEXT.equalsIgnoreCase(value)) { return C.TRACK_TYPE_TEXT; } else { - throw new ParserException("Invalid key value[" + value + "]"); + throw ParserException.createForMalformedManifest( + "Invalid key value[" + value + "]", /* cause= */ null); } } throw new MissingFieldException(KEY_TYPE);