diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java index 258390d21d..e6436de2bb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/FlacReader.java @@ -24,9 +24,9 @@ import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.FlacConstants; import com.google.android.exoplayer2.util.FlacStreamMetadata; +import com.google.android.exoplayer2.util.FlacStreamMetadata.SeekTable; import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.Util; -import java.io.IOException; import java.util.Arrays; /** @@ -70,15 +70,17 @@ import java.util.Arrays; @Override protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData) { byte[] data = packet.data; + @Nullable FlacStreamMetadata streamMetadata = this.streamMetadata; if (streamMetadata == null) { streamMetadata = new FlacStreamMetadata(data, 17); + this.streamMetadata = streamMetadata; byte[] metadata = Arrays.copyOfRange(data, 9, packet.limit()); setupData.format = streamMetadata.getFormat(metadata, /* id3Metadata= */ null); } else if ((data[0] & 0x7F) == FlacConstants.METADATA_TYPE_SEEK_TABLE) { - flacOggSeeker = new FlacOggSeeker(); - FlacStreamMetadata.SeekTable seekTable = - FlacMetadataReader.readSeekTableMetadataBlock(packet); + SeekTable seekTable = FlacMetadataReader.readSeekTableMetadataBlock(packet); streamMetadata = streamMetadata.copyWithSeekTable(seekTable); + this.streamMetadata = streamMetadata; + flacOggSeeker = new FlacOggSeeker(streamMetadata, seekTable); } else if (isAudioPacket(data)) { if (flacOggSeeker != null) { flacOggSeeker.setFirstFrameOffset(position); @@ -101,12 +103,16 @@ import java.util.Arrays; return result; } - private class FlacOggSeeker implements OggSeeker { + private static final class FlacOggSeeker implements OggSeeker { + private FlacStreamMetadata streamMetadata; + private SeekTable seekTable; private long firstFrameOffset; private long pendingSeekGranule; - public FlacOggSeeker() { + public FlacOggSeeker(FlacStreamMetadata streamMetadata, SeekTable seekTable) { + this.streamMetadata = streamMetadata; + this.seekTable = seekTable; firstFrameOffset = -1; pendingSeekGranule = -1; } @@ -116,7 +122,7 @@ import java.util.Arrays; } @Override - public long read(ExtractorInput input) throws IOException, InterruptedException { + public long read(ExtractorInput input) { if (pendingSeekGranule >= 0) { long result = -(pendingSeekGranule + 2); pendingSeekGranule = -1; @@ -127,9 +133,10 @@ import java.util.Arrays; @Override public void startSeek(long targetGranule) { - Assertions.checkNotNull(streamMetadata.seekTable); - long[] seekPointGranules = streamMetadata.seekTable.pointSampleNumbers; - int index = Util.binarySearchFloor(seekPointGranules, targetGranule, true, true); + long[] seekPointGranules = seekTable.pointSampleNumbers; + int index = + Util.binarySearchFloor( + seekPointGranules, targetGranule, /* inclusive= */ true, /* stayInBounds= */ true); pendingSeekGranule = seekPointGranules[index]; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java index 90ae3f0f47..84a7ecc9f9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java @@ -76,9 +76,19 @@ import java.util.List; putNativeOrderLong(initializationData, preskip); putNativeOrderLong(initializationData, DEFAULT_SEEK_PRE_ROLL_SAMPLES); - setupData.format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_OPUS, null, - Format.NO_VALUE, Format.NO_VALUE, channelCount, SAMPLE_RATE, initializationData, null, 0, - null); + setupData.format = + Format.createAudioSampleFormat( + null, + MimeTypes.AUDIO_OPUS, + /* codecs= */ null, + Format.NO_VALUE, + Format.NO_VALUE, + channelCount, + SAMPLE_RATE, + initializationData, + /* drmInitData= */ null, + /* selectionFlags= */ 0, + /* language= */ null); headerRead = true; } else { boolean headerPacket = packet.readInt() == OPUS_CODE; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java index 2aec9cdd59..41ae394de2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/StreamReader.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.extractor.ogg; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.Extractor; @@ -23,6 +24,7 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -51,7 +53,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; private long currentGranule; private int state; private int sampleRate; - private SetupData setupData; + @Nullable private SetupData setupData; private long lengthOfReadPacket; private boolean seekMapSet; private boolean formatSet; @@ -149,7 +151,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; boolean isLastPage = (firstPayloadPageHeader.type & 0x04) != 0; // Type 4 is end of stream. oggSeeker = new DefaultOggSeeker( - this, + /* streamReader= */ this, payloadStartPosition, input.getLength(), firstPayloadPageHeader.headerSize + firstPayloadPageHeader.bodySize, @@ -173,8 +175,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } else if (position < -1) { onSeekEnd(-(position + 2)); } + if (!seekMapSet) { - SeekMap seekMap = oggSeeker.createSeekMap(); + SeekMap seekMap = Assertions.checkNotNull(oggSeeker.createSeekMap()); extractorOutput.seekMap(seekMap); seekMapSet = true; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java index 71c6c3b73e..5c573e2ec0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.extractor.ogg; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ParserException; @@ -30,16 +31,16 @@ import java.util.ArrayList; */ /* package */ final class VorbisReader extends StreamReader { - private VorbisSetup vorbisSetup; + @Nullable private VorbisSetup vorbisSetup; private int previousPacketBlockSize; private boolean seenFirstAudioPacket; - private VorbisUtil.VorbisIdHeader vorbisIdHeader; - private VorbisUtil.CommentHeader commentHeader; + @Nullable private VorbisUtil.VorbisIdHeader vorbisIdHeader; + @Nullable private VorbisUtil.CommentHeader commentHeader; public static boolean verifyBitstreamType(ParsableByteArray data) { try { - return VorbisUtil.verifyVorbisHeaderCapturePattern(0x01, data, true); + return VorbisUtil.verifyVorbisHeaderCapturePattern(/* headerType= */ 0x01, data, true); } catch (ParserException e) { return false; } @@ -102,14 +103,24 @@ import java.util.ArrayList; codecInitialisationData.add(vorbisSetup.idHeader.data); codecInitialisationData.add(vorbisSetup.setupHeaderData); - setupData.format = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_VORBIS, null, - this.vorbisSetup.idHeader.bitrateNominal, Format.NO_VALUE, - this.vorbisSetup.idHeader.channels, (int) this.vorbisSetup.idHeader.sampleRate, - codecInitialisationData, null, 0, null); + setupData.format = + Format.createAudioSampleFormat( + null, + MimeTypes.AUDIO_VORBIS, + /* codecs= */ null, + this.vorbisSetup.idHeader.bitrateNominal, + Format.NO_VALUE, + this.vorbisSetup.idHeader.channels, + (int) this.vorbisSetup.idHeader.sampleRate, + codecInitialisationData, + null, + /* selectionFlags= */ 0, + /* language= */ null); return true; } @VisibleForTesting + @Nullable /* package */ VorbisSetup readSetupHeaders(ParsableByteArray scratch) throws IOException { if (vorbisIdHeader == null) {