Remove HlsMediaChunk from null-checking blacklist

PiperOrigin-RevId: 274566133
This commit is contained in:
ibaker 2019-10-14 14:26:57 +01:00 committed by Oliver Woodman
parent d36abf966e
commit e670b1d0f6

View File

@ -23,6 +23,7 @@ import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.DefaultExtractorInput;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.metadata.Metadata; 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.PrivFrame; import com.google.android.exoplayer2.metadata.id3.PrivFrame;
@ -30,6 +31,7 @@ import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
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.TimestampAdjuster; import com.google.android.exoplayer2.util.TimestampAdjuster;
import com.google.android.exoplayer2.util.UriUtil; import com.google.android.exoplayer2.util.UriUtil;
@ -39,6 +41,9 @@ import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** /**
* An HLS {@link MediaChunk}. * An HLS {@link MediaChunk}.
@ -93,7 +98,9 @@ import java.util.concurrent.atomic.AtomicInteger;
/* key= */ null); /* key= */ null);
boolean mediaSegmentEncrypted = mediaSegmentKey != null; boolean mediaSegmentEncrypted = mediaSegmentKey != null;
byte[] mediaSegmentIv = byte[] mediaSegmentIv =
mediaSegmentEncrypted ? getEncryptionIvArray(mediaSegment.encryptionIV) : null; mediaSegmentEncrypted
? getEncryptionIvArray(Assertions.checkNotNull(mediaSegment.encryptionIV))
: null;
DataSource mediaDataSource = buildDataSource(dataSource, mediaSegmentKey, mediaSegmentIv); DataSource mediaDataSource = buildDataSource(dataSource, mediaSegmentKey, mediaSegmentIv);
// Init segment. // Init segment.
@ -104,7 +111,9 @@ import java.util.concurrent.atomic.AtomicInteger;
if (initSegment != null) { if (initSegment != null) {
initSegmentEncrypted = initSegmentKey != null; initSegmentEncrypted = initSegmentKey != null;
byte[] initSegmentIv = byte[] initSegmentIv =
initSegmentEncrypted ? getEncryptionIvArray(initSegment.encryptionIV) : null; initSegmentEncrypted
? getEncryptionIvArray(Assertions.checkNotNull(initSegment.encryptionIV))
: null;
Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url); Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
initDataSpec = initDataSpec =
new DataSpec( new DataSpec(
@ -170,6 +179,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public static final String PRIV_TIMESTAMP_FRAME_OWNER = public static final String PRIV_TIMESTAMP_FRAME_OWNER =
"com.apple.streaming.transportStreamTimestamp"; "com.apple.streaming.transportStreamTimestamp";
private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder();
private static final AtomicInteger uidSource = new AtomicInteger(); private static final AtomicInteger uidSource = new AtomicInteger();
@ -186,8 +196,12 @@ import java.util.concurrent.atomic.AtomicInteger;
/** The url of the playlist from which this chunk was obtained. */ /** The url of the playlist from which this chunk was obtained. */
public final Uri playlistUrl; public final Uri playlistUrl;
@Nullable private final DataSource initDataSource; // These should be final, but can't be due to
@Nullable private final DataSpec initDataSpec; // https://github.com/typetools/checker-framework/issues/2215
@MonotonicNonNull private DataSource initDataSource;
@MonotonicNonNull private DataSpec initDataSpec;
@MonotonicNonNull private Extractor previousExtractor;
private final boolean isMasterTimestampSource; private final boolean isMasterTimestampSource;
private final boolean hasGapTag; private final boolean hasGapTag;
private final TimestampAdjuster timestampAdjuster; private final TimestampAdjuster timestampAdjuster;
@ -195,15 +209,14 @@ import java.util.concurrent.atomic.AtomicInteger;
private final HlsExtractorFactory extractorFactory; private final HlsExtractorFactory extractorFactory;
@Nullable private final List<Format> muxedCaptionFormats; @Nullable private final List<Format> muxedCaptionFormats;
@Nullable private final DrmInitData drmInitData; @Nullable private final DrmInitData drmInitData;
@Nullable private final Extractor previousExtractor;
private final Id3Decoder id3Decoder; private final Id3Decoder id3Decoder;
private final ParsableByteArray scratchId3Data; private final ParsableByteArray scratchId3Data;
private final boolean mediaSegmentEncrypted; private final boolean mediaSegmentEncrypted;
private final boolean initSegmentEncrypted; private final boolean initSegmentEncrypted;
private Extractor extractor; @MonotonicNonNull private Extractor extractor;
private boolean isExtractorReusable; private boolean isExtractorReusable;
private HlsSampleStreamWrapper output; @MonotonicNonNull private HlsSampleStreamWrapper output;
// nextLoadPosition refers to the init segment if initDataLoadRequired is true. // nextLoadPosition refers to the init segment if initDataLoadRequired is true.
// Otherwise, nextLoadPosition refers to the media segment. // Otherwise, nextLoadPosition refers to the media segment.
private int nextLoadPosition; private int nextLoadPosition;
@ -217,13 +230,13 @@ import java.util.concurrent.atomic.AtomicInteger;
DataSpec dataSpec, DataSpec dataSpec,
Format format, Format format,
boolean mediaSegmentEncrypted, boolean mediaSegmentEncrypted,
DataSource initDataSource, @Nullable DataSource initDataSource,
@Nullable DataSpec initDataSpec, @Nullable DataSpec initDataSpec,
boolean initSegmentEncrypted, boolean initSegmentEncrypted,
Uri playlistUrl, Uri playlistUrl,
@Nullable List<Format> muxedCaptionFormats, @Nullable List<Format> muxedCaptionFormats,
int trackSelectionReason, int trackSelectionReason,
Object trackSelectionData, @Nullable Object trackSelectionData,
long startTimeUs, long startTimeUs,
long endTimeUs, long endTimeUs,
long chunkMediaSequence, long chunkMediaSequence,
@ -247,8 +260,12 @@ import java.util.concurrent.atomic.AtomicInteger;
chunkMediaSequence); chunkMediaSequence);
this.mediaSegmentEncrypted = mediaSegmentEncrypted; this.mediaSegmentEncrypted = mediaSegmentEncrypted;
this.discontinuitySequenceNumber = discontinuitySequenceNumber; this.discontinuitySequenceNumber = discontinuitySequenceNumber;
this.initDataSource = initDataSource; // Workaround for https://github.com/typetools/checker-framework/issues/2215
if (initDataSpec != null) {
this.initDataSpec = initDataSpec; this.initDataSpec = initDataSpec;
this.initDataSource = Assertions.checkNotNull(initDataSource);
initDataLoadRequired = true;
}
this.initSegmentEncrypted = initSegmentEncrypted; this.initSegmentEncrypted = initSegmentEncrypted;
this.playlistUrl = playlistUrl; this.playlistUrl = playlistUrl;
this.isMasterTimestampSource = isMasterTimestampSource; this.isMasterTimestampSource = isMasterTimestampSource;
@ -257,11 +274,13 @@ import java.util.concurrent.atomic.AtomicInteger;
this.extractorFactory = extractorFactory; this.extractorFactory = extractorFactory;
this.muxedCaptionFormats = muxedCaptionFormats; this.muxedCaptionFormats = muxedCaptionFormats;
this.drmInitData = drmInitData; this.drmInitData = drmInitData;
// Workaround for https://github.com/typetools/checker-framework/issues/2215
if (previousExtractor != null) {
this.previousExtractor = previousExtractor; this.previousExtractor = previousExtractor;
}
this.id3Decoder = id3Decoder; this.id3Decoder = id3Decoder;
this.scratchId3Data = scratchId3Data; this.scratchId3Data = scratchId3Data;
this.shouldSpliceIn = shouldSpliceIn; this.shouldSpliceIn = shouldSpliceIn;
initDataLoadRequired = initDataSpec != null;
uid = uidSource.getAndIncrement(); uid = uidSource.getAndIncrement();
} }
@ -289,6 +308,8 @@ import java.util.concurrent.atomic.AtomicInteger;
@Override @Override
public void load() throws IOException, InterruptedException { public void load() throws IOException, InterruptedException {
// output == null means init() hasn't been called.
Assertions.checkNotNull(output);
if (extractor == null && previousExtractor != null) { if (extractor == null && previousExtractor != null) {
extractor = previousExtractor; extractor = previousExtractor;
isExtractorReusable = true; isExtractorReusable = true;
@ -306,15 +327,20 @@ import java.util.concurrent.atomic.AtomicInteger;
// Internal methods. // Internal methods.
@RequiresNonNull("output")
private void maybeLoadInitData() throws IOException, InterruptedException { private void maybeLoadInitData() throws IOException, InterruptedException {
if (!initDataLoadRequired) { if (!initDataLoadRequired) {
return; return;
} }
// initDataLoadRequired => initDataSource != null && initDataSpec != null
Assertions.checkNotNull(initDataSource);
Assertions.checkNotNull(initDataSpec);
feedDataToExtractor(initDataSource, initDataSpec, initSegmentEncrypted); feedDataToExtractor(initDataSource, initDataSpec, initSegmentEncrypted);
nextLoadPosition = 0; nextLoadPosition = 0;
initDataLoadRequired = false; initDataLoadRequired = false;
} }
@RequiresNonNull("output")
private void loadMedia() throws IOException, InterruptedException { private void loadMedia() throws IOException, InterruptedException {
if (!isMasterTimestampSource) { if (!isMasterTimestampSource) {
timestampAdjuster.waitUntilInitialized(); timestampAdjuster.waitUntilInitialized();
@ -330,6 +356,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* concludes (because of a thrown exception or because the operation finishes), the number of fed * concludes (because of a thrown exception or because the operation finishes), the number of fed
* bytes is written to {@code nextLoadPosition}. * bytes is written to {@code nextLoadPosition}.
*/ */
@RequiresNonNull("output")
private void feedDataToExtractor( private void feedDataToExtractor(
DataSource dataSource, DataSpec dataSpec, boolean dataIsEncrypted) DataSource dataSource, DataSpec dataSpec, boolean dataIsEncrypted)
throws IOException, InterruptedException { throws IOException, InterruptedException {
@ -354,7 +381,7 @@ import java.util.concurrent.atomic.AtomicInteger;
try { try {
int result = Extractor.RESULT_CONTINUE; int result = Extractor.RESULT_CONTINUE;
while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
result = extractor.read(input, /* seekPosition= */ null); result = extractor.read(input, DUMMY_POSITION_HOLDER);
} }
} finally { } finally {
nextLoadPosition = (int) (input.getPosition() - dataSpec.absoluteStreamPosition); nextLoadPosition = (int) (input.getPosition() - dataSpec.absoluteStreamPosition);
@ -364,6 +391,8 @@ import java.util.concurrent.atomic.AtomicInteger;
} }
} }
@RequiresNonNull("output")
@EnsuresNonNull("extractor")
private DefaultExtractorInput prepareExtraction(DataSource dataSource, DataSpec dataSpec) private DefaultExtractorInput prepareExtraction(DataSource dataSource, DataSpec dataSpec)
throws IOException, InterruptedException { throws IOException, InterruptedException {
long bytesToRead = dataSource.open(dataSpec); long bytesToRead = dataSource.open(dataSpec);
@ -483,10 +512,15 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* If the segment is fully encrypted, returns an {@link Aes128DataSource} that wraps the original * If the segment is fully encrypted, returns an {@link Aes128DataSource} that wraps the original
* in order to decrypt the loaded data. Else returns the original. * in order to decrypt the loaded data. Else returns the original.
*
* <p>{@code fullSegmentEncryptionKey} & {@code encryptionIv} can either both be null, or neither.
*/ */
private static DataSource buildDataSource(DataSource dataSource, byte[] fullSegmentEncryptionKey, private static DataSource buildDataSource(
byte[] encryptionIv) { DataSource dataSource,
@Nullable byte[] fullSegmentEncryptionKey,
@Nullable byte[] encryptionIv) {
if (fullSegmentEncryptionKey != null) { if (fullSegmentEncryptionKey != null) {
Assertions.checkNotNull(encryptionIv);
return new Aes128DataSource(dataSource, fullSegmentEncryptionKey, encryptionIv); return new Aes128DataSource(dataSource, fullSegmentEncryptionKey, encryptionIv);
} }
return dataSource; return dataSource;