Standardise the use of ParsableByteArray
use among SubtitleParsers
PiperOrigin-RevId: 549609028
This commit is contained in:
parent
9128293236
commit
27bda610aa
@ -91,7 +91,6 @@ public final class DvbParser implements SubtitleParser {
|
||||
private final DisplayDefinition defaultDisplayDefinition;
|
||||
private final ClutDefinition defaultClutDefinition;
|
||||
private final SubtitleService subtitleService;
|
||||
private byte[] dataScratch = Util.EMPTY_BYTE_ARRAY;
|
||||
|
||||
private @MonotonicNonNull Bitmap bitmap;
|
||||
|
||||
@ -131,13 +130,8 @@ public final class DvbParser implements SubtitleParser {
|
||||
|
||||
@Override
|
||||
public ImmutableList<CuesWithTiming> parse(byte[] data, int offset, int length) {
|
||||
// Parse the input data.
|
||||
if (dataScratch.length < length) {
|
||||
dataScratch = new byte[length];
|
||||
}
|
||||
System.arraycopy(
|
||||
/* src= */ data, /* scrPos= */ offset, /* dest= */ dataScratch, /* destPos= */ 0, length);
|
||||
ParsableBitArray dataBitArray = new ParsableBitArray(dataScratch, length);
|
||||
ParsableBitArray dataBitArray = new ParsableBitArray(data, /* limit= */ offset + length);
|
||||
dataBitArray.setPosition(offset);
|
||||
while (dataBitArray.bitsLeft() >= 48 // sync_byte (8) + segment header (40)
|
||||
&& dataBitArray.readBits(8) == 0x0F) {
|
||||
parseSubtitlingSegment(dataBitArray, subtitleService);
|
||||
|
@ -45,7 +45,6 @@ public final class PgsParser implements SubtitleParser {
|
||||
private final ParsableByteArray buffer;
|
||||
private final ParsableByteArray inflatedBuffer;
|
||||
private final CueBuilder cueBuilder;
|
||||
private byte[] dataScratch = Util.EMPTY_BYTE_ARRAY;
|
||||
@Nullable private Inflater inflater;
|
||||
|
||||
public PgsParser() {
|
||||
@ -59,16 +58,8 @@ public final class PgsParser implements SubtitleParser {
|
||||
|
||||
@Override
|
||||
public ImmutableList<CuesWithTiming> parse(byte[] data, int offset, int length) {
|
||||
if (offset != 0) {
|
||||
if (dataScratch.length < length) {
|
||||
dataScratch = new byte[length];
|
||||
}
|
||||
System.arraycopy(
|
||||
/* src= */ data, /* scrPos= */ offset, /* dest= */ dataScratch, /* destPos= */ 0, length);
|
||||
buffer.reset(dataScratch, length);
|
||||
} else {
|
||||
buffer.reset(data, length);
|
||||
}
|
||||
buffer.reset(data, /* limit= */ offset + length);
|
||||
buffer.setPosition(offset);
|
||||
maybeInflateData(buffer);
|
||||
cueBuilder.reset();
|
||||
ArrayList<Cue> cues = new ArrayList<>();
|
||||
|
@ -65,6 +65,7 @@ public final class SsaParser implements SubtitleParser {
|
||||
|
||||
private final boolean haveInitializationData;
|
||||
@Nullable private final SsaDialogueFormat dialogueFormatFromInitializationData;
|
||||
private final ParsableByteArray parsableByteArray;
|
||||
|
||||
private @MonotonicNonNull Map<String, SsaStyle> styles;
|
||||
|
||||
@ -82,8 +83,6 @@ public final class SsaParser implements SubtitleParser {
|
||||
*/
|
||||
private float screenHeight;
|
||||
|
||||
private byte[] dataScratch = Util.EMPTY_BYTE_ARRAY;
|
||||
|
||||
public SsaParser() {
|
||||
this(/* initializationData= */ null);
|
||||
}
|
||||
@ -100,6 +99,7 @@ public final class SsaParser implements SubtitleParser {
|
||||
public SsaParser(@Nullable List<byte[]> initializationData) {
|
||||
screenWidth = Cue.DIMEN_UNSET;
|
||||
screenHeight = Cue.DIMEN_UNSET;
|
||||
parsableByteArray = new ParsableByteArray();
|
||||
|
||||
if (initializationData != null && !initializationData.isEmpty()) {
|
||||
haveInitializationData = true;
|
||||
@ -126,18 +126,14 @@ public final class SsaParser implements SubtitleParser {
|
||||
List<List<Cue>> cues = new ArrayList<>();
|
||||
List<Long> startTimesUs = new ArrayList<>();
|
||||
|
||||
if (dataScratch.length < length) {
|
||||
dataScratch = new byte[length];
|
||||
}
|
||||
System.arraycopy(
|
||||
/* src= */ data, /* scrPos= */ offset, /* dest= */ dataScratch, /* destPos= */ 0, length);
|
||||
ParsableByteArray parsableData = new ParsableByteArray(dataScratch, length);
|
||||
Charset charset = detectUtfCharset(parsableData);
|
||||
parsableByteArray.reset(data, /* limit= */ offset + length);
|
||||
parsableByteArray.setPosition(offset);
|
||||
Charset charset = detectUtfCharset(parsableByteArray);
|
||||
|
||||
if (!haveInitializationData) {
|
||||
parseHeader(parsableData, charset);
|
||||
parseHeader(parsableByteArray, charset);
|
||||
}
|
||||
parseEventBody(parsableData, cues, startTimesUs, charset);
|
||||
parseEventBody(parsableByteArray, cues, startTimesUs, charset);
|
||||
|
||||
ImmutableList.Builder<CuesWithTiming> cuesWithStartTimeAndDuration = ImmutableList.builder();
|
||||
for (int i = 0; i < cues.size(); i++) {
|
||||
|
@ -27,7 +27,6 @@ import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.ParsableByteArray;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.extractor.text.CuesWithTiming;
|
||||
import androidx.media3.extractor.text.SubtitleParser;
|
||||
import com.google.common.base.Charsets;
|
||||
@ -70,11 +69,12 @@ public final class SubripParser implements SubtitleParser {
|
||||
|
||||
private final StringBuilder textBuilder;
|
||||
private final ArrayList<String> tags;
|
||||
private byte[] dataScratch = Util.EMPTY_BYTE_ARRAY;
|
||||
private final ParsableByteArray parsableByteArray;
|
||||
|
||||
public SubripParser() {
|
||||
textBuilder = new StringBuilder();
|
||||
tags = new ArrayList<>();
|
||||
parsableByteArray = new ParsableByteArray();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -82,16 +82,12 @@ public final class SubripParser implements SubtitleParser {
|
||||
public ImmutableList<CuesWithTiming> parse(byte[] data, int offset, int length) {
|
||||
ImmutableList.Builder<CuesWithTiming> cues = new ImmutableList.Builder<>();
|
||||
|
||||
if (dataScratch.length < length) {
|
||||
dataScratch = new byte[length];
|
||||
}
|
||||
System.arraycopy(
|
||||
/* src= */ data, /* scrPos= */ offset, /* dest= */ dataScratch, /* destPos= */ 0, length);
|
||||
ParsableByteArray subripData = new ParsableByteArray(dataScratch, length);
|
||||
Charset charset = detectUtfCharset(subripData);
|
||||
parsableByteArray.reset(data, /* limit= */ offset + length);
|
||||
parsableByteArray.setPosition(offset);
|
||||
Charset charset = detectUtfCharset(parsableByteArray);
|
||||
|
||||
@Nullable String currentLine;
|
||||
while ((currentLine = subripData.readLine(charset)) != null) {
|
||||
while ((currentLine = parsableByteArray.readLine(charset)) != null) {
|
||||
if (currentLine.length() == 0) {
|
||||
// Skip blank lines.
|
||||
continue;
|
||||
@ -106,7 +102,7 @@ public final class SubripParser implements SubtitleParser {
|
||||
}
|
||||
|
||||
// Read and parse the timing line.
|
||||
currentLine = subripData.readLine(charset);
|
||||
currentLine = parsableByteArray.readLine(charset);
|
||||
if (currentLine == null) {
|
||||
Log.w(TAG, "Unexpected end");
|
||||
break;
|
||||
@ -126,13 +122,13 @@ public final class SubripParser implements SubtitleParser {
|
||||
// Read and parse the text and tags.
|
||||
textBuilder.setLength(0);
|
||||
tags.clear();
|
||||
currentLine = subripData.readLine(charset);
|
||||
currentLine = parsableByteArray.readLine(charset);
|
||||
while (!TextUtils.isEmpty(currentLine)) {
|
||||
if (textBuilder.length() > 0) {
|
||||
textBuilder.append("<br>");
|
||||
}
|
||||
textBuilder.append(processLine(currentLine, tags));
|
||||
currentLine = subripData.readLine(charset);
|
||||
currentLine = parsableByteArray.readLine(charset);
|
||||
}
|
||||
|
||||
Spanned text = Html.fromHtml(textBuilder.toString());
|
||||
|
@ -79,7 +79,6 @@ public final class Tx3gParser implements SubtitleParser {
|
||||
private final String defaultFontFamily;
|
||||
private final float defaultVerticalPlacement;
|
||||
private final int calculatedVideoTrackHeight;
|
||||
private byte[] dataScratch = Util.EMPTY_BYTE_ARRAY;
|
||||
|
||||
/**
|
||||
* Sets up a new {@link Tx3gParser} with default values.
|
||||
@ -128,16 +127,8 @@ public final class Tx3gParser implements SubtitleParser {
|
||||
|
||||
@Override
|
||||
public ImmutableList<CuesWithTiming> parse(byte[] data, int offset, int length) {
|
||||
if (offset != 0) {
|
||||
if (dataScratch.length < length) {
|
||||
dataScratch = new byte[length];
|
||||
}
|
||||
System.arraycopy(
|
||||
/* src= */ data, /* scrPos= */ offset, /* dest= */ dataScratch, /* destPos= */ 0, length);
|
||||
parsableByteArray.reset(dataScratch, length);
|
||||
} else {
|
||||
parsableByteArray.reset(data, length);
|
||||
}
|
||||
parsableByteArray.reset(data, /* limit= */ offset + length);
|
||||
parsableByteArray.setPosition(offset);
|
||||
String cueTextString = readSubtitleText(parsableByteArray);
|
||||
if (cueTextString.isEmpty()) {
|
||||
return ImmutableList.of(
|
||||
|
@ -46,39 +46,30 @@ public final class Mp4WebvttParser implements SubtitleParser {
|
||||
@SuppressWarnings("ConstantCaseForConstants")
|
||||
private static final int TYPE_vttc = 0x76747463;
|
||||
|
||||
private final ParsableByteArray sampleData;
|
||||
private byte[] dataScratch = Util.EMPTY_BYTE_ARRAY;
|
||||
private final ParsableByteArray parsableByteArray;
|
||||
|
||||
public Mp4WebvttParser() {
|
||||
sampleData = new ParsableByteArray();
|
||||
parsableByteArray = new ParsableByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<CuesWithTiming> parse(byte[] data, int offset, int length) {
|
||||
if (offset != 0) {
|
||||
if (dataScratch.length < length) {
|
||||
dataScratch = new byte[length];
|
||||
}
|
||||
System.arraycopy(
|
||||
/* src= */ data, /* scrPos= */ offset, /* dest= */ dataScratch, /* destPos= */ 0, length);
|
||||
sampleData.reset(dataScratch, length);
|
||||
} else {
|
||||
sampleData.reset(data, length);
|
||||
}
|
||||
parsableByteArray.reset(data, /* limit= */ offset + length);
|
||||
parsableByteArray.setPosition(offset);
|
||||
List<Cue> cues = new ArrayList<>();
|
||||
while (sampleData.bytesLeft() > 0) {
|
||||
while (parsableByteArray.bytesLeft() > 0) {
|
||||
// Webvtt in Mp4 samples have boxes inside of them, so we have to do a traditional box
|
||||
// parsing: first 4 bytes size and then 4 bytes type.
|
||||
checkArgument(
|
||||
sampleData.bytesLeft() >= BOX_HEADER_SIZE,
|
||||
parsableByteArray.bytesLeft() >= BOX_HEADER_SIZE,
|
||||
"Incomplete Mp4Webvtt Top Level box header found.");
|
||||
int boxSize = sampleData.readInt();
|
||||
int boxType = sampleData.readInt();
|
||||
int boxSize = parsableByteArray.readInt();
|
||||
int boxType = parsableByteArray.readInt();
|
||||
if (boxType == TYPE_vttc) {
|
||||
cues.add(parseVttCueBox(sampleData, boxSize - BOX_HEADER_SIZE));
|
||||
cues.add(parseVttCueBox(parsableByteArray, boxSize - BOX_HEADER_SIZE));
|
||||
} else {
|
||||
// Peers of the VTTCueBox are still not supported and are skipped.
|
||||
sampleData.skipBytes(boxSize - BOX_HEADER_SIZE);
|
||||
parsableByteArray.skipBytes(boxSize - BOX_HEADER_SIZE);
|
||||
}
|
||||
}
|
||||
return cues.isEmpty()
|
||||
|
@ -53,7 +53,7 @@ public final class WebvttParser implements SubtitleParser {
|
||||
|
||||
@Override
|
||||
public ImmutableList<CuesWithTiming> parse(byte[] data, int offset, int length) {
|
||||
parsableWebvttData.reset(data, length);
|
||||
parsableWebvttData.reset(data, /* limit= */ offset + length);
|
||||
parsableWebvttData.setPosition(offset);
|
||||
List<WebvttCssStyle> definedStyles = new ArrayList<>();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user