Add NonNull annotations to the most extractor packages

PiperOrigin-RevId: 285961788
This commit is contained in:
olly 2019-12-17 13:34:33 +00:00 committed by Oliver Woodman
parent f10bc37831
commit dfc15733d2
22 changed files with 255 additions and 47 deletions

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer2.extractor.amr; package com.google.android.exoplayer2.extractor.amr;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
@ -28,6 +27,7 @@ import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.EOFException; import java.io.EOFException;
@ -36,6 +36,9 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.Arrays; import java.util.Arrays;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Extracts data from the AMR containers format (either AMR or AMR-WB). This follows RFC-4867, * Extracts data from the AMR containers format (either AMR or AMR-WB). This follows RFC-4867,
@ -138,9 +141,9 @@ public final class AmrExtractor implements Extractor {
private int numSamplesWithSameSize; private int numSamplesWithSameSize;
private long timeOffsetUs; private long timeOffsetUs;
private ExtractorOutput extractorOutput; @MonotonicNonNull private ExtractorOutput extractorOutput;
private TrackOutput trackOutput; @MonotonicNonNull private TrackOutput trackOutput;
@Nullable private SeekMap seekMap; @MonotonicNonNull private SeekMap seekMap;
private boolean hasOutputFormat; private boolean hasOutputFormat;
public AmrExtractor() { public AmrExtractor() {
@ -171,6 +174,7 @@ public final class AmrExtractor implements Extractor {
@Override @Override
public int read(ExtractorInput input, PositionHolder seekPosition) public int read(ExtractorInput input, PositionHolder seekPosition)
throws IOException, InterruptedException { throws IOException, InterruptedException {
assertInitialized();
if (input.getPosition() == 0) { if (input.getPosition() == 0) {
if (!readAmrHeader(input)) { if (!readAmrHeader(input)) {
throw new ParserException("Could not find AMR header."); throw new ParserException("Could not find AMR header.");
@ -245,6 +249,7 @@ public final class AmrExtractor implements Extractor {
return Arrays.equals(header, amrSignature); return Arrays.equals(header, amrSignature);
} }
@RequiresNonNull("trackOutput")
private void maybeOutputFormat() { private void maybeOutputFormat() {
if (!hasOutputFormat) { if (!hasOutputFormat) {
hasOutputFormat = true; hasOutputFormat = true;
@ -267,6 +272,7 @@ public final class AmrExtractor implements Extractor {
} }
} }
@RequiresNonNull("trackOutput")
private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException { private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException {
if (currentSampleBytesRemaining == 0) { if (currentSampleBytesRemaining == 0) {
try { try {
@ -346,6 +352,7 @@ public final class AmrExtractor implements Extractor {
return !isWideBand && (frameType < 12 || frameType > 14); return !isWideBand && (frameType < 12 || frameType > 14);
} }
@RequiresNonNull("extractorOutput")
private void maybeOutputSeekMap(long inputLength, int sampleReadResult) { private void maybeOutputSeekMap(long inputLength, int sampleReadResult) {
if (hasOutputSeekMap) { if (hasOutputSeekMap) {
return; return;
@ -370,6 +377,12 @@ public final class AmrExtractor implements Extractor {
return new ConstantBitrateSeekMap(inputLength, firstSamplePosition, bitrate, firstSampleSize); return new ConstantBitrateSeekMap(inputLength, firstSamplePosition, bitrate, firstSampleSize);
} }
@EnsuresNonNull({"extractorOutput", "trackOutput"})
private void assertInitialized() {
Assertions.checkStateNotNull(trackOutput);
Util.castNonNull(extractorOutput);
}
/** /**
* Returns the stream bitrate, given a frame size and the duration of that frame in microseconds. * Returns the stream bitrate, given a frame size and the duration of that frame in microseconds.
* *

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.amr;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.flac;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -23,11 +23,14 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Extracts data from the FLV container format. * Extracts data from the FLV container format.
@ -71,7 +74,7 @@ public final class FlvExtractor implements Extractor {
private final ParsableByteArray tagData; private final ParsableByteArray tagData;
private final ScriptTagPayloadReader metadataReader; private final ScriptTagPayloadReader metadataReader;
private ExtractorOutput extractorOutput; @MonotonicNonNull private ExtractorOutput extractorOutput;
private @States int state; private @States int state;
private boolean outputFirstSample; private boolean outputFirstSample;
private long mediaTagTimestampOffsetUs; private long mediaTagTimestampOffsetUs;
@ -80,8 +83,8 @@ public final class FlvExtractor implements Extractor {
private int tagDataSize; private int tagDataSize;
private long tagTimestampUs; private long tagTimestampUs;
private boolean outputSeekMap; private boolean outputSeekMap;
private AudioTagPayloadReader audioReader; @MonotonicNonNull private AudioTagPayloadReader audioReader;
private VideoTagPayloadReader videoReader; @MonotonicNonNull private VideoTagPayloadReader videoReader;
public FlvExtractor() { public FlvExtractor() {
scratch = new ParsableByteArray(4); scratch = new ParsableByteArray(4);
@ -143,6 +146,7 @@ public final class FlvExtractor implements Extractor {
@Override @Override
public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException, public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException,
InterruptedException { InterruptedException {
Assertions.checkStateNotNull(extractorOutput); // Asserts that init has been called.
while (true) { while (true) {
switch (state) { switch (state) {
case STATE_READING_FLV_HEADER: case STATE_READING_FLV_HEADER:
@ -178,6 +182,7 @@ public final class FlvExtractor implements Extractor {
* @throws IOException If an error occurred reading or parsing data from the source. * @throws IOException If an error occurred reading or parsing data from the source.
* @throws InterruptedException If the thread was interrupted. * @throws InterruptedException If the thread was interrupted.
*/ */
@RequiresNonNull("extractorOutput")
private boolean readFlvHeader(ExtractorInput input) throws IOException, InterruptedException { private boolean readFlvHeader(ExtractorInput input) throws IOException, InterruptedException {
if (!input.readFully(headerBuffer.data, 0, FLV_HEADER_SIZE, true)) { if (!input.readFully(headerBuffer.data, 0, FLV_HEADER_SIZE, true)) {
// We've reached the end of the stream. // We've reached the end of the stream.
@ -250,6 +255,7 @@ public final class FlvExtractor implements Extractor {
* @throws IOException If an error occurred reading or parsing data from the source. * @throws IOException If an error occurred reading or parsing data from the source.
* @throws InterruptedException If the thread was interrupted. * @throws InterruptedException If the thread was interrupted.
*/ */
@RequiresNonNull("extractorOutput")
private boolean readTagData(ExtractorInput input) throws IOException, InterruptedException { private boolean readTagData(ExtractorInput input) throws IOException, InterruptedException {
boolean wasConsumed = true; boolean wasConsumed = true;
boolean wasSampleOutput = false; boolean wasSampleOutput = false;
@ -293,6 +299,7 @@ public final class FlvExtractor implements Extractor {
return tagData; return tagData;
} }
@RequiresNonNull("extractorOutput")
private void ensureReadyForMediaOutput() { private void ensureReadyForMediaOutput() {
if (!outputSeekMap) { if (!outputSeekMap) {
extractorOutput.seekMap(new SeekMap.Unseekable(C.TIME_UNSET)); extractorOutput.seekMap(new SeekMap.Unseekable(C.TIME_UNSET));

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.flv;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.extractor.mkv; package com.google.android.exoplayer2.extractor.mkv;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
@ -26,6 +27,8 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Default implementation of {@link EbmlReader}. * Default implementation of {@link EbmlReader}.
@ -52,7 +55,7 @@ import java.util.ArrayDeque;
private final ArrayDeque<MasterElement> masterElementsStack; private final ArrayDeque<MasterElement> masterElementsStack;
private final VarintReader varintReader; private final VarintReader varintReader;
private EbmlProcessor processor; @MonotonicNonNull private EbmlProcessor processor;
private @ElementState int elementState; private @ElementState int elementState;
private int elementId; private int elementId;
private long elementContentSize; private long elementContentSize;
@ -79,8 +82,8 @@ import java.util.ArrayDeque;
public boolean read(ExtractorInput input) throws IOException, InterruptedException { public boolean read(ExtractorInput input) throws IOException, InterruptedException {
Assertions.checkNotNull(processor); Assertions.checkNotNull(processor);
while (true) { while (true) {
if (!masterElementsStack.isEmpty() MasterElement head = masterElementsStack.peek();
&& input.getPosition() >= masterElementsStack.peek().elementEndPosition) { if (head != null && input.getPosition() >= head.elementEndPosition) {
processor.endMasterElement(masterElementsStack.pop().elementId); processor.endMasterElement(masterElementsStack.pop().elementId);
return true; return true;
} }
@ -159,8 +162,9 @@ import java.util.ArrayDeque;
* @throws IOException If an error occurs reading from the input. * @throws IOException If an error occurs reading from the input.
* @throws InterruptedException If the thread is interrupted. * @throws InterruptedException If the thread is interrupted.
*/ */
private long maybeResyncToNextLevel1Element(ExtractorInput input) throws IOException, @RequiresNonNull("processor")
InterruptedException { private long maybeResyncToNextLevel1Element(ExtractorInput input)
throws IOException, InterruptedException {
input.resetPeekPosition(); input.resetPeekPosition();
while (true) { while (true) {
input.peekFully(scratch, 0, MAX_ID_BYTES); input.peekFully(scratch, 0, MAX_ID_BYTES);

View File

@ -57,6 +57,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.UUID; import java.util.UUID;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Extracts data from the Matroska and WebM container formats. */ /** Extracts data from the Matroska and WebM container formats. */
public class MatroskaExtractor implements Extractor { public class MatroskaExtractor implements Extractor {
@ -342,7 +344,7 @@ public class MatroskaExtractor implements Extractor {
private long durationUs = C.TIME_UNSET; private long durationUs = C.TIME_UNSET;
// The track corresponding to the current TrackEntry element, or null. // The track corresponding to the current TrackEntry element, or null.
private Track currentTrack; @Nullable private Track currentTrack;
// Whether a seek map has been sent to the output. // Whether a seek map has been sent to the output.
private boolean sentSeekMap; private boolean sentSeekMap;
@ -356,8 +358,8 @@ public class MatroskaExtractor implements Extractor {
private long cuesContentPosition = C.POSITION_UNSET; private long cuesContentPosition = C.POSITION_UNSET;
private long seekPositionAfterBuildingCues = C.POSITION_UNSET; private long seekPositionAfterBuildingCues = C.POSITION_UNSET;
private long clusterTimecodeUs = C.TIME_UNSET; private long clusterTimecodeUs = C.TIME_UNSET;
private LongArray cueTimesUs; @Nullable private LongArray cueTimesUs;
private LongArray cueClusterPositions; @Nullable private LongArray cueClusterPositions;
private boolean seenClusterPositionForCurrentCuePoint; private boolean seenClusterPositionForCurrentCuePoint;
// Reading state. // Reading state.
@ -372,8 +374,7 @@ public class MatroskaExtractor implements Extractor {
private int[] blockSampleSizes; private int[] blockSampleSizes;
private int blockTrackNumber; private int blockTrackNumber;
private int blockTrackNumberLength; private int blockTrackNumberLength;
@C.BufferFlags @C.BufferFlags private int blockFlags;
private int blockFlags;
private int blockAdditionalId; private int blockAdditionalId;
private boolean blockHasReferenceBlock; private boolean blockHasReferenceBlock;
@ -389,7 +390,7 @@ public class MatroskaExtractor implements Extractor {
private boolean sampleInitializationVectorRead; private boolean sampleInitializationVectorRead;
// Extractor outputs. // Extractor outputs.
private ExtractorOutput extractorOutput; @MonotonicNonNull private ExtractorOutput extractorOutput;
public MatroskaExtractor() { public MatroskaExtractor() {
this(0); this(0);
@ -415,6 +416,7 @@ public class MatroskaExtractor implements Extractor {
encryptionInitializationVector = new ParsableByteArray(ENCRYPTION_IV_SIZE); encryptionInitializationVector = new ParsableByteArray(ENCRYPTION_IV_SIZE);
encryptionSubsampleData = new ParsableByteArray(); encryptionSubsampleData = new ParsableByteArray();
blockAdditionalData = new ParsableByteArray(); blockAdditionalData = new ParsableByteArray();
blockSampleSizes = new int[1];
} }
@Override @Override
@ -1924,7 +1926,7 @@ public class MatroskaExtractor implements Extractor {
String mimeType; String mimeType;
int maxInputSize = Format.NO_VALUE; int maxInputSize = Format.NO_VALUE;
@C.PcmEncoding int pcmEncoding = Format.NO_VALUE; @C.PcmEncoding int pcmEncoding = Format.NO_VALUE;
List<byte[]> initializationData = null; @Nullable List<byte[]> initializationData = null;
switch (codecId) { switch (codecId) {
case CODEC_ID_VP8: case CODEC_ID_VP8:
mimeType = MimeTypes.VIDEO_VP8; mimeType = MimeTypes.VIDEO_VP8;
@ -1958,7 +1960,8 @@ public class MatroskaExtractor implements Extractor {
nalUnitLengthFieldLength = hevcConfig.nalUnitLengthFieldLength; nalUnitLengthFieldLength = hevcConfig.nalUnitLengthFieldLength;
break; break;
case CODEC_ID_FOURCC: case CODEC_ID_FOURCC:
Pair<String, List<byte[]>> pair = parseFourCcPrivate(new ParsableByteArray(codecPrivate)); Pair<String, @NullableType List<byte[]>> pair =
parseFourCcPrivate(new ParsableByteArray(codecPrivate));
mimeType = pair.first; mimeType = pair.first;
initializationData = pair.second; initializationData = pair.second;
break; break;
@ -2220,8 +2223,8 @@ public class MatroskaExtractor implements Extractor {
* is {@code null}. * is {@code null}.
* @throws ParserException If the initialization data could not be built. * @throws ParserException If the initialization data could not be built.
*/ */
private static Pair<String, List<byte[]>> parseFourCcPrivate(ParsableByteArray buffer) private static Pair<String, @NullableType List<byte[]>> parseFourCcPrivate(
throws ParserException { ParsableByteArray buffer) throws ParserException {
try { try {
buffer.skipBytes(16); // size(4), width(4), height(4), planes(2), bitcount(2). buffer.skipBytes(16); // size(4), width(4), height(4), planes(2), bitcount(2).
long compression = buffer.readLittleEndianUnsignedInt(); long compression = buffer.readLittleEndianUnsignedInt();

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.mkv;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -34,12 +34,17 @@ import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder; import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate; import com.google.android.exoplayer2.metadata.id3.Id3Decoder.FramePredicate;
import com.google.android.exoplayer2.metadata.id3.MlltFrame; import com.google.android.exoplayer2.metadata.id3.MlltFrame;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Extracts data from the MP3 container format. * Extracts data from the MP3 container format.
@ -107,13 +112,13 @@ public final class Mp3Extractor implements Extractor {
private final Id3Peeker id3Peeker; private final Id3Peeker id3Peeker;
// Extractor outputs. // Extractor outputs.
private ExtractorOutput extractorOutput; @MonotonicNonNull private ExtractorOutput extractorOutput;
private TrackOutput trackOutput; @MonotonicNonNull private TrackOutput trackOutput;
private int synchronizedHeaderData; private int synchronizedHeaderData;
private Metadata metadata; @Nullable private Metadata metadata;
@Nullable private Seeker seeker; @MonotonicNonNull private Seeker seeker;
private boolean disableSeeking; private boolean disableSeeking;
private long basisTimeUs; private long basisTimeUs;
private long samplesRead; private long samplesRead;
@ -176,6 +181,7 @@ public final class Mp3Extractor implements Extractor {
@Override @Override
public int read(ExtractorInput input, PositionHolder seekPosition) public int read(ExtractorInput input, PositionHolder seekPosition)
throws IOException, InterruptedException { throws IOException, InterruptedException {
assertInitialized();
if (synchronizedHeaderData == 0) { if (synchronizedHeaderData == 0) {
try { try {
synchronize(input, false); synchronize(input, false);
@ -242,6 +248,7 @@ public final class Mp3Extractor implements Extractor {
// Internal methods. // Internal methods.
@RequiresNonNull({"trackOutput", "seeker"})
private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException { private int readSample(ExtractorInput extractorInput) throws IOException, InterruptedException {
if (sampleBytesRemaining == 0) { if (sampleBytesRemaining == 0) {
extractorInput.resetPeekPosition(); extractorInput.resetPeekPosition();
@ -390,6 +397,7 @@ public final class Mp3Extractor implements Extractor {
* @throws InterruptedException Thrown if reading from the stream was interrupted. Not expected if * @throws InterruptedException Thrown if reading from the stream was interrupted. Not expected if
* the next two frames were already peeked during synchronization. * the next two frames were already peeked during synchronization.
*/ */
@Nullable
private Seeker maybeReadSeekFrame(ExtractorInput input) throws IOException, InterruptedException { private Seeker maybeReadSeekFrame(ExtractorInput input) throws IOException, InterruptedException {
ParsableByteArray frame = new ParsableByteArray(synchronizedHeader.frameSize); ParsableByteArray frame = new ParsableByteArray(synchronizedHeader.frameSize);
input.peekFully(frame.data, 0, synchronizedHeader.frameSize); input.peekFully(frame.data, 0, synchronizedHeader.frameSize);
@ -397,7 +405,7 @@ public final class Mp3Extractor implements Extractor {
? (synchronizedHeader.channels != 1 ? 36 : 21) // MPEG 1 ? (synchronizedHeader.channels != 1 ? 36 : 21) // MPEG 1
: (synchronizedHeader.channels != 1 ? 21 : 13); // MPEG 2 or 2.5 : (synchronizedHeader.channels != 1 ? 21 : 13); // MPEG 2 or 2.5
int seekHeader = getSeekFrameHeader(frame, xingBase); int seekHeader = getSeekFrameHeader(frame, xingBase);
Seeker seeker; @Nullable Seeker seeker;
if (seekHeader == SEEK_HEADER_XING || seekHeader == SEEK_HEADER_INFO) { if (seekHeader == SEEK_HEADER_XING || seekHeader == SEEK_HEADER_INFO) {
seeker = XingSeeker.create(input.getLength(), input.getPosition(), synchronizedHeader, frame); seeker = XingSeeker.create(input.getLength(), input.getPosition(), synchronizedHeader, frame);
if (seeker != null && !gaplessInfoHolder.hasGaplessInfo()) { if (seeker != null && !gaplessInfoHolder.hasGaplessInfo()) {
@ -435,6 +443,12 @@ public final class Mp3Extractor implements Extractor {
return new ConstantBitrateSeeker(input.getLength(), input.getPosition(), synchronizedHeader); return new ConstantBitrateSeeker(input.getLength(), input.getPosition(), synchronizedHeader);
} }
@EnsuresNonNull({"extractorOutput", "trackOutput"})
private void assertInitialized() {
Assertions.checkStateNotNull(trackOutput);
Util.castNonNull(extractorOutput);
}
/** /**
* Returns whether the headers match in those bits masked by {@link #MPEG_AUDIO_HEADER_MASK}. * Returns whether the headers match in those bits masked by {@link #MPEG_AUDIO_HEADER_MASK}.
*/ */
@ -465,7 +479,8 @@ public final class Mp3Extractor implements Extractor {
} }
@Nullable @Nullable
private static MlltSeeker maybeHandleSeekMetadata(Metadata metadata, long firstFramePosition) { private static MlltSeeker maybeHandleSeekMetadata(
@Nullable Metadata metadata, long firstFramePosition) {
if (metadata != null) { if (metadata != null) {
int length = metadata.length(); int length = metadata.length();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
@ -477,6 +492,4 @@ public final class Mp3Extractor implements Extractor {
} }
return null; return null;
} }
} }

View File

@ -41,7 +41,8 @@ import com.google.android.exoplayer2.util.Util;
* @return A {@link VbriSeeker} for seeking in the stream, or {@code null} if the required * @return A {@link VbriSeeker} for seeking in the stream, or {@code null} if the required
* information is not present. * information is not present.
*/ */
public static @Nullable VbriSeeker create( @Nullable
public static VbriSeeker create(
long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) { long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) {
frame.skipBytes(10); frame.skipBytes(10);
int numFrames = frame.readInt(); int numFrames = frame.readInt();

View File

@ -42,7 +42,8 @@ import com.google.android.exoplayer2.util.Util;
* @return A {@link XingSeeker} for seeking in the stream, or {@code null} if the required * @return A {@link XingSeeker} for seeking in the stream, or {@code null} if the required
* information is not present. * information is not present.
*/ */
public static @Nullable XingSeeker create( @Nullable
public static XingSeeker create(
long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) { long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) {
int samplesPerFrame = mpegAudioHeader.samplesPerFrame; int samplesPerFrame = mpegAudioHeader.samplesPerFrame;
int sampleRate = mpegAudioHeader.sampleRate; int sampleRate = mpegAudioHeader.sampleRate;

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.mp3;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.extractor.ogg; package com.google.android.exoplayer2.extractor.ogg;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.ParserException;
@ -39,7 +40,7 @@ import java.io.IOException;
private static final int STATE_SKIP = 3; private static final int STATE_SKIP = 3;
private static final int STATE_IDLE = 4; private static final int STATE_IDLE = 4;
private final OggPageHeader pageHeader = new OggPageHeader(); private final OggPageHeader pageHeader;
private final long payloadStartPosition; private final long payloadStartPosition;
private final long payloadEndPosition; private final long payloadEndPosition;
private final StreamReader streamReader; private final StreamReader streamReader;
@ -83,6 +84,7 @@ import java.io.IOException;
} else { } else {
state = STATE_SEEK_TO_END; state = STATE_SEEK_TO_END;
} }
pageHeader = new OggPageHeader();
} }
@Override @Override
@ -121,6 +123,7 @@ import java.io.IOException;
} }
@Override @Override
@Nullable
public OggSeekMap createSeekMap() { public OggSeekMap createSeekMap() {
return totalGranules != 0 ? new OggSeekMap() : null; return totalGranules != 0 ? new OggSeekMap() : null;
} }

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.extractor.ogg; package com.google.android.exoplayer2.extractor.ogg;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.FlacFrameReader; import com.google.android.exoplayer2.extractor.FlacFrameReader;
import com.google.android.exoplayer2.extractor.FlacMetadataReader; import com.google.android.exoplayer2.extractor.FlacMetadataReader;
@ -37,8 +38,8 @@ import java.util.Arrays;
private static final int FRAME_HEADER_SAMPLE_NUMBER_OFFSET = 4; private static final int FRAME_HEADER_SAMPLE_NUMBER_OFFSET = 4;
private FlacStreamMetadata streamMetadata; @Nullable private FlacStreamMetadata streamMetadata;
private FlacOggSeeker flacOggSeeker; @Nullable private FlacOggSeeker flacOggSeeker;
public static boolean verifyBitstreamType(ParsableByteArray data) { public static boolean verifyBitstreamType(ParsableByteArray data) {
return data.bytesLeft() >= 5 && data.readUnsignedByte() == 0x7F && // packet type return data.bytesLeft() >= 5 && data.readUnsignedByte() == 0x7F && // packet type

View File

@ -23,8 +23,11 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.ExtractorsFactory; import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException; import java.io.IOException;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* Extracts data from the Ogg container format. * Extracts data from the Ogg container format.
@ -36,8 +39,8 @@ public class OggExtractor implements Extractor {
private static final int MAX_VERIFICATION_BYTES = 8; private static final int MAX_VERIFICATION_BYTES = 8;
private ExtractorOutput output; @MonotonicNonNull private ExtractorOutput output;
private StreamReader streamReader; @MonotonicNonNull private StreamReader streamReader;
private boolean streamReaderInitialized; private boolean streamReaderInitialized;
@Override @Override
@ -69,6 +72,7 @@ public class OggExtractor implements Extractor {
@Override @Override
public int read(ExtractorInput input, PositionHolder seekPosition) public int read(ExtractorInput input, PositionHolder seekPosition)
throws IOException, InterruptedException { throws IOException, InterruptedException {
Assertions.checkStateNotNull(output); // Asserts that init has been called.
if (streamReader == null) { if (streamReader == null) {
if (!sniffInternal(input)) { if (!sniffInternal(input)) {
throw new ParserException("Failed to determine bitstream type"); throw new ParserException("Failed to determine bitstream type");
@ -84,6 +88,7 @@ public class OggExtractor implements Extractor {
return streamReader.read(input, seekPosition); return streamReader.read(input, seekPosition);
} }
@EnsuresNonNullIf(expression = "streamReader", result = true)
private boolean sniffInternal(ExtractorInput input) throws IOException, InterruptedException { private boolean sniffInternal(ExtractorInput input) throws IOException, InterruptedException {
OggPageHeader header = new OggPageHeader(); OggPageHeader header = new OggPageHeader();
if (!header.populate(input, true) || (header.type & 0x02) != 0x02) { if (!header.populate(input, true) || (header.type & 0x02) != 0x02) {

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.extractor.ogg; package com.google.android.exoplayer2.extractor.ogg;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import java.io.IOException; import java.io.IOException;
@ -27,9 +28,10 @@ import java.io.IOException;
/* package */ interface OggSeeker { /* package */ interface OggSeeker {
/** /**
* Returns a {@link SeekMap} that returns an initial estimated position for progressive seeking * Returns a {@link SeekMap} that returns an initial estimated position for progressive seeking or
* or the final position for direct seeking. Returns null if {@link #read} has yet to return -1. * the final position for direct seeking. Returns null if {@link #read} has yet to return -1.
*/ */
@Nullable
SeekMap createSeekMap(); SeekMap createSeekMap();
/** /**

View File

@ -25,6 +25,7 @@ import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException; import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** StreamReader abstract class. */ /** StreamReader abstract class. */
@SuppressWarnings("UngroupedOverloads") @SuppressWarnings("UngroupedOverloads")
@ -42,9 +43,9 @@ import java.io.IOException;
private final OggPacket oggPacket; private final OggPacket oggPacket;
private TrackOutput trackOutput; @MonotonicNonNull private TrackOutput trackOutput;
private ExtractorOutput extractorOutput; @MonotonicNonNull private ExtractorOutput extractorOutput;
private OggSeeker oggSeeker; @MonotonicNonNull private OggSeeker oggSeeker;
private long targetGranule; private long targetGranule;
private long payloadStartPosition; private long payloadStartPosition;
private long currentGranule; private long currentGranule;

View File

@ -88,7 +88,7 @@ import java.util.ArrayList;
@Override @Override
protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData) protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData)
throws IOException, InterruptedException { throws IOException {
if (vorbisSetup != null) { if (vorbisSetup != null) {
return false; return false;
} }

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.ogg;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -24,8 +24,11 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException; import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* Extracts data from the RawCC container format. * Extracts data from the RawCC container format.
@ -44,11 +47,9 @@ public final class RawCcExtractor implements Extractor {
private static final int STATE_READING_SAMPLES = 2; private static final int STATE_READING_SAMPLES = 2;
private final Format format; private final Format format;
private final ParsableByteArray dataScratch; private final ParsableByteArray dataScratch;
private TrackOutput trackOutput; @MonotonicNonNull private TrackOutput trackOutput;
private int parserState; private int parserState;
private int version; private int version;
private long timestampUs; private long timestampUs;
@ -79,6 +80,7 @@ public final class RawCcExtractor implements Extractor {
@Override @Override
public int read(ExtractorInput input, PositionHolder seekPosition) public int read(ExtractorInput input, PositionHolder seekPosition)
throws IOException, InterruptedException { throws IOException, InterruptedException {
Assertions.checkStateNotNull(trackOutput); // Asserts that init has been called.
while (true) { while (true) {
switch (parserState) { switch (parserState) {
case STATE_READING_HEADER: case STATE_READING_HEADER:
@ -153,6 +155,7 @@ public final class RawCcExtractor implements Extractor {
return true; return true;
} }
@RequiresNonNull("trackOutput")
private void parseSamples(ExtractorInput input) throws IOException, InterruptedException { private void parseSamples(ExtractorInput input) throws IOException, InterruptedException {
for (; remainingSampleCount > 0; remainingSampleCount--) { for (; remainingSampleCount > 0; remainingSampleCount--) {
dataScratch.reset(); dataScratch.reset();
@ -166,5 +169,4 @@ public final class RawCcExtractor implements Extractor {
trackOutput.sampleMetadata(timestampUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null); trackOutput.sampleMetadata(timestampUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null);
} }
} }
} }

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.rawcc;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.extractor.wav;
import com.google.android.exoplayer2.util.NonNullApi;