mirror of
https://github.com/samsonjs/media.git
synced 2026-03-28 09:55:48 +00:00
Remove CEA package from null-checking blacklist
PiperOrigin-RevId: 290610312
This commit is contained in:
parent
de3f04b721
commit
f7470c5126
3 changed files with 49 additions and 29 deletions
|
|
@ -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<CueBuilder> cueBuilders;
|
||||
|
||||
private CueBuilder currentCueBuilder;
|
||||
private List<Cue> cues;
|
||||
private List<Cue> lastCues;
|
||||
@Nullable private List<Cue> cues;
|
||||
@Nullable private List<Cue> 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<Cue> 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<Cue> 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.
|
||||
|
|
|
|||
|
|
@ -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<Cue> cues;
|
||||
private List<Cue> lastCues;
|
||||
@Nullable private List<Cue> cues;
|
||||
@Nullable private List<Cue> 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<Cea708CueInfo> 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.
|
||||
|
|
|
|||
|
|
@ -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<SubtitleOutputBuffer> availableOutputBuffers;
|
||||
private final PriorityQueue<CeaInputBuffer> 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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue