mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Refactored the SubtitleParser's parse() signature
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=111326567
This commit is contained in:
parent
9bcd1069b1
commit
681df4e4aa
17 changed files with 188 additions and 121 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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>");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,4 +47,5 @@ public final class ParserUtil {
|
|||
public static String removeNamespacePrefix(String attributeName) {
|
||||
return attributeName.replaceFirst("^.*:", "");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue