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.Extractor;
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.id3.Id3Decoder;
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.upstream.DataSource;
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.TimestampAdjuster;
import com.google.android.exoplayer2.util.UriUtil;
@ -39,6 +41,9 @@ import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
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}.
@ -93,7 +98,9 @@ import java.util.concurrent.atomic.AtomicInteger;
/* key= */ null);
boolean mediaSegmentEncrypted = mediaSegmentKey != null;
byte[] mediaSegmentIv =
mediaSegmentEncrypted ? getEncryptionIvArray(mediaSegment.encryptionIV) : null;
mediaSegmentEncrypted
? getEncryptionIvArray(Assertions.checkNotNull(mediaSegment.encryptionIV))
: null;
DataSource mediaDataSource = buildDataSource(dataSource, mediaSegmentKey, mediaSegmentIv);
// Init segment.
@ -104,7 +111,9 @@ import java.util.concurrent.atomic.AtomicInteger;
if (initSegment != null) {
initSegmentEncrypted = initSegmentKey != null;
byte[] initSegmentIv =
initSegmentEncrypted ? getEncryptionIvArray(initSegment.encryptionIV) : null;
initSegmentEncrypted
? getEncryptionIvArray(Assertions.checkNotNull(initSegment.encryptionIV))
: null;
Uri initSegmentUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, initSegment.url);
initDataSpec =
new DataSpec(
@ -170,6 +179,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public static final String PRIV_TIMESTAMP_FRAME_OWNER =
"com.apple.streaming.transportStreamTimestamp";
private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder();
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. */
public final Uri playlistUrl;
@Nullable private final DataSource initDataSource;
@Nullable private final DataSpec initDataSpec;
// These should be final, but can't be due to
// 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 hasGapTag;
private final TimestampAdjuster timestampAdjuster;
@ -195,15 +209,14 @@ import java.util.concurrent.atomic.AtomicInteger;
private final HlsExtractorFactory extractorFactory;
@Nullable private final List<Format> muxedCaptionFormats;
@Nullable private final DrmInitData drmInitData;
@Nullable private final Extractor previousExtractor;
private final Id3Decoder id3Decoder;
private final ParsableByteArray scratchId3Data;
private final boolean mediaSegmentEncrypted;
private final boolean initSegmentEncrypted;
private Extractor extractor;
@MonotonicNonNull private Extractor extractor;
private boolean isExtractorReusable;
private HlsSampleStreamWrapper output;
@MonotonicNonNull private HlsSampleStreamWrapper output;
// nextLoadPosition refers to the init segment if initDataLoadRequired is true.
// Otherwise, nextLoadPosition refers to the media segment.
private int nextLoadPosition;
@ -217,13 +230,13 @@ import java.util.concurrent.atomic.AtomicInteger;
DataSpec dataSpec,
Format format,
boolean mediaSegmentEncrypted,
DataSource initDataSource,
@Nullable DataSource initDataSource,
@Nullable DataSpec initDataSpec,
boolean initSegmentEncrypted,
Uri playlistUrl,
@Nullable List<Format> muxedCaptionFormats,
int trackSelectionReason,
Object trackSelectionData,
@Nullable Object trackSelectionData,
long startTimeUs,
long endTimeUs,
long chunkMediaSequence,
@ -247,8 +260,12 @@ import java.util.concurrent.atomic.AtomicInteger;
chunkMediaSequence);
this.mediaSegmentEncrypted = mediaSegmentEncrypted;
this.discontinuitySequenceNumber = discontinuitySequenceNumber;
this.initDataSource = initDataSource;
// Workaround for https://github.com/typetools/checker-framework/issues/2215
if (initDataSpec != null) {
this.initDataSpec = initDataSpec;
this.initDataSource = Assertions.checkNotNull(initDataSource);
initDataLoadRequired = true;
}
this.initSegmentEncrypted = initSegmentEncrypted;
this.playlistUrl = playlistUrl;
this.isMasterTimestampSource = isMasterTimestampSource;
@ -257,11 +274,13 @@ import java.util.concurrent.atomic.AtomicInteger;
this.extractorFactory = extractorFactory;
this.muxedCaptionFormats = muxedCaptionFormats;
this.drmInitData = drmInitData;
// Workaround for https://github.com/typetools/checker-framework/issues/2215
if (previousExtractor != null) {
this.previousExtractor = previousExtractor;
}
this.id3Decoder = id3Decoder;
this.scratchId3Data = scratchId3Data;
this.shouldSpliceIn = shouldSpliceIn;
initDataLoadRequired = initDataSpec != null;
uid = uidSource.getAndIncrement();
}
@ -289,6 +308,8 @@ import java.util.concurrent.atomic.AtomicInteger;
@Override
public void load() throws IOException, InterruptedException {
// output == null means init() hasn't been called.
Assertions.checkNotNull(output);
if (extractor == null && previousExtractor != null) {
extractor = previousExtractor;
isExtractorReusable = true;
@ -306,15 +327,20 @@ import java.util.concurrent.atomic.AtomicInteger;
// Internal methods.
@RequiresNonNull("output")
private void maybeLoadInitData() throws IOException, InterruptedException {
if (!initDataLoadRequired) {
return;
}
// initDataLoadRequired => initDataSource != null && initDataSpec != null
Assertions.checkNotNull(initDataSource);
Assertions.checkNotNull(initDataSpec);
feedDataToExtractor(initDataSource, initDataSpec, initSegmentEncrypted);
nextLoadPosition = 0;
initDataLoadRequired = false;
}
@RequiresNonNull("output")
private void loadMedia() throws IOException, InterruptedException {
if (!isMasterTimestampSource) {
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
* bytes is written to {@code nextLoadPosition}.
*/
@RequiresNonNull("output")
private void feedDataToExtractor(
DataSource dataSource, DataSpec dataSpec, boolean dataIsEncrypted)
throws IOException, InterruptedException {
@ -354,7 +381,7 @@ import java.util.concurrent.atomic.AtomicInteger;
try {
int result = Extractor.RESULT_CONTINUE;
while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
result = extractor.read(input, /* seekPosition= */ null);
result = extractor.read(input, DUMMY_POSITION_HOLDER);
}
} finally {
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)
throws IOException, InterruptedException {
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
* 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,
byte[] encryptionIv) {
private static DataSource buildDataSource(
DataSource dataSource,
@Nullable byte[] fullSegmentEncryptionKey,
@Nullable byte[] encryptionIv) {
if (fullSegmentEncryptionKey != null) {
Assertions.checkNotNull(encryptionIv);
return new Aes128DataSource(dataSource, fullSegmentEncryptionKey, encryptionIv);
}
return dataSource;