Refactored the SubtitleParser's parse() signature

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=111326567
This commit is contained in:
aquilescanta 2016-01-04 09:07:05 -08:00 committed by Oliver Woodman
parent 9bcd1069b1
commit 681df4e4aa
17 changed files with 188 additions and 121 deletions

View file

@ -21,13 +21,16 @@ import com.google.android.exoplayer.extractor.Extractor;
import com.google.android.exoplayer.extractor.ExtractorInput;
import com.google.android.exoplayer.extractor.PositionHolder;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.util.Util;
import android.app.Instrumentation;
import android.net.Uri;
import android.test.InstrumentationTestCase;
import org.mockito.MockitoAnnotations;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Random;
@ -115,4 +118,10 @@ public class TestUtil {
MockitoAnnotations.initMocks(instrumentationTestCase);
}
public static byte[] getByteArray(Instrumentation instrumentation, String fileName)
throws IOException {
InputStream is = instrumentation.getContext().getResources().getAssets().open(fileName);
return Util.toByteArray(is);
}
}

View file

@ -24,7 +24,6 @@ import android.util.ArraySet;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@ -107,29 +106,29 @@ public final class Mp4WebvttParserTest extends TestCase {
// Positive tests.
public void testSingleCueSample() throws IOException {
Subtitle result = parser.parse(new ByteArrayInputStream(SINGLE_CUE_SAMPLE));
public void testSingleCueSample() throws ParserException {
Subtitle result = parser.parse(SINGLE_CUE_SAMPLE, 0, SINGLE_CUE_SAMPLE.length);
Cue expectedCue = new Cue("Hello World"); // Line feed must be trimmed by the parser
assertMp4WebvttSubtitleEquals(result, expectedCue);
}
public void testTwoCuesSample() throws IOException {
Subtitle result = parser.parse(new ByteArrayInputStream(DOUBLE_CUE_SAMPLE));
public void testTwoCuesSample() throws ParserException {
Subtitle result = parser.parse(DOUBLE_CUE_SAMPLE, 0, DOUBLE_CUE_SAMPLE.length);
Cue firstExpectedCue = new Cue("Hello World");
Cue secondExpectedCue = new Cue("Bye Bye");
assertMp4WebvttSubtitleEquals(result, firstExpectedCue, secondExpectedCue);
}
public void testNoCueSample() throws IOException {
Subtitle result = parser.parse(new ByteArrayInputStream(NO_CUE_SAMPLE));
Subtitle result = parser.parse(NO_CUE_SAMPLE, 0, NO_CUE_SAMPLE.length);
assertMp4WebvttSubtitleEquals(result, new Cue[] {});
}
// Negative tests.
public void testSampleWithVttCueWithNoPayload() throws IOException {
public void testSampleWithVttCueWithNoPayload() {
try {
parser.parse(new ByteArrayInputStream(NO_PAYLOAD_CUE_SAMPLE));
parser.parse(NO_PAYLOAD_CUE_SAMPLE, 0, NO_PAYLOAD_CUE_SAMPLE.length);
} catch (ParserException e) {
// Expected.
return;
@ -137,9 +136,9 @@ public final class Mp4WebvttParserTest extends TestCase {
fail("The parser should have failed, no payload was included in the VTTCue.");
}
public void testSampleWithIncompleteHeader() throws IOException {
public void testSampleWithIncompleteHeader() {
try {
parser.parse(new ByteArrayInputStream(INCOMPLETE_HEADER_SAMPLE));
parser.parse(INCOMPLETE_HEADER_SAMPLE, 0, INCOMPLETE_HEADER_SAMPLE.length);
} catch (ParserException e) {
return;
}

View file

@ -15,10 +15,11 @@
*/
package com.google.android.exoplayer.text.subrip;
import com.google.android.exoplayer.testutil.TestUtil;
import android.test.InstrumentationTestCase;
import java.io.IOException;
import java.io.InputStream;
/**
* Unit test for {@link SubripParser}.
@ -34,8 +35,8 @@ public final class SubripParserTest extends InstrumentationTestCase {
public void testParseEmpty() throws IOException {
SubripParser parser = new SubripParser();
InputStream inputStream = getInputStream(EMPTY_FILE);
SubripSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), EMPTY_FILE);
SubripSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// Assert that the subtitle is empty.
assertEquals(0, subtitle.getEventTimeCount());
assertTrue(subtitle.getCues(0).isEmpty());
@ -43,8 +44,8 @@ public final class SubripParserTest extends InstrumentationTestCase {
public void testParseTypical() throws IOException {
SubripParser parser = new SubripParser();
InputStream inputStream = getInputStream(TYPICAL_FILE);
SubripSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_FILE);
SubripSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
assertEquals(6, subtitle.getEventTimeCount());
assertTypicalCue1(subtitle, 0);
assertTypicalCue2(subtitle, 2);
@ -53,8 +54,8 @@ public final class SubripParserTest extends InstrumentationTestCase {
public void testParseTypicalExtraBlankLine() throws IOException {
SubripParser parser = new SubripParser();
InputStream inputStream = getInputStream(TYPICAL_EXTRA_BLANK_LINE);
SubripSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_EXTRA_BLANK_LINE);
SubripSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
assertEquals(6, subtitle.getEventTimeCount());
assertTypicalCue1(subtitle, 0);
assertTypicalCue2(subtitle, 2);
@ -64,8 +65,8 @@ public final class SubripParserTest extends InstrumentationTestCase {
public void testParseTypicalMissingTimecode() throws IOException {
// Parsing should succeed, parsing the first and third cues only.
SubripParser parser = new SubripParser();
InputStream inputStream = getInputStream(TYPICAL_MISSING_TIMECODE);
SubripSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_MISSING_TIMECODE);
SubripSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
assertEquals(4, subtitle.getEventTimeCount());
assertTypicalCue1(subtitle, 0);
assertTypicalCue3(subtitle, 2);
@ -74,8 +75,8 @@ public final class SubripParserTest extends InstrumentationTestCase {
public void testParseTypicalMissingSequence() throws IOException {
// Parsing should succeed, parsing the first and third cues only.
SubripParser parser = new SubripParser();
InputStream inputStream = getInputStream(TYPICAL_MISSING_SEQUENCE);
SubripSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_MISSING_SEQUENCE);
SubripSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
assertEquals(4, subtitle.getEventTimeCount());
assertTypicalCue1(subtitle, 0);
assertTypicalCue3(subtitle, 2);
@ -83,8 +84,8 @@ public final class SubripParserTest extends InstrumentationTestCase {
public void testParseNoEndTimecodes() throws IOException {
SubripParser parser = new SubripParser();
InputStream inputStream = getInputStream(NO_END_TIMECODES_FILE);
SubripSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), NO_END_TIMECODES_FILE);
SubripSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// Test event count.
assertEquals(3, subtitle.getEventTimeCount());
@ -105,10 +106,6 @@ public final class SubripParserTest extends InstrumentationTestCase {
subtitle.getCues(subtitle.getEventTime(2)).get(0).text.toString());
}
private InputStream getInputStream(String fileName) throws IOException {
return getInstrumentation().getContext().getResources().getAssets().open(fileName);
}
private static void assertTypicalCue1(SubripSubtitle subtitle, int eventIndex) {
assertEquals(0, subtitle.getEventTime(eventIndex));
assertEquals("This is the first subtitle.",

View file

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer.text.ttml;
import com.google.android.exoplayer.testutil.TestUtil;
import com.google.android.exoplayer.text.Cue;
import android.test.InstrumentationTestCase;
@ -32,7 +33,6 @@ import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
@ -471,8 +471,7 @@ public final class TtmlParserTest extends InstrumentationTestCase {
private TtmlSubtitle getSubtitle(String file) throws IOException {
TtmlParser ttmlParser = new TtmlParser();
InputStream inputStream = getInstrumentation().getContext()
.getResources().getAssets().open(file);
return (TtmlSubtitle) ttmlParser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), file);
return ttmlParser.parse(bytes, 0, bytes.length);
}
}

View file

@ -15,13 +15,14 @@
*/
package com.google.android.exoplayer.text.webvtt;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.testutil.TestUtil;
import com.google.android.exoplayer.text.Cue;
import android.test.InstrumentationTestCase;
import android.text.Layout.Alignment;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
@ -39,21 +40,19 @@ public class WebvttParserTest extends InstrumentationTestCase {
public void testParseEmpty() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream = getInstrumentation().getContext().getResources().getAssets()
.open(EMPTY_FILE);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), EMPTY_FILE);
try {
parser.parse(inputStream);
fail("Expected IOException");
} catch (IOException expected) {
parser.parse(bytes, 0, bytes.length);
fail("Expected ParserException");
} catch (ParserException expected) {
// Do nothing.
}
}
public void testParseTypical() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets().open(TYPICAL_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_FILE);
WebvttSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// test event count
assertEquals(4, subtitle.getEventTimeCount());
@ -65,9 +64,8 @@ public class WebvttParserTest extends InstrumentationTestCase {
public void testParseTypicalWithIds() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream = getInstrumentation().getContext().getResources().getAssets()
.open(TYPICAL_WITH_IDS_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_WITH_IDS_FILE);
WebvttSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// test event count
assertEquals(4, subtitle.getEventTimeCount());
@ -79,9 +77,8 @@ public class WebvttParserTest extends InstrumentationTestCase {
public void testParseTypicalWithComments() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream = getInstrumentation().getContext().getResources().getAssets()
.open(TYPICAL_WITH_COMMENTS_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_WITH_COMMENTS_FILE);
WebvttSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// test event count
assertEquals(4, subtitle.getEventTimeCount());
@ -93,9 +90,8 @@ public class WebvttParserTest extends InstrumentationTestCase {
public void testParseWithTags() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream = getInstrumentation().getContext().getResources().getAssets()
.open(WITH_TAGS_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), WITH_TAGS_FILE);
WebvttSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// test event count
assertEquals(8, subtitle.getEventTimeCount());
@ -109,9 +105,8 @@ public class WebvttParserTest extends InstrumentationTestCase {
public void testParseWithPositioning() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream = getInstrumentation().getContext().getResources().getAssets()
.open(WITH_POSITIONING_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), WITH_POSITIONING_FILE);
WebvttSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// test event count
assertEquals(10, subtitle.getEventTimeCount());
@ -135,9 +130,8 @@ public class WebvttParserTest extends InstrumentationTestCase {
public void testParseWithBadCueHeader() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets().open(WITH_BAD_CUE_HEADER_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream);
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), WITH_BAD_CUE_HEADER_FILE);
WebvttSubtitle subtitle = parser.parse(bytes, 0, bytes.length);
// test event count
assertEquals(4, subtitle.getEventTimeCount());

View file

@ -322,4 +322,61 @@ public class ParsableByteArrayTest extends TestCase {
assertEquals((short) 0xFF02, byteArray.readLittleEndianShort());
}
public void testReadEmptyString() {
byte[] bytes = new byte[0];
ParsableByteArray parser = new ParsableByteArray(bytes);
assertNull(parser.readLine());
}
public void testReadSingleLineWithoutEndingTrail() {
byte[] bytes = new byte[] {
'f', 'o', 'o'
};
ParsableByteArray parser = new ParsableByteArray(bytes);
assertEquals("foo", parser.readLine());
assertNull(parser.readLine());
}
public void testReadSingleLineWithEndingLf() {
byte[] bytes = new byte[] {
'f', 'o', 'o', '\n'
};
ParsableByteArray parser = new ParsableByteArray(bytes);
assertEquals("foo", parser.readLine());
assertNull(parser.readLine());
}
public void testReadTwoLinesWithLfFollowedByCr() {
byte[] bytes = new byte[] {
'f', 'o', 'o', '\n', '\r', 'b', 'a', 'r'
};
ParsableByteArray parser = new ParsableByteArray(bytes);
assertEquals("foo", parser.readLine());
assertEquals("bar", parser.readLine());
assertNull(parser.readLine());
}
public void testReadThreeLinesWithEmptyLine() {
byte[] bytes = new byte[] {
'f', 'o', 'o', '\n', '\r', '\n', 'b', 'a', 'r'
};
ParsableByteArray parser = new ParsableByteArray(bytes);
assertEquals("foo", parser.readLine());
assertEquals("", parser.readLine());
assertEquals("bar", parser.readLine());
assertNull(parser.readLine());
}
public void testReadFourLinesWithCrFollowedByLf() {
byte[] bytes = new byte[] {
'f', 'o', 'o', '\r', '\n', '\n', 'b', 'a', 'r', '\n', '\r'
};
ParsableByteArray parser = new ParsableByteArray(bytes);
assertEquals("foo", parser.readLine());
assertEquals("", parser.readLine());
assertEquals("", parser.readLine());
assertEquals("bar", parser.readLine());
assertNull(parser.readLine());
}
}

View file

@ -31,10 +31,7 @@ import com.google.android.exoplayer.util.ParsableByteArray;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -111,12 +108,11 @@ import java.util.regex.Pattern;
return Extractor.RESULT_END_OF_INPUT;
}
private void processSample() throws IOException {
BufferedReader reader = new BufferedReader(
new InputStreamReader(new ByteArrayInputStream(sampleData), C.UTF8_NAME));
private void processSample() throws ParserException {
ParsableByteArray webvttData = new ParsableByteArray(sampleData);
// Validate the first line of the header.
WebvttParserUtil.validateWebvttHeaderLine(reader);
WebvttParserUtil.validateWebvttHeaderLine(webvttData);
// Defaults to use if the header doesn't contain an X-TIMESTAMP-MAP header.
long vttTimestampUs = 0;
@ -124,7 +120,7 @@ import java.util.regex.Pattern;
// Parse the remainder of the header looking for X-TIMESTAMP-MAP.
String line;
while (!TextUtils.isEmpty(line = reader.readLine())) {
while (!TextUtils.isEmpty(line = webvttData.readLine())) {
if (line.startsWith("X-TIMESTAMP-MAP")) {
Matcher localTimestampMatcher = LOCAL_TIMESTAMP.matcher(line);
if (!localTimestampMatcher.find()) {
@ -141,7 +137,7 @@ import java.util.regex.Pattern;
}
// Find the first cue header and parse the start time.
Matcher cueHeaderMatcher = WebvttParserUtil.findNextCueHeader(reader);
Matcher cueHeaderMatcher = WebvttParserUtil.findNextCueHeader(webvttData);
if (cueHeaderMatcher == null) {
// No cues found. Don't output a sample, but still output a corresponding track.
buildTrackOutput(0);

View file

@ -15,11 +15,10 @@
*/
package com.google.android.exoplayer.text;
import java.io.IOException;
import java.io.InputStream;
import com.google.android.exoplayer.ParserException;
/**
* Parses {@link Subtitle}s from {@link InputStream}s.
* Parses {@link Subtitle}s from a byte array.
*/
public interface SubtitleParser {
@ -32,12 +31,14 @@ public interface SubtitleParser {
public boolean canParse(String mimeType);
/**
* Parses a {@link Subtitle} from the provided {@link InputStream}.
* Parses a {@link Subtitle} from the provided {@code byte[]}.
*
* @param inputStream The stream from which to parse the subtitle.
* @param bytes The array holding the subtitle data.
* @param offset The offset of the subtitle data in bytes.
* @param length The length of the subtitle data in bytes.
* @return A parsed representation of the subtitle.
* @throws IOException If a problem occurred reading from the stream.
* @throws ParserException If a problem occurred parsing the subtitle data.
*/
public Subtitle parse(InputStream inputStream) throws IOException;
public Subtitle parse(byte[] bytes, int offset, int length) throws ParserException;
}

View file

@ -16,6 +16,7 @@
package com.google.android.exoplayer.text;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
@ -25,9 +26,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Wraps a {@link SubtitleParser}, exposing an interface similar to {@link MediaCodec} for
@ -165,12 +164,11 @@ import java.io.InputStream;
private void handleSample(long sampleTimeUs, SampleHolder holder) {
Subtitle parsedSubtitle = null;
IOException error = null;
ParserException error = null;
RuntimeException runtimeError = null;
try {
InputStream inputStream = new ByteArrayInputStream(holder.data.array(), 0, holder.size);
parsedSubtitle = parser.parse(inputStream);
} catch (IOException e) {
parsedSubtitle = parser.parse(holder.data.array(), 0, holder.size);
} catch (ParserException e) {
error = e;
} catch (RuntimeException e) {
runtimeError = e;

View file

@ -22,8 +22,6 @@ import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.ParsableByteArray;
import com.google.android.exoplayer.util.Util;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
@ -38,7 +36,6 @@ public final class Mp4WebvttParser implements SubtitleParser {
private static final int TYPE_payl = Util.getIntegerCodeForString("payl");
private final ParsableByteArray sampleData;
private byte[] inputBytesBuffer;
public Mp4WebvttParser() {
sampleData = new ParsableByteArray();
@ -50,15 +47,11 @@ public final class Mp4WebvttParser implements SubtitleParser {
}
@Override
public Mp4WebvttSubtitle parse(InputStream inputStream) throws IOException {
public Mp4WebvttSubtitle parse(byte[] bytes, int offset, int length) throws ParserException {
// 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.
int inputStreamByteCount = inputStream.available();
if (inputBytesBuffer == null || inputBytesBuffer.length < inputStreamByteCount) {
inputBytesBuffer = new byte[inputStreamByteCount];
}
inputStream.read(inputBytesBuffer, 0, inputStreamByteCount);
sampleData.reset(inputBytesBuffer, inputStreamByteCount);
sampleData.reset(bytes, offset + length);
sampleData.setPosition(offset);
List<Cue> resultingCueList = new ArrayList<>();
while (sampleData.bytesLeft() > 0) {
if (sampleData.bytesLeft() < BOX_HEADER_SIZE) {
@ -76,7 +69,7 @@ public final class Mp4WebvttParser implements SubtitleParser {
return new Mp4WebvttSubtitle(resultingCueList);
}
private static Cue parseVttCueBox(ParsableByteArray sampleData) throws IOException {
private static Cue parseVttCueBox(ParsableByteArray sampleData) throws ParserException {
while (sampleData.bytesLeft() > 0) {
if (sampleData.bytesLeft() < BOX_HEADER_SIZE) {
throw new ParserException("Incomplete vtt cue box header found.");

View file

@ -15,21 +15,17 @@
*/
package com.google.android.exoplayer.text.subrip;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.SubtitleParser;
import com.google.android.exoplayer.util.LongArray;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.ParsableByteArray;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -57,14 +53,15 @@ public final class SubripParser implements SubtitleParser {
}
@Override
public SubripSubtitle parse(InputStream inputStream) throws IOException {
public SubripSubtitle parse(byte[] bytes, int offset, int length) {
ArrayList<Cue> cues = new ArrayList<>();
LongArray cueTimesUs = new LongArray();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, C.UTF8_NAME));
ParsableByteArray subripData = new ParsableByteArray(bytes, offset + length);
subripData.setPosition(offset);
boolean haveEndTimecode;
String currentLine;
while ((currentLine = reader.readLine()) != null) {
while ((currentLine = subripData.readLine()) != null) {
if (currentLine.length() == 0) {
// Skip blank lines.
continue;
@ -80,7 +77,7 @@ public final class SubripParser implements SubtitleParser {
// Read and parse the timing line.
haveEndTimecode = false;
currentLine = reader.readLine();
currentLine = subripData.readLine();
Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine);
if (matcher.find()) {
cueTimesUs.add(parseTimecode(matcher.group(1)));
@ -96,7 +93,7 @@ public final class SubripParser implements SubtitleParser {
// Read and parse the text.
textBuilder.setLength(0);
while (!TextUtils.isEmpty(currentLine = reader.readLine())) {
while (!TextUtils.isEmpty(currentLine = subripData.readLine())) {
if (textBuilder.length() > 0) {
textBuilder.append("<br>");
}

View file

@ -17,7 +17,6 @@ package com.google.android.exoplayer.text.ttml;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.text.Subtitle;
import com.google.android.exoplayer.text.SubtitleParser;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.ParserUtil;
@ -30,8 +29,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
@ -97,10 +96,11 @@ public final class TtmlParser implements SubtitleParser {
}
@Override
public Subtitle parse(InputStream inputStream) throws IOException {
public TtmlSubtitle parse(byte[] bytes, int offset, int length) throws ParserException {
try {
XmlPullParser xmlParser = xmlParserFactory.newPullParser();
Map<String, TtmlStyle> globalStyles = new HashMap<>();
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes, offset, length);
xmlParser.setInput(inputStream, null);
TtmlSubtitle ttmlSubtitle = null;
LinkedList<TtmlNode> nodeStack = new LinkedList<>();
@ -150,6 +150,8 @@ public final class TtmlParser implements SubtitleParser {
return ttmlSubtitle;
} catch (XmlPullParserException xppe) {
throw new ParserException("Unable to parse source", xppe);
} catch (IOException e) {
throw new IllegalStateException("Unexpected error when reading input.", e);
}
}

View file

@ -20,10 +20,6 @@ import com.google.android.exoplayer.text.Subtitle;
import com.google.android.exoplayer.text.SubtitleParser;
import com.google.android.exoplayer.util.MimeTypes;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* A {@link SubtitleParser} for tx3g.
* <p>
@ -37,9 +33,8 @@ public final class Tx3gParser implements SubtitleParser {
}
@Override
public Subtitle parse(InputStream inputStream) throws IOException {
DataInputStream dataInputStream = new DataInputStream(inputStream);
String cueText = dataInputStream.readUTF();
public Subtitle parse(byte[] bytes, int offset, int length) {
String cueText = new String(bytes, offset, length);
return new Tx3gSubtitle(new Cue(cueText));
}

View file

@ -15,19 +15,16 @@
*/
package com.google.android.exoplayer.text.webvtt;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.SubtitleParser;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.ParsableByteArray;
import android.text.Layout.Alignment;
import android.text.TextUtils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -59,8 +56,9 @@ public final class WebvttParser implements SubtitleParser {
}
@Override
public final WebvttSubtitle parse(InputStream inputStream) throws IOException {
BufferedReader webvttData = new BufferedReader(new InputStreamReader(inputStream, C.UTF8_NAME));
public final WebvttSubtitle parse(byte[] bytes, int offset, int length) throws ParserException {
ParsableByteArray webvttData = new ParsableByteArray(bytes, offset + length);
webvttData.setPosition(offset);
// Validate the first line of the header, and skip the remainder.
WebvttParserUtil.validateWebvttHeaderLine(webvttData);

View file

@ -16,9 +16,8 @@
package com.google.android.exoplayer.text.webvtt;
import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.util.ParsableByteArray;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -38,9 +37,8 @@ public final class WebvttParserUtil {
*
* @param input The input from which the line should be read.
* @throws ParserException If the line isn't the start of a valid WebVTT file.
* @throws IOException If an error occurs reading from the input.
*/
public static void validateWebvttHeaderLine(BufferedReader input) throws IOException {
public static void validateWebvttHeaderLine(ParsableByteArray input) throws ParserException {
String line = input.readLine();
if (line == null || !HEADER.matcher(line).matches()) {
throw new ParserException("Expected WEBVTT. Got " + line);
@ -51,12 +49,11 @@ public final class WebvttParserUtil {
* Reads lines up to and including the next WebVTT cue header.
*
* @param input The input from which lines should be read.
* @throws IOException If an error occurs reading from the input.
* @return A {@link Matcher} for the WebVTT cue header, or null if the end of the input was
* reached without a cue header being found. In the case that a cue header is found, groups 1,
* 2 and 3 of the returned matcher contain the start time, end time and settings list.
*/
public static Matcher findNextCueHeader(BufferedReader input) throws IOException {
public static Matcher findNextCueHeader(ParsableByteArray input) {
String line;
while ((line = input.readLine()) != null) {
if (COMMENT.matcher(line).matches()) {

View file

@ -306,4 +306,38 @@ public final class ParsableByteArray {
return result;
}
/**
* Reads a line of text. A line is considered to be terminated by any one of a line feed ('\n'), a
* carriage return ('\r'), or a carriage return followed immediately by a line feed. Platform
* default's charset used.
*
* @return A String containing the contents of the line, not including any line-termination
* characters, or null if the end of the stream has been reached.
*/
public String readLine() {
if (bytesLeft() == 0) {
return null;
}
int lineLimit = position;
while (lineLimit < limit && data[lineLimit] != '\n' && data[lineLimit] != '\r') {
lineLimit++;
}
String line = new String(data, position, lineLimit - position);
position = lineLimit;
if (position == limit) {
return line;
}
if (data[position] == '\n') {
position++;
if (position == limit) {
return line;
}
}
if (data[position] == '\r') {
position++;
}
return line;
}
}

View file

@ -47,4 +47,5 @@ public final class ParserUtil {
public static String removeNamespacePrefix(String attributeName) {
return attributeName.replaceFirst("^.*:", "");
}
}