Commit f7470c51 by ibaker Committed by Ian Baker

Remove CEA package from null-checking blacklist

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