Add NonNull annotations to text packages

PiperOrigin-RevId: 283951181
This commit is contained in:
olly 2019-12-05 13:02:01 +00:00 committed by Oliver Woodman
parent cab05cb71d
commit e10a78e6b7
17 changed files with 215 additions and 92 deletions

View File

@ -333,7 +333,7 @@ public class Cue {
*/ */
public Cue( public Cue(
CharSequence text, CharSequence text,
Alignment textAlignment, @Nullable Alignment textAlignment,
float line, float line,
@LineType int lineType, @LineType int lineType,
@AnchorType int lineAnchor, @AnchorType int lineAnchor,

View File

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.text;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.SimpleDecoder;
import com.google.android.exoplayer2.util.Assertions;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
@ -29,9 +30,8 @@ public abstract class SimpleSubtitleDecoder extends
private final String name; private final String name;
/** /** @param name The name of the decoder. */
* @param name The name of the decoder. @SuppressWarnings("initialization:method.invocation.invalid")
*/
protected SimpleSubtitleDecoder(String name) { protected SimpleSubtitleDecoder(String name) {
super(new SubtitleInputBuffer[2], new SubtitleOutputBuffer[2]); super(new SubtitleInputBuffer[2], new SubtitleOutputBuffer[2]);
this.name = name; this.name = name;
@ -74,7 +74,7 @@ public abstract class SimpleSubtitleDecoder extends
protected final SubtitleDecoderException decode( protected final SubtitleDecoderException decode(
SubtitleInputBuffer inputBuffer, SubtitleOutputBuffer outputBuffer, boolean reset) { SubtitleInputBuffer inputBuffer, SubtitleOutputBuffer outputBuffer, boolean reset) {
try { try {
ByteBuffer inputData = inputBuffer.data; ByteBuffer inputData = Assertions.checkNotNull(inputBuffer.data);
Subtitle subtitle = decode(inputData.array(), inputData.limit(), reset); Subtitle subtitle = decode(inputData.array(), inputData.limit(), reset);
outputBuffer.setContent(inputBuffer.timeUs, subtitle, inputBuffer.subsampleOffsetUs); outputBuffer.setContent(inputBuffer.timeUs, subtitle, inputBuffer.subsampleOffsetUs);
// Clear BUFFER_FLAG_DECODE_ONLY (see [Internal: b/27893809]). // Clear BUFFER_FLAG_DECODE_ONLY (see [Internal: b/27893809]).

View File

@ -80,11 +80,11 @@ public final class TextRenderer extends BaseRenderer implements Callback {
private boolean inputStreamEnded; private boolean inputStreamEnded;
private boolean outputStreamEnded; private boolean outputStreamEnded;
@ReplacementState private int decoderReplacementState; @ReplacementState private int decoderReplacementState;
private Format streamFormat; @Nullable private Format streamFormat;
private SubtitleDecoder decoder; @Nullable private SubtitleDecoder decoder;
private SubtitleInputBuffer nextInputBuffer; @Nullable private SubtitleInputBuffer nextInputBuffer;
private SubtitleOutputBuffer subtitle; @Nullable private SubtitleOutputBuffer subtitle;
private SubtitleOutputBuffer nextSubtitle; @Nullable private SubtitleOutputBuffer nextSubtitle;
private int nextSubtitleEventIndex; private int nextSubtitleEventIndex;
/** /**
@ -132,7 +132,7 @@ public final class TextRenderer extends BaseRenderer implements Callback {
} }
@Override @Override
protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException { protected void onStreamChanged(Format[] formats, long offsetUs) {
streamFormat = formats[0]; streamFormat = formats[0];
if (decoder != null) { if (decoder != null) {
decoderReplacementState = REPLACEMENT_STATE_SIGNAL_END_OF_STREAM; decoderReplacementState = REPLACEMENT_STATE_SIGNAL_END_OF_STREAM;

View File

@ -24,11 +24,6 @@ import com.google.android.exoplayer2.text.Cue;
*/ */
/* package */ final class Cea708Cue extends Cue implements Comparable<Cea708Cue> { /* package */ final class Cea708Cue extends Cue implements Comparable<Cea708Cue> {
/**
* An unset priority.
*/
public static final int PRIORITY_UNSET = -1;
/** /**
* The priority of the cue box. * The priority of the cue box.
*/ */
@ -64,5 +59,4 @@ import com.google.android.exoplayer2.text.Cue;
} }
return 0; return 0;
} }
} }

View File

@ -25,6 +25,7 @@ import android.text.style.BackgroundColorSpan;
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.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
@ -152,7 +153,8 @@ public final class Cea708Decoder extends CeaDecoder {
private DtvCcPacket currentDtvCcPacket; private DtvCcPacket currentDtvCcPacket;
private int currentWindow; private int currentWindow;
public Cea708Decoder(int accessibilityChannel, List<byte[]> initializationData) { // TODO: Retrieve isWideAspectRatio from initializationData and use it.
public Cea708Decoder(int accessibilityChannel, @Nullable List<byte[]> initializationData) {
ccData = new ParsableByteArray(); ccData = new ParsableByteArray();
serviceBlockPacket = new ParsableBitArray(); serviceBlockPacket = new ParsableBitArray();
selectedServiceNumber = accessibilityChannel == Format.NO_VALUE ? 1 : accessibilityChannel; selectedServiceNumber = accessibilityChannel == Format.NO_VALUE ? 1 : accessibilityChannel;

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.text.cea;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -22,6 +22,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode; import android.graphics.PorterDuffXfermode;
import android.util.SparseArray; import android.util.SparseArray;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
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;
@ -29,6 +30,7 @@ import com.google.android.exoplayer2.util.Util;
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.MonotonicNonNull;
/** /**
* Parses {@link Cue}s from a DVB subtitle bitstream. * Parses {@link Cue}s from a DVB subtitle bitstream.
@ -85,7 +87,7 @@ import java.util.List;
private final ClutDefinition defaultClutDefinition; private final ClutDefinition defaultClutDefinition;
private final SubtitleService subtitleService; private final SubtitleService subtitleService;
private Bitmap bitmap; @MonotonicNonNull private Bitmap bitmap;
/** /**
* Construct an instance for the given subtitle and ancillary page ids. * Construct an instance for the given subtitle and ancillary page ids.
@ -131,7 +133,8 @@ import java.util.List;
parseSubtitlingSegment(dataBitArray, subtitleService); parseSubtitlingSegment(dataBitArray, subtitleService);
} }
if (subtitleService.pageComposition == null) { @Nullable PageComposition pageComposition = subtitleService.pageComposition;
if (pageComposition == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -147,7 +150,7 @@ import java.util.List;
// Build the cues. // Build the cues.
List<Cue> cues = new ArrayList<>(); List<Cue> cues = new ArrayList<>();
SparseArray<PageRegion> pageRegions = subtitleService.pageComposition.regions; SparseArray<PageRegion> pageRegions = pageComposition.regions;
for (int i = 0; i < pageRegions.size(); i++) { for (int i = 0; i < pageRegions.size(); i++) {
// Save clean clipping state. // Save clean clipping state.
canvas.save(); canvas.save();
@ -182,7 +185,7 @@ import java.util.List;
objectData = subtitleService.ancillaryObjects.get(objectId); objectData = subtitleService.ancillaryObjects.get(objectId);
} }
if (objectData != null) { if (objectData != null) {
Paint paint = objectData.nonModifyingColorFlag ? null : defaultPaint; @Nullable Paint paint = objectData.nonModifyingColorFlag ? null : defaultPaint;
paintPixelDataSubBlocks(objectData, clutDefinition, regionComposition.depth, paintPixelDataSubBlocks(objectData, clutDefinition, regionComposition.depth,
baseHorizontalAddress + regionObject.horizontalPosition, baseHorizontalAddress + regionObject.horizontalPosition,
baseVerticalAddress + regionObject.verticalPosition, paint, canvas); baseVerticalAddress + regionObject.verticalPosition, paint, canvas);
@ -248,7 +251,7 @@ import java.util.List;
break; break;
case SEGMENT_TYPE_PAGE_COMPOSITION: case SEGMENT_TYPE_PAGE_COMPOSITION:
if (pageId == service.subtitlePageId) { if (pageId == service.subtitlePageId) {
PageComposition current = service.pageComposition; @Nullable PageComposition current = service.pageComposition;
PageComposition pageComposition = parsePageComposition(data, dataFieldLength); PageComposition pageComposition = parsePageComposition(data, dataFieldLength);
if (pageComposition.state != PAGE_STATE_NORMAL) { if (pageComposition.state != PAGE_STATE_NORMAL) {
service.pageComposition = pageComposition; service.pageComposition = pageComposition;
@ -261,11 +264,15 @@ import java.util.List;
} }
break; break;
case SEGMENT_TYPE_REGION_COMPOSITION: case SEGMENT_TYPE_REGION_COMPOSITION:
PageComposition pageComposition = service.pageComposition; @Nullable PageComposition pageComposition = service.pageComposition;
if (pageId == service.subtitlePageId && pageComposition != null) { if (pageId == service.subtitlePageId && pageComposition != null) {
RegionComposition regionComposition = parseRegionComposition(data, dataFieldLength); RegionComposition regionComposition = parseRegionComposition(data, dataFieldLength);
if (pageComposition.state == PAGE_STATE_NORMAL) { if (pageComposition.state == PAGE_STATE_NORMAL) {
regionComposition.mergeFrom(service.regions.get(regionComposition.id)); @Nullable
RegionComposition existingRegionComposition = service.regions.get(regionComposition.id);
if (existingRegionComposition != null) {
regionComposition.mergeFrom(existingRegionComposition);
}
} }
service.regions.put(regionComposition.id, regionComposition); service.regions.put(regionComposition.id, regionComposition);
} }
@ -470,8 +477,8 @@ import java.util.List;
boolean nonModifyingColorFlag = data.readBit(); boolean nonModifyingColorFlag = data.readBit();
data.skipBits(1); // Skip reserved. data.skipBits(1); // Skip reserved.
byte[] topFieldData = null; @Nullable byte[] topFieldData = null;
byte[] bottomFieldData = null; @Nullable byte[] bottomFieldData = null;
if (objectCodingMethod == OBJECT_CODING_STRING) { if (objectCodingMethod == OBJECT_CODING_STRING) {
int numberOfCodes = data.readBits(8); int numberOfCodes = data.readBits(8);
@ -577,11 +584,15 @@ import java.util.List;
// Static drawing. // Static drawing.
/** /** Draws a pixel data sub-block, as defined by ETSI EN 300 743 7.2.5.1, into a canvas. */
* Draws a pixel data sub-block, as defined by ETSI EN 300 743 7.2.5.1, into a canvas. private static void paintPixelDataSubBlocks(
*/ ObjectData objectData,
private static void paintPixelDataSubBlocks(ObjectData objectData, ClutDefinition clutDefinition, ClutDefinition clutDefinition,
int regionDepth, int horizontalAddress, int verticalAddress, Paint paint, Canvas canvas) { int regionDepth,
int horizontalAddress,
int verticalAddress,
@Nullable Paint paint,
Canvas canvas) {
int[] clutEntries; int[] clutEntries;
if (regionDepth == REGION_DEPTH_8_BIT) { if (regionDepth == REGION_DEPTH_8_BIT) {
clutEntries = clutDefinition.clutEntries8Bit; clutEntries = clutDefinition.clutEntries8Bit;
@ -596,23 +607,27 @@ import java.util.List;
verticalAddress + 1, paint, canvas); verticalAddress + 1, paint, canvas);
} }
/** /** Draws a pixel data sub-block, as defined by ETSI EN 300 743 7.2.5.1, into a canvas. */
* Draws a pixel data sub-block, as defined by ETSI EN 300 743 7.2.5.1, into a canvas. private static void paintPixelDataSubBlock(
*/ byte[] pixelData,
private static void paintPixelDataSubBlock(byte[] pixelData, int[] clutEntries, int regionDepth, int[] clutEntries,
int horizontalAddress, int verticalAddress, Paint paint, Canvas canvas) { int regionDepth,
int horizontalAddress,
int verticalAddress,
@Nullable Paint paint,
Canvas canvas) {
ParsableBitArray data = new ParsableBitArray(pixelData); ParsableBitArray data = new ParsableBitArray(pixelData);
int column = horizontalAddress; int column = horizontalAddress;
int line = verticalAddress; int line = verticalAddress;
byte[] clutMapTable2To4 = null; @Nullable byte[] clutMapTable2To4 = null;
byte[] clutMapTable2To8 = null; @Nullable byte[] clutMapTable2To8 = null;
byte[] clutMapTable4To8 = null; @Nullable byte[] clutMapTable4To8 = null;
while (data.bitsLeft() != 0) { while (data.bitsLeft() != 0) {
int dataType = data.readBits(8); int dataType = data.readBits(8);
switch (dataType) { switch (dataType) {
case DATA_TYPE_2BP_CODE_STRING: case DATA_TYPE_2BP_CODE_STRING:
byte[] clutMapTable2ToX; @Nullable byte[] clutMapTable2ToX;
if (regionDepth == REGION_DEPTH_8_BIT) { if (regionDepth == REGION_DEPTH_8_BIT) {
clutMapTable2ToX = clutMapTable2To8 == null ? defaultMap2To8 : clutMapTable2To8; clutMapTable2ToX = clutMapTable2To8 == null ? defaultMap2To8 : clutMapTable2To8;
} else if (regionDepth == REGION_DEPTH_4_BIT) { } else if (regionDepth == REGION_DEPTH_4_BIT) {
@ -625,7 +640,7 @@ import java.util.List;
data.byteAlign(); data.byteAlign();
break; break;
case DATA_TYPE_4BP_CODE_STRING: case DATA_TYPE_4BP_CODE_STRING:
byte[] clutMapTable4ToX; @Nullable byte[] clutMapTable4ToX;
if (regionDepth == REGION_DEPTH_8_BIT) { if (regionDepth == REGION_DEPTH_8_BIT) {
clutMapTable4ToX = clutMapTable4To8 == null ? defaultMap4To8 : clutMapTable4To8; clutMapTable4ToX = clutMapTable4To8 == null ? defaultMap4To8 : clutMapTable4To8;
} else { } else {
@ -636,7 +651,9 @@ import java.util.List;
data.byteAlign(); data.byteAlign();
break; break;
case DATA_TYPE_8BP_CODE_STRING: case DATA_TYPE_8BP_CODE_STRING:
column = paint8BitPixelCodeString(data, clutEntries, null, column, line, paint, canvas); column =
paint8BitPixelCodeString(
data, clutEntries, /* clutMapTable= */ null, column, line, paint, canvas);
break; break;
case DATA_TYPE_24_TABLE_DATA: case DATA_TYPE_24_TABLE_DATA:
clutMapTable2To4 = buildClutMapTable(4, 4, data); clutMapTable2To4 = buildClutMapTable(4, 4, data);
@ -658,11 +675,15 @@ import java.util.List;
} }
} }
/** /** Paint a 2-bit/pixel code string, as defined by ETSI EN 300 743 7.2.5.2, to a canvas. */
* Paint a 2-bit/pixel code string, as defined by ETSI EN 300 743 7.2.5.2, to a canvas. private static int paint2BitPixelCodeString(
*/ ParsableBitArray data,
private static int paint2BitPixelCodeString(ParsableBitArray data, int[] clutEntries, int[] clutEntries,
byte[] clutMapTable, int column, int line, Paint paint, Canvas canvas) { @Nullable byte[] clutMapTable,
int column,
int line,
@Nullable Paint paint,
Canvas canvas) {
boolean endOfPixelCodeString = false; boolean endOfPixelCodeString = false;
do { do {
int runLength = 0; int runLength = 0;
@ -706,11 +727,15 @@ import java.util.List;
return column; return column;
} }
/** /** Paint a 4-bit/pixel code string, as defined by ETSI EN 300 743 7.2.5.2, to a canvas. */
* Paint a 4-bit/pixel code string, as defined by ETSI EN 300 743 7.2.5.2, to a canvas. private static int paint4BitPixelCodeString(
*/ ParsableBitArray data,
private static int paint4BitPixelCodeString(ParsableBitArray data, int[] clutEntries, int[] clutEntries,
byte[] clutMapTable, int column, int line, Paint paint, Canvas canvas) { @Nullable byte[] clutMapTable,
int column,
int line,
@Nullable Paint paint,
Canvas canvas) {
boolean endOfPixelCodeString = false; boolean endOfPixelCodeString = false;
do { do {
int runLength = 0; int runLength = 0;
@ -760,11 +785,15 @@ import java.util.List;
return column; return column;
} }
/** /** Paint an 8-bit/pixel code string, as defined by ETSI EN 300 743 7.2.5.2, to a canvas. */
* Paint an 8-bit/pixel code string, as defined by ETSI EN 300 743 7.2.5.2, to a canvas. private static int paint8BitPixelCodeString(
*/ ParsableBitArray data,
private static int paint8BitPixelCodeString(ParsableBitArray data, int[] clutEntries, int[] clutEntries,
byte[] clutMapTable, int column, int line, Paint paint, Canvas canvas) { @Nullable byte[] clutMapTable,
int column,
int line,
@Nullable Paint paint,
Canvas canvas) {
boolean endOfPixelCodeString = false; boolean endOfPixelCodeString = false;
do { do {
int runLength = 0; int runLength = 0;
@ -816,18 +845,23 @@ import java.util.List;
public final int subtitlePageId; public final int subtitlePageId;
public final int ancillaryPageId; public final int ancillaryPageId;
public final SparseArray<RegionComposition> regions = new SparseArray<>(); public final SparseArray<RegionComposition> regions;
public final SparseArray<ClutDefinition> cluts = new SparseArray<>(); public final SparseArray<ClutDefinition> cluts;
public final SparseArray<ObjectData> objects = new SparseArray<>(); public final SparseArray<ObjectData> objects;
public final SparseArray<ClutDefinition> ancillaryCluts = new SparseArray<>(); public final SparseArray<ClutDefinition> ancillaryCluts;
public final SparseArray<ObjectData> ancillaryObjects = new SparseArray<>(); public final SparseArray<ObjectData> ancillaryObjects;
public DisplayDefinition displayDefinition; @Nullable public DisplayDefinition displayDefinition;
public PageComposition pageComposition; @Nullable public PageComposition pageComposition;
public SubtitleService(int subtitlePageId, int ancillaryPageId) { public SubtitleService(int subtitlePageId, int ancillaryPageId) {
this.subtitlePageId = subtitlePageId; this.subtitlePageId = subtitlePageId;
this.ancillaryPageId = ancillaryPageId; this.ancillaryPageId = ancillaryPageId;
regions = new SparseArray<>();
cluts = new SparseArray<>();
objects = new SparseArray<>();
ancillaryCluts = new SparseArray<>();
ancillaryObjects = new SparseArray<>();
} }
public void reset() { public void reset() {
@ -944,9 +978,6 @@ import java.util.List;
} }
public void mergeFrom(RegionComposition otherRegionComposition) { public void mergeFrom(RegionComposition otherRegionComposition) {
if (otherRegionComposition == null) {
return;
}
SparseArray<RegionObject> otherRegionObjects = otherRegionComposition.regionObjects; SparseArray<RegionObject> otherRegionObjects = otherRegionComposition.regionObjects;
for (int i = 0; i < otherRegionObjects.size(); i++) { for (int i = 0; i < otherRegionObjects.size(); i++) {
regionObjects.put(otherRegionObjects.keyAt(i), otherRegionObjects.valueAt(i)); regionObjects.put(otherRegionObjects.keyAt(i), otherRegionObjects.valueAt(i));

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.text.dvb;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.text;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.text.ssa; package com.google.android.exoplayer2.text.ssa;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.text.Layout; import android.text.Layout;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
@ -115,7 +117,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
* @param data A {@link ParsableByteArray} from which the header should be read. * @param data A {@link ParsableByteArray} from which the header should be read.
*/ */
private void parseHeader(ParsableByteArray data) { private void parseHeader(ParsableByteArray data) {
String currentLine; @Nullable String currentLine;
while ((currentLine = data.readLine()) != null) { while ((currentLine = data.readLine()) != null) {
if ("[Script Info]".equalsIgnoreCase(currentLine)) { if ("[Script Info]".equalsIgnoreCase(currentLine)) {
parseScriptInfo(data); parseScriptInfo(data);
@ -140,7 +142,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
* set to the beginning of of the first line after {@code [Script Info]}. * set to the beginning of of the first line after {@code [Script Info]}.
*/ */
private void parseScriptInfo(ParsableByteArray data) { private void parseScriptInfo(ParsableByteArray data) {
String currentLine; @Nullable String currentLine;
while ((currentLine = data.readLine()) != null while ((currentLine = data.readLine()) != null
&& (data.bytesLeft() == 0 || data.peekUnsignedByte() != '[')) { && (data.bytesLeft() == 0 || data.peekUnsignedByte() != '[')) {
String[] infoNameAndValue = currentLine.split(":"); String[] infoNameAndValue = currentLine.split(":");
@ -176,9 +178,9 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
* at the beginning of of the first line after {@code [V4+ Styles]}. * at the beginning of of the first line after {@code [V4+ Styles]}.
*/ */
private static Map<String, SsaStyle> parseStyles(ParsableByteArray data) { private static Map<String, SsaStyle> parseStyles(ParsableByteArray data) {
SsaStyle.Format formatInfo = null;
Map<String, SsaStyle> styles = new LinkedHashMap<>(); Map<String, SsaStyle> styles = new LinkedHashMap<>();
String currentLine; @Nullable SsaStyle.Format formatInfo = null;
@Nullable String currentLine;
while ((currentLine = data.readLine()) != null while ((currentLine = data.readLine()) != null
&& (data.bytesLeft() == 0 || data.peekUnsignedByte() != '[')) { && (data.bytesLeft() == 0 || data.peekUnsignedByte() != '[')) {
if (currentLine.startsWith(FORMAT_LINE_PREFIX)) { if (currentLine.startsWith(FORMAT_LINE_PREFIX)) {
@ -188,7 +190,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
Log.w(TAG, "Skipping 'Style:' line before 'Format:' line: " + currentLine); Log.w(TAG, "Skipping 'Style:' line before 'Format:' line: " + currentLine);
continue; continue;
} }
SsaStyle style = SsaStyle.fromStyleLine(currentLine, formatInfo); @Nullable SsaStyle style = SsaStyle.fromStyleLine(currentLine, formatInfo);
if (style != null) { if (style != null) {
styles.put(style.name, style); styles.put(style.name, style);
} }
@ -205,8 +207,9 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
* @param cueTimesUs A sorted list to which parsed cue timestamps will be added. * @param cueTimesUs A sorted list to which parsed cue timestamps will be added.
*/ */
private void parseEventBody(ParsableByteArray data, List<List<Cue>> cues, List<Long> cueTimesUs) { private void parseEventBody(ParsableByteArray data, List<List<Cue>> cues, List<Long> cueTimesUs) {
@Nullable
SsaDialogueFormat format = haveInitializationData ? dialogueFormatFromInitializationData : null; SsaDialogueFormat format = haveInitializationData ? dialogueFormatFromInitializationData : null;
String currentLine; @Nullable String currentLine;
while ((currentLine = data.readLine()) != null) { while ((currentLine = data.readLine()) != null) {
if (currentLine.startsWith(FORMAT_LINE_PREFIX)) { if (currentLine.startsWith(FORMAT_LINE_PREFIX)) {
format = SsaDialogueFormat.fromFormatLine(currentLine); format = SsaDialogueFormat.fromFormatLine(currentLine);
@ -250,6 +253,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
return; return;
} }
@Nullable
SsaStyle style = SsaStyle style =
styles != null && format.styleIndex != C.INDEX_UNSET styles != null && format.styleIndex != C.INDEX_UNSET
? styles.get(lineValues[format.styleIndex].trim()) ? styles.get(lineValues[format.styleIndex].trim())
@ -281,10 +285,11 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
if (!matcher.matches()) { if (!matcher.matches()) {
return C.TIME_UNSET; return C.TIME_UNSET;
} }
long timestampUs = Long.parseLong(matcher.group(1)) * 60 * 60 * C.MICROS_PER_SECOND; long timestampUs =
timestampUs += Long.parseLong(matcher.group(2)) * 60 * C.MICROS_PER_SECOND; Long.parseLong(castNonNull(matcher.group(1))) * 60 * 60 * C.MICROS_PER_SECOND;
timestampUs += Long.parseLong(matcher.group(3)) * C.MICROS_PER_SECOND; timestampUs += Long.parseLong(castNonNull(matcher.group(2))) * 60 * C.MICROS_PER_SECOND;
timestampUs += Long.parseLong(matcher.group(4)) * 10000; // 100ths of a second. timestampUs += Long.parseLong(castNonNull(matcher.group(3))) * C.MICROS_PER_SECOND;
timestampUs += Long.parseLong(castNonNull(matcher.group(4))) * 10000; // 100ths of a second.
return timestampUs; return timestampUs;
} }

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.text.ssa;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -73,8 +73,8 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
ArrayList<Cue> cues = new ArrayList<>(); ArrayList<Cue> cues = new ArrayList<>();
LongArray cueTimesUs = new LongArray(); LongArray cueTimesUs = new LongArray();
ParsableByteArray subripData = new ParsableByteArray(bytes, length); ParsableByteArray subripData = new ParsableByteArray(bytes, length);
String currentLine;
@Nullable String currentLine;
while ((currentLine = subripData.readLine()) != null) { while ((currentLine = subripData.readLine()) != null) {
if (currentLine.length() == 0) { if (currentLine.length() == 0) {
// Skip blank lines. // Skip blank lines.
@ -119,7 +119,7 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
Spanned text = Html.fromHtml(textBuilder.toString()); Spanned text = Html.fromHtml(textBuilder.toString());
String alignmentTag = null; @Nullable String alignmentTag = null;
for (int i = 0; i < tags.size(); i++) { for (int i = 0; i < tags.size(); i++) {
String tag = tags.get(i); String tag = tags.get(i);
if (tag.matches(SUBRIP_ALIGNMENT_TAG)) { if (tag.matches(SUBRIP_ALIGNMENT_TAG)) {

View File

@ -0,0 +1,19 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@NonNullApi
package com.google.android.exoplayer2.text.ttml;
import com.google.android.exoplayer2.util.NonNullApi;

View File

@ -220,7 +220,7 @@ public final class WebvttCssStyle {
return fontFamily; return fontFamily;
} }
public WebvttCssStyle setFontFamily(String fontFamily) { public WebvttCssStyle setFontFamily(@Nullable String fontFamily) {
this.fontFamily = Util.toLowerInvariant(fontFamily); this.fontFamily = Util.toLowerInvariant(fontFamily);
return this; return this;
} }
@ -264,7 +264,7 @@ public final class WebvttCssStyle {
return textAlign; return textAlign;
} }
public WebvttCssStyle setTextAlign(Layout.Alignment textAlign) { public WebvttCssStyle setTextAlign(@Nullable Layout.Alignment textAlign) {
this.textAlign = textAlign; this.textAlign = textAlign;
return this; return this;
} }

View File

@ -26,9 +26,7 @@ import com.google.android.exoplayer2.util.Log;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
/** /** A representation of a WebVTT cue. */
* A representation of a WebVTT cue.
*/
public final class WebvttCue extends Cue { public final class WebvttCue extends Cue {
private static final float DEFAULT_POSITION = 0.5f; private static final float DEFAULT_POSITION = 0.5f;

View File

@ -44,9 +44,7 @@ import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /** Parser for WebVTT cues. (https://w3c.github.io/webvtt/#cues) */
* Parser for WebVTT cues. (https://w3c.github.io/webvtt/#cues)
*/
public final class WebvttCueParser { public final class WebvttCueParser {
public static final Pattern CUE_HEADER_PATTERN = Pattern public static final Pattern CUE_HEADER_PATTERN = Pattern
@ -94,7 +92,7 @@ public final class WebvttCueParser {
*/ */
public boolean parseCue( public boolean parseCue(
ParsableByteArray webvttData, WebvttCue.Builder builder, List<WebvttCssStyle> styles) { ParsableByteArray webvttData, WebvttCue.Builder builder, List<WebvttCssStyle> styles) {
String firstLine = webvttData.readLine(); @Nullable String firstLine = webvttData.readLine();
if (firstLine == null) { if (firstLine == null) {
return false; return false;
} }
@ -104,7 +102,7 @@ public final class WebvttCueParser {
return parseCue(null, cueHeaderMatcher, webvttData, builder, textBuilder, styles); return parseCue(null, cueHeaderMatcher, webvttData, builder, textBuilder, styles);
} }
// The first line is not the timestamps, but could be the cue id. // The first line is not the timestamps, but could be the cue id.
String secondLine = webvttData.readLine(); @Nullable String secondLine = webvttData.readLine();
if (secondLine == null) { if (secondLine == null) {
return false; return false;
} }

View File

@ -52,7 +52,7 @@ public final class WebvttParserUtil {
* @param input The input from which the line should be read. * @param input The input from which the line should be read.
*/ */
public static boolean isWebvttHeaderLine(ParsableByteArray input) { public static boolean isWebvttHeaderLine(ParsableByteArray input) {
String line = input.readLine(); @Nullable String line = input.readLine();
return line != null && line.startsWith(WEBVTT_HEADER); return line != null && line.startsWith(WEBVTT_HEADER);
} }
@ -101,7 +101,7 @@ public final class WebvttParserUtil {
*/ */
@Nullable @Nullable
public static Matcher findNextCueHeader(ParsableByteArray input) { public static Matcher findNextCueHeader(ParsableByteArray input) {
String line; @Nullable String line;
while ((line = input.readLine()) != null) { while ((line = input.readLine()) != null) {
if (COMMENT.matcher(line).matches()) { if (COMMENT.matcher(line).matches()) {
// Skip until the end of the comment block. // Skip until the end of the comment block.