From f7470c512604cff97e75fbf7b86a4b4249f24898 Mon Sep 17 00:00:00 2001 From: ibaker Date: Mon, 20 Jan 2020 14:52:26 +0000 Subject: [PATCH] Remove CEA package from null-checking blacklist PiperOrigin-RevId: 290610312 --- .../exoplayer2/text/cea/Cea608Decoder.java | 27 +++++++++++------- .../exoplayer2/text/cea/Cea708Decoder.java | 23 +++++++++------ .../exoplayer2/text/cea/CeaDecoder.java | 28 +++++++++++-------- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java index 5a14063aa1..cce1bf6270 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea608Decoder.java @@ -24,17 +24,21 @@ import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Subtitle; import com.google.android.exoplayer2.text.SubtitleDecoder; import com.google.android.exoplayer2.text.SubtitleInputBuffer; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.ParsableByteArray; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.checkerframework.checker.nullness.compatqual.NullableType; /** * A {@link SubtitleDecoder} for CEA-608 (also known as "line 21 captions" and "EIA-608"). @@ -236,8 +240,8 @@ public final class Cea608Decoder extends CeaDecoder { private final ArrayList cueBuilders; private CueBuilder currentCueBuilder; - private List cues; - private List lastCues; + @Nullable private List cues; + @Nullable private List lastCues; private int captionMode; private int captionRowCount; @@ -321,13 +325,14 @@ public final class Cea608Decoder extends CeaDecoder { @Override protected Subtitle createSubtitle() { lastCues = cues; - return new CeaSubtitle(cues); + return new CeaSubtitle(Assertions.checkNotNull(cues)); } @SuppressWarnings("ByteBufferBackingArray") @Override protected void decode(SubtitleInputBuffer inputBuffer) { - ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit()); + ByteBuffer subtitleData = Assertions.checkNotNull(inputBuffer.data); + ccData.reset(subtitleData.array(), subtitleData.limit()); boolean captionDataProcessed = false; while (ccData.bytesLeft() >= packetLength) { byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER @@ -572,9 +577,9 @@ public final class Cea608Decoder extends CeaDecoder { // preference, then middle alignment, then end alignment. @Cue.AnchorType int positionAnchor = Cue.ANCHOR_TYPE_END; int cueBuilderCount = cueBuilders.size(); - List cueBuilderCues = new ArrayList<>(cueBuilderCount); + List<@NullableType Cue> cueBuilderCues = new ArrayList<>(cueBuilderCount); for (int i = 0; i < cueBuilderCount; i++) { - Cue cue = cueBuilders.get(i).build(/* forcedPositionAnchor= */ Cue.TYPE_UNSET); + @Nullable Cue cue = cueBuilders.get(i).build(/* forcedPositionAnchor= */ Cue.TYPE_UNSET); cueBuilderCues.add(cue); if (cue != null) { positionAnchor = Math.min(positionAnchor, cue.positionAnchor); @@ -584,10 +589,11 @@ public final class Cea608Decoder extends CeaDecoder { // Skip null cues and rebuild any that don't have the preferred alignment. List displayCues = new ArrayList<>(cueBuilderCount); for (int i = 0; i < cueBuilderCount; i++) { - Cue cue = cueBuilderCues.get(i); + @Nullable Cue cue = cueBuilderCues.get(i); if (cue != null) { if (cue.positionAnchor != positionAnchor) { - cue = cueBuilders.get(i).build(positionAnchor); + // The last time we built this cue it was non-null, it will be non-null this time too. + cue = Assertions.checkNotNull(cueBuilders.get(i).build(positionAnchor)); } displayCues.add(cue); } @@ -745,7 +751,7 @@ public final class Cea608Decoder extends CeaDecoder { return (cc1 & 0xF7) == 0x14; } - private static class CueBuilder { + private static final class CueBuilder { // 608 captions define a 15 row by 32 column screen grid. These constants convert from 608 // positions to normalized screen position. @@ -767,7 +773,7 @@ public final class Cea608Decoder extends CeaDecoder { rolledUpCaptions = new ArrayList<>(); captionStringBuilder = new StringBuilder(); reset(captionMode); - setCaptionRowCount(captionRowCount); + this.captionRowCount = captionRowCount; } public void reset(int captionMode) { @@ -829,6 +835,7 @@ public final class Cea608Decoder extends CeaDecoder { } } + @Nullable public Cue build(@Cue.AnchorType int forcedPositionAnchor) { SpannableStringBuilder cueString = new SpannableStringBuilder(); // Add any rolled up captions, separated by new lines. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Decoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Decoder.java index 4eaf65c721..8262a6dabc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Decoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/Cea708Decoder.java @@ -37,9 +37,11 @@ import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.ParsableBitArray; import com.google.android.exoplayer2.util.ParsableByteArray; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.checkerframework.checker.nullness.qual.RequiresNonNull; /** * A {@link SubtitleDecoder} for CEA-708 (also known as "EIA-708"). @@ -147,10 +149,10 @@ public final class Cea708Decoder extends CeaDecoder { private final CueInfoBuilder[] cueInfoBuilders; private CueInfoBuilder currentCueInfoBuilder; - private List cues; - private List lastCues; + @Nullable private List cues; + @Nullable private List lastCues; - private DtvCcPacket currentDtvCcPacket; + @Nullable private DtvCcPacket currentDtvCcPacket; private int currentWindow; // TODO: Retrieve isWideAspectRatio from initializationData and use it. @@ -165,7 +167,6 @@ public final class Cea708Decoder extends CeaDecoder { } currentCueInfoBuilder = cueInfoBuilders[0]; - resetCueBuilders(); } @Override @@ -192,15 +193,16 @@ public final class Cea708Decoder extends CeaDecoder { @Override protected Subtitle createSubtitle() { lastCues = cues; - return new CeaSubtitle(cues); + return new CeaSubtitle(Assertions.checkNotNull(cues)); } @Override protected void decode(SubtitleInputBuffer inputBuffer) { // Subtitle input buffers are non-direct and the position is zero, so calling array() is safe. + ByteBuffer subtitleData = Assertions.checkNotNull(inputBuffer.data); @SuppressWarnings("ByteBufferBackingArray") - byte[] inputBufferData = inputBuffer.data.array(); - ccData.reset(inputBufferData, inputBuffer.data.limit()); + byte[] inputBufferData = subtitleData.array(); + ccData.reset(inputBufferData, subtitleData.limit()); while (ccData.bytesLeft() >= 3) { int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07); @@ -259,6 +261,7 @@ public final class Cea708Decoder extends CeaDecoder { currentDtvCcPacket = null; } + @RequiresNonNull("currentDtvCcPacket") private void processCurrentPacket() { if (currentDtvCcPacket.currentIndex != (currentDtvCcPacket.packetSize * 2 - 1)) { Log.w(TAG, "DtvCcPacket ended prematurely; size is " + (currentDtvCcPacket.packetSize * 2 - 1) @@ -761,7 +764,10 @@ public final class Cea708Decoder extends CeaDecoder { List displayCueInfos = new ArrayList<>(); for (int i = 0; i < NUM_WINDOWS; i++) { if (!cueInfoBuilders[i].isEmpty() && cueInfoBuilders[i].isVisible()) { - displayCueInfos.add(cueInfoBuilders[i].build()); + @Nullable Cea708CueInfo cueInfo = cueInfoBuilders[i].build(); + if (cueInfo != null) { + displayCueInfos.add(cueInfo); + } } } Collections.sort( @@ -1157,6 +1163,7 @@ public final class Cea708Decoder extends CeaDecoder { return new SpannableString(spannableStringBuilder); } + @Nullable public Cea708CueInfo build() { if (isEmpty()) { // The cue is empty. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java index ce9da9f5d5..e596f7481d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/cea/CeaDecoder.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.text.cea; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.text.Subtitle; @@ -24,6 +25,7 @@ import com.google.android.exoplayer2.text.SubtitleDecoderException; import com.google.android.exoplayer2.text.SubtitleInputBuffer; import com.google.android.exoplayer2.text.SubtitleOutputBuffer; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import java.util.ArrayDeque; import java.util.PriorityQueue; @@ -39,7 +41,7 @@ import java.util.PriorityQueue; private final ArrayDeque availableOutputBuffers; private final PriorityQueue queuedInputBuffers; - private CeaInputBuffer dequeuedInputBuffer; + @Nullable private CeaInputBuffer dequeuedInputBuffer; private long playbackPositionUs; private long queuedInputBufferCount; @@ -64,6 +66,7 @@ import java.util.PriorityQueue; } @Override + @Nullable public SubtitleInputBuffer dequeueInputBuffer() throws SubtitleDecoderException { Assertions.checkState(dequeuedInputBuffer == null); if (availableInputBuffers.isEmpty()) { @@ -76,18 +79,20 @@ import java.util.PriorityQueue; @Override public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException { Assertions.checkArgument(inputBuffer == dequeuedInputBuffer); - if (inputBuffer.isDecodeOnly()) { + CeaInputBuffer ceaInputBuffer = (CeaInputBuffer) inputBuffer; + if (ceaInputBuffer.isDecodeOnly()) { // We can drop this buffer early (i.e. before it would be decoded) as the CEA formats allow // for decoding to begin mid-stream. - releaseInputBuffer(dequeuedInputBuffer); + releaseInputBuffer(ceaInputBuffer); } else { - dequeuedInputBuffer.queuedInputBufferCount = queuedInputBufferCount++; - queuedInputBuffers.add(dequeuedInputBuffer); + ceaInputBuffer.queuedInputBufferCount = queuedInputBufferCount++; + queuedInputBuffers.add(ceaInputBuffer); } dequeuedInputBuffer = null; } @Override + @Nullable public SubtitleOutputBuffer dequeueOutputBuffer() throws SubtitleDecoderException { if (availableOutputBuffers.isEmpty()) { return null; @@ -96,13 +101,14 @@ import java.util.PriorityQueue; // to the current playback position; processing input buffers for future content should // be deferred until they would be applicable while (!queuedInputBuffers.isEmpty() - && queuedInputBuffers.peek().timeUs <= playbackPositionUs) { - CeaInputBuffer inputBuffer = queuedInputBuffers.poll(); + && Util.castNonNull(queuedInputBuffers.peek()).timeUs <= playbackPositionUs) { + CeaInputBuffer inputBuffer = Util.castNonNull(queuedInputBuffers.poll()); // If the input buffer indicates we've reached the end of the stream, we can // return immediately with an output buffer propagating that if (inputBuffer.isEndOfStream()) { - SubtitleOutputBuffer outputBuffer = availableOutputBuffers.pollFirst(); + // availableOutputBuffers.isEmpty() is checked at the top of the method, so this is safe. + SubtitleOutputBuffer outputBuffer = Util.castNonNull(availableOutputBuffers.pollFirst()); outputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM); releaseInputBuffer(inputBuffer); return outputBuffer; @@ -116,7 +122,8 @@ import java.util.PriorityQueue; // isn't accidentally prepended to the next subtitle Subtitle subtitle = createSubtitle(); if (!inputBuffer.isDecodeOnly()) { - SubtitleOutputBuffer outputBuffer = availableOutputBuffers.pollFirst(); + // availableOutputBuffers.isEmpty() is checked at the top of the method, so this is safe. + SubtitleOutputBuffer outputBuffer = Util.castNonNull(availableOutputBuffers.pollFirst()); outputBuffer.setContent(inputBuffer.timeUs, subtitle, Format.OFFSET_SAMPLE_RELATIVE); releaseInputBuffer(inputBuffer); return outputBuffer; @@ -125,7 +132,6 @@ import java.util.PriorityQueue; releaseInputBuffer(inputBuffer); } - return null; } @@ -144,7 +150,7 @@ import java.util.PriorityQueue; queuedInputBufferCount = 0; playbackPositionUs = 0; while (!queuedInputBuffers.isEmpty()) { - releaseInputBuffer(queuedInputBuffers.poll()); + releaseInputBuffer(Util.castNonNull(queuedInputBuffers.poll())); } if (dequeuedInputBuffer != null) { releaseInputBuffer(dequeuedInputBuffer);