Commit 5baf5517 by aquilescanta Committed by Oliver Woodman

Add support for Cue Settings and Spanned text in MP4WebVTT

Using the provided methods by the previous refactors, it is now possible to use all of the WebVTT features already available.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=112243172
parent d45f0b8b
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer.text.mp4webvtt; package com.google.android.exoplayer.text.webvtt;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.Cue;
...@@ -73,16 +73,6 @@ public final class Mp4WebvttParserTest extends TestCase { ...@@ -73,16 +73,6 @@ public final class Mp4WebvttParserTest extends TestCase {
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 // Hello World 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64 // Hello World
}; };
private static final byte[] NO_PAYLOAD_CUE_SAMPLE = {
0x00, 0x00, 0x00, 0x1B, // Size
0x76, 0x74, 0x74, 0x63, // Box type. First VTT Cue box begins:
0x00, 0x00, 0x00, 0x13, // First contained payload box's size
0x71, 0x61, 0x79, 0x6c, // Type of box, which is not payload (qayl)
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, // Hello World
};
private static final byte[] INCOMPLETE_HEADER_SAMPLE = { private static final byte[] INCOMPLETE_HEADER_SAMPLE = {
0x00, 0x00, 0x00, 0x23, // Size 0x00, 0x00, 0x00, 0x23, // Size
0x76, 0x74, 0x74, 0x63, // "vttc" Box type. VTT Cue box begins: 0x76, 0x74, 0x74, 0x63, // "vttc" Box type. VTT Cue box begins:
...@@ -96,7 +86,6 @@ public final class Mp4WebvttParserTest extends TestCase { ...@@ -96,7 +86,6 @@ public final class Mp4WebvttParserTest extends TestCase {
0x76, 0x74, 0x74 0x76, 0x74, 0x74
}; };
private Mp4WebvttParser parser; private Mp4WebvttParser parser;
@Override @Override
...@@ -126,16 +115,6 @@ public final class Mp4WebvttParserTest extends TestCase { ...@@ -126,16 +115,6 @@ public final class Mp4WebvttParserTest extends TestCase {
// Negative tests. // Negative tests.
public void testSampleWithVttCueWithNoPayload() {
try {
parser.parse(NO_PAYLOAD_CUE_SAMPLE, 0, NO_PAYLOAD_CUE_SAMPLE.length);
} catch (ParserException e) {
// Expected.
return;
}
fail("The parser should have failed, no payload was included in the VTTCue.");
}
public void testSampleWithIncompleteHeader() { public void testSampleWithIncompleteHeader() {
try { try {
parser.parse(INCOMPLETE_HEADER_SAMPLE, 0, INCOMPLETE_HEADER_SAMPLE.length); parser.parse(INCOMPLETE_HEADER_SAMPLE, 0, INCOMPLETE_HEADER_SAMPLE.length);
...@@ -193,8 +172,8 @@ public final class Mp4WebvttParserTest extends TestCase { ...@@ -193,8 +172,8 @@ public final class Mp4WebvttParserTest extends TestCase {
if (aCue.size != anotherCue.size) { if (aCue.size != anotherCue.size) {
differences.add("size: " + aCue.size + " | " + anotherCue.size); differences.add("size: " + aCue.size + " | " + anotherCue.size);
} }
if (!Util.areEqual(aCue.text, anotherCue.text)) { if (!Util.areEqual(aCue.text.toString(), anotherCue.text.toString())) {
differences.add("text: " + aCue.text + " | " + anotherCue.text); differences.add("text: '" + aCue.text + "' | '" + anotherCue.text + '\'');
} }
if (!Util.areEqual(aCue.textAlignment, anotherCue.textAlignment)) { if (!Util.areEqual(aCue.textAlignment, anotherCue.textAlignment)) {
differences.add("textAlignment: " + aCue.textAlignment + " | " + anotherCue.textAlignment); differences.add("textAlignment: " + aCue.textAlignment + " | " + anotherCue.textAlignment);
......
...@@ -27,7 +27,7 @@ import android.text.style.UnderlineSpan; ...@@ -27,7 +27,7 @@ import android.text.style.UnderlineSpan;
public final class WebvttCueParserTest extends InstrumentationTestCase { public final class WebvttCueParserTest extends InstrumentationTestCase {
public void testParseStrictValidClassesAndTrailingTokens() throws Exception { public void testParseStrictValidClassesAndTrailingTokens() throws Exception {
Spanned text = WebvttCueParser.parseCueText("<v.first.loud Esme>" Spanned text = parseCueText("<v.first.loud Esme>"
+ "This <u.style1.style2 some stuff>is</u> text with <b.foo><i.bar>html</i></b> tags"); + "This <u.style1.style2 some stuff>is</u> text with <b.foo><i.bar>html</i></b> tags");
assertEquals("This is text with html tags", text.toString()); assertEquals("This is text with html tags", text.toString());
...@@ -48,18 +48,16 @@ public final class WebvttCueParserTest extends InstrumentationTestCase { ...@@ -48,18 +48,16 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
} }
public void testParseStrictValidUnsupportedTagsStrippedOut() throws Exception { public void testParseStrictValidUnsupportedTagsStrippedOut() throws Exception {
Spanned text = WebvttCueParser.parseCueText( Spanned text = parseCueText("<v.first.loud Esme>This <unsupported>is</unsupported> text with "
"<v.first.loud Esme>This <unsupported>is</unsupported> text with "
+ "<notsupp><invalid>html</invalid></notsupp> tags"); + "<notsupp><invalid>html</invalid></notsupp> tags");
assertEquals("This is text with html tags", text.toString()); assertEquals("This is text with html tags", text.toString());
assertEquals(0, getSpans(text, UnderlineSpan.class).length); assertEquals(0, getSpans(text, UnderlineSpan.class).length);
assertEquals(0, getSpans(text, StyleSpan.class).length); assertEquals(0, getSpans(text, StyleSpan.class).length);
} }
public void testParseWellFormedUnclosedEndAtCueEnd() throws Exception { public void testParseWellFormedUnclosedEndAtCueEnd() throws Exception {
Spanned text = WebvttCueParser.parseCueText( Spanned text = parseCueText("An <u some trailing stuff>unclosed u tag with "
"An <u some trailing stuff>unclosed u tag with <i>italic</i> inside"); + "<i>italic</i> inside");
assertEquals("An unclosed u tag with italic inside", text.toString()); assertEquals("An unclosed u tag with italic inside", text.toString());
...@@ -76,8 +74,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase { ...@@ -76,8 +74,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
} }
public void testParseWellFormedUnclosedEndAtParent() throws Exception { public void testParseWellFormedUnclosedEndAtParent() throws Exception {
Spanned text = WebvttCueParser.parseCueText( Spanned text = parseCueText("An unclosed u tag with <i><u>underline and italic</i> inside");
"An unclosed u tag with <i><u>underline and italic</i> inside");
assertEquals("An unclosed u tag with underline and italic inside", text.toString()); assertEquals("An unclosed u tag with underline and italic inside", text.toString());
...@@ -95,8 +92,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase { ...@@ -95,8 +92,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
} }
public void testParseMalformedNestedElements() throws Exception { public void testParseMalformedNestedElements() throws Exception {
Spanned text = WebvttCueParser.parseCueText( Spanned text = parseCueText("<b><u>An unclosed u tag with <i>italic</u> inside</i></b>");
"<b><u>An unclosed u tag with <i>italic</u> inside</i></b>");
assertEquals("An unclosed u tag with italic inside", text.toString()); assertEquals("An unclosed u tag with italic inside", text.toString());
UnderlineSpan[] underlineSpans = getSpans(text, UnderlineSpan.class); UnderlineSpan[] underlineSpans = getSpans(text, UnderlineSpan.class);
...@@ -121,7 +117,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase { ...@@ -121,7 +117,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
} }
public void testParseCloseNonExistingTag() throws Exception { public void testParseCloseNonExistingTag() throws Exception {
Spanned text = WebvttCueParser.parseCueText("blah<b>blah</i>blah</b>blah"); Spanned text = parseCueText("blah<b>blah</i>blah</b>blah");
assertEquals("blahblahblahblah", text.toString()); assertEquals("blahblahblahblah", text.toString());
StyleSpan[] spans = getSpans(text, StyleSpan.class); StyleSpan[] spans = getSpans(text, StyleSpan.class);
...@@ -132,42 +128,42 @@ public final class WebvttCueParserTest extends InstrumentationTestCase { ...@@ -132,42 +128,42 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
} }
public void testParseEmptyTagName() throws Exception { public void testParseEmptyTagName() throws Exception {
Spanned text = WebvttCueParser.parseCueText("An unclosed u tag with <>italic inside"); Spanned text = parseCueText("An unclosed u tag with <>italic inside");
assertEquals("An unclosed u tag with italic inside", text.toString()); assertEquals("An unclosed u tag with italic inside", text.toString());
} }
public void testParseEntities() throws Exception { public void testParseEntities() throws Exception {
Spanned text = WebvttCueParser.parseCueText("&amp; &gt; &lt; &nbsp;"); Spanned text = parseCueText("&amp; &gt; &lt; &nbsp;");
assertEquals("& > < ", text.toString()); assertEquals("& > < ", text.toString());
} }
public void testParseEntitiesUnsupported() throws Exception { public void testParseEntitiesUnsupported() throws Exception {
Spanned text = WebvttCueParser.parseCueText("&noway; &sure;"); Spanned text = parseCueText("&noway; &sure;");
assertEquals(" ", text.toString()); assertEquals(" ", text.toString());
} }
public void testParseEntitiesNotTerminated() throws Exception { public void testParseEntitiesNotTerminated() throws Exception {
Spanned text = WebvttCueParser.parseCueText("&amp here comes text"); Spanned text = parseCueText("&amp here comes text");
assertEquals("& here comes text", text.toString()); assertEquals("& here comes text", text.toString());
} }
public void testParseEntitiesNotTerminatedUnsupported() throws Exception { public void testParseEntitiesNotTerminatedUnsupported() throws Exception {
Spanned text = WebvttCueParser.parseCueText("&surenot here comes text"); Spanned text = parseCueText("&surenot here comes text");
assertEquals(" here comes text", text.toString()); assertEquals(" here comes text", text.toString());
} }
public void testParseEntitiesNotTerminatedNoSpace() throws Exception { public void testParseEntitiesNotTerminatedNoSpace() throws Exception {
Spanned text = WebvttCueParser.parseCueText("&surenot"); Spanned text = parseCueText("&surenot");
assertEquals("&surenot", text.toString()); assertEquals("&surenot", text.toString());
} }
public void testParseVoidTag() throws Exception { public void testParseVoidTag() throws Exception {
Spanned text = WebvttCueParser.parseCueText("here comes<br/> text<br/>"); Spanned text = parseCueText("here comes<br/> text<br/>");
assertEquals("here comes text", text.toString()); assertEquals("here comes text", text.toString());
} }
public void testParseMultipleTagsOfSameKind() { public void testParseMultipleTagsOfSameKind() {
Spanned text = WebvttCueParser.parseCueText("blah <b>blah</b> blah <b>foo</b>"); Spanned text = parseCueText("blah <b>blah</b> blah <b>foo</b>");
assertEquals("blah blah blah foo", text.toString()); assertEquals("blah blah blah foo", text.toString());
StyleSpan[] spans = getSpans(text, StyleSpan.class); StyleSpan[] spans = getSpans(text, StyleSpan.class);
...@@ -181,7 +177,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase { ...@@ -181,7 +177,7 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
} }
public void testParseInvalidVoidSlash() { public void testParseInvalidVoidSlash() {
Spanned text = WebvttCueParser.parseCueText("blah <b/.st1.st2 trailing stuff> blah"); Spanned text = parseCueText("blah <b/.st1.st2 trailing stuff> blah");
assertEquals("blah blah", text.toString()); assertEquals("blah blah", text.toString());
StyleSpan[] spans = getSpans(text, StyleSpan.class); StyleSpan[] spans = getSpans(text, StyleSpan.class);
...@@ -189,40 +185,46 @@ public final class WebvttCueParserTest extends InstrumentationTestCase { ...@@ -189,40 +185,46 @@ public final class WebvttCueParserTest extends InstrumentationTestCase {
} }
public void testParseMonkey() throws Exception { public void testParseMonkey() throws Exception {
Spanned text = WebvttCueParser.parseCueText( Spanned text = parseCueText("< u>An unclosed u tag with <<<<< i>italic</u></u></u></u >"
"< u>An unclosed u tag with <<<<< i>italic</u></u></u></u ></i><u><u> inside"); + "</i><u><u> inside");
assertEquals("An unclosed u tag with italic inside", text.toString()); assertEquals("An unclosed u tag with italic inside", text.toString());
text = WebvttCueParser.parseCueText(">>>>>>>>>An unclosed u tag with <<<<< italic</u></u></u>" text = parseCueText(">>>>>>>>>An unclosed u tag with <<<<< italic</u></u></u>"
+ "</u ></i><u><u> inside"); + "</u ></i><u><u> inside");
assertEquals(">>>>>>>>>An unclosed u tag with inside", text.toString()); assertEquals(">>>>>>>>>An unclosed u tag with inside", text.toString());
} }
public void testParseCornerCases() throws Exception { public void testParseCornerCases() throws Exception {
Spanned text = WebvttCueParser.parseCueText(">"); Spanned text = parseCueText(">");
assertEquals(">", text.toString()); assertEquals(">", text.toString());
text = WebvttCueParser.parseCueText("<"); text = parseCueText("<");
assertEquals("", text.toString()); assertEquals("", text.toString());
text = WebvttCueParser.parseCueText("<b.st1.st2 annotation"); text = parseCueText("<b.st1.st2 annotation");
assertEquals("", text.toString()); assertEquals("", text.toString());
text = WebvttCueParser.parseCueText("<<<<<<<<<<<<<<<<"); text = parseCueText("<<<<<<<<<<<<<<<<");
assertEquals("", text.toString()); assertEquals("", text.toString());
text = WebvttCueParser.parseCueText("<<<<<<>><<<<<<<<<<"); text = parseCueText("<<<<<<>><<<<<<<<<<");
assertEquals(">", text.toString()); assertEquals(">", text.toString());
text = WebvttCueParser.parseCueText("<>"); text = parseCueText("<>");
assertEquals("", text.toString()); assertEquals("", text.toString());
text = WebvttCueParser.parseCueText("&"); text = parseCueText("&");
assertEquals("&", text.toString()); assertEquals("&", text.toString());
text = WebvttCueParser.parseCueText("&&&&&&&"); text = parseCueText("&&&&&&&");
assertEquals("&&&&&&&", text.toString()); assertEquals("&&&&&&&", text.toString());
} }
private static Spanned parseCueText(String string) {
WebvttCue.Builder builder = new WebvttCue.Builder();
WebvttCueParser.parseCueText(string, builder);
return (Spanned) builder.build().text;
}
private static <T> T[] getSpans(Spanned text, Class<T> spanType) { private static <T> T[] getSpans(Spanned text, Class<T> spanType) {
return text.getSpans(0, text.length(), spanType); return text.getSpans(0, text.length(), spanType);
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer.text.mp4webvtt; package com.google.android.exoplayer.text.webvtt;
import com.google.android.exoplayer.ParserException; import com.google.android.exoplayer.ParserException;
import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.Cue;
...@@ -32,13 +32,16 @@ public final class Mp4WebvttParser implements SubtitleParser { ...@@ -32,13 +32,16 @@ public final class Mp4WebvttParser implements SubtitleParser {
private static final int BOX_HEADER_SIZE = 8; private static final int BOX_HEADER_SIZE = 8;
private static final int TYPE_vttc = Util.getIntegerCodeForString("vttc");
private static final int TYPE_payl = Util.getIntegerCodeForString("payl"); private static final int TYPE_payl = Util.getIntegerCodeForString("payl");
private static final int TYPE_sttg = Util.getIntegerCodeForString("sttg");
private static final int TYPE_vttc = Util.getIntegerCodeForString("vttc");
private final ParsableByteArray sampleData; private final ParsableByteArray sampleData;
private final WebvttCue.Builder builder;
public Mp4WebvttParser() { public Mp4WebvttParser() {
sampleData = new ParsableByteArray(); sampleData = new ParsableByteArray();
builder = new WebvttCue.Builder();
} }
@Override @Override
...@@ -60,7 +63,7 @@ public final class Mp4WebvttParser implements SubtitleParser { ...@@ -60,7 +63,7 @@ public final class Mp4WebvttParser implements SubtitleParser {
int boxSize = sampleData.readInt(); int boxSize = sampleData.readInt();
int boxType = sampleData.readInt(); int boxType = sampleData.readInt();
if (boxType == TYPE_vttc) { if (boxType == TYPE_vttc) {
resultingCueList.add(parseVttCueBox(sampleData)); resultingCueList.add(parseVttCueBox(sampleData, builder, boxSize - BOX_HEADER_SIZE));
} else { } else {
// Peers of the VTTCueBox are still not supported and are skipped. // Peers of the VTTCueBox are still not supported and are skipped.
sampleData.skipBytes(boxSize - BOX_HEADER_SIZE); sampleData.skipBytes(boxSize - BOX_HEADER_SIZE);
...@@ -69,24 +72,29 @@ public final class Mp4WebvttParser implements SubtitleParser { ...@@ -69,24 +72,29 @@ public final class Mp4WebvttParser implements SubtitleParser {
return new Mp4WebvttSubtitle(resultingCueList); return new Mp4WebvttSubtitle(resultingCueList);
} }
private static Cue parseVttCueBox(ParsableByteArray sampleData) throws ParserException { private static Cue parseVttCueBox(ParsableByteArray sampleData, WebvttCue.Builder builder,
while (sampleData.bytesLeft() > 0) { int remainingCueBoxBytes) throws ParserException {
if (sampleData.bytesLeft() < BOX_HEADER_SIZE) { builder.reset();
while (remainingCueBoxBytes > 0) {
if (remainingCueBoxBytes < BOX_HEADER_SIZE) {
throw new ParserException("Incomplete vtt cue box header found."); throw new ParserException("Incomplete vtt cue box header found.");
} }
int boxSize = sampleData.readInt(); int boxSize = sampleData.readInt();
int boxType = sampleData.readInt(); int boxType = sampleData.readInt();
if (boxType == TYPE_payl) { remainingCueBoxBytes -= BOX_HEADER_SIZE;
int payloadLength = boxSize - BOX_HEADER_SIZE; int payloadLength = boxSize - BOX_HEADER_SIZE;
String cueText = new String(sampleData.data, sampleData.getPosition(), payloadLength); String boxPayload = new String(sampleData.data, sampleData.getPosition(), payloadLength);
sampleData.skipBytes(payloadLength); sampleData.skipBytes(payloadLength);
return new Cue(cueText.trim()); remainingCueBoxBytes -= payloadLength;
if (boxType == TYPE_sttg) {
WebvttCueParser.parseCueSettingsList(boxPayload, builder);
} else if (boxType == TYPE_payl) {
WebvttCueParser.parseCueText(boxPayload.trim(), builder);
} else { } else {
// Other VTTCueBox children are still not supported and are skipped. // Other VTTCueBox children are still not supported and are ignored.
sampleData.skipBytes(boxSize - BOX_HEADER_SIZE);
} }
} }
throw new ParserException("VTTCueBox does not contain mandatory payload box."); return builder.build();
} }
} }
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.google.android.exoplayer.text.mp4webvtt; package com.google.android.exoplayer.text.webvtt;
import com.google.android.exoplayer.text.Cue; import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.Subtitle; import com.google.android.exoplayer.text.Subtitle;
......
...@@ -76,13 +76,13 @@ public final class WebvttCueParser { ...@@ -76,13 +76,13 @@ public final class WebvttCueParser {
* Parses the next valid WebVTT cue in a parsable array, including timestamps, settings and text. * Parses the next valid WebVTT cue in a parsable array, including timestamps, settings and text.
* *
* @param webvttData Parsable WebVTT file data. * @param webvttData Parsable WebVTT file data.
* @param cueBuilder Builder for WebVTT Cues. * @param builder Builder for WebVTT Cues.
* @return True if a valid Cue was found, false otherwise. * @return True if a valid Cue was found, false otherwise.
*/ */
public boolean parseNextValidCue(ParsableByteArray webvttData, WebvttCue.Builder cueBuilder) { /* package */ boolean parseNextValidCue(ParsableByteArray webvttData, WebvttCue.Builder builder) {
Matcher cueHeaderMatcher; Matcher cueHeaderMatcher;
while ((cueHeaderMatcher = findNextCueHeader(webvttData)) != null) { while ((cueHeaderMatcher = findNextCueHeader(webvttData)) != null) {
if (parseCue(cueHeaderMatcher, webvttData, cueBuilder, textBuilder)) { if (parseCue(cueHeaderMatcher, webvttData, builder, textBuilder)) {
return true; return true;
} }
} }
...@@ -95,7 +95,8 @@ public final class WebvttCueParser { ...@@ -95,7 +95,8 @@ public final class WebvttCueParser {
* @param cueSettingsList String containing the settings for a given cue. * @param cueSettingsList String containing the settings for a given cue.
* @param builder The {@link WebvttCue.Builder} where incremental construction takes place. * @param builder The {@link WebvttCue.Builder} where incremental construction takes place.
*/ */
public static void parseCueSettingsList(String cueSettingsList, WebvttCue.Builder builder) { /* package */ static void parseCueSettingsList(String cueSettingsList,
WebvttCue.Builder builder) {
// Parse the cue settings list. // Parse the cue settings list.
Matcher cueSettingMatcher = CUE_SETTING_PATTERN.matcher(cueSettingsList); Matcher cueSettingMatcher = CUE_SETTING_PATTERN.matcher(cueSettingsList);
while (cueSettingMatcher.find()) { while (cueSettingMatcher.find()) {
...@@ -143,33 +144,13 @@ public final class WebvttCueParser { ...@@ -143,33 +144,13 @@ public final class WebvttCueParser {
return null; return null;
} }
private static boolean parseCue(Matcher cueHeaderMatcher, ParsableByteArray webvttData, /**
WebvttCue.Builder builder, StringBuilder textBuilder) { * Parses the text payload of a WebVTT Cue and applies modifications on {@link WebvttCue.Builder}.
try { *
// Parse the cue start and end times. * @param markup The markup text to be parsed.
builder.setStartTime(WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(1))) * @param builder Target builder.
.setEndTime(WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(2))); */
} catch (NumberFormatException e) { /* package */ static void parseCueText(String markup, WebvttCue.Builder builder) {
Log.w(TAG, "Skipping cue with bad header: " + cueHeaderMatcher.group());
return false;
}
parseCueSettingsList(cueHeaderMatcher.group(3), builder);
// Parse the cue text.
textBuilder.setLength(0);
String line;
while ((line = webvttData.readLine()) != null && !line.isEmpty()) {
if (textBuilder.length() > 0) {
textBuilder.append("\n");
}
textBuilder.append(line.trim());
}
builder.setText(parseCueText(textBuilder.toString()));
return true;
}
/* package */ static Spanned parseCueText(String markup) {
SpannableStringBuilder spannedText = new SpannableStringBuilder(); SpannableStringBuilder spannedText = new SpannableStringBuilder();
Stack<StartTag> startTagStack = new Stack<>(); Stack<StartTag> startTagStack = new Stack<>();
String[] tagTokens; String[] tagTokens;
...@@ -231,7 +212,33 @@ public final class WebvttCueParser { ...@@ -231,7 +212,33 @@ public final class WebvttCueParser {
while (!startTagStack.isEmpty()) { while (!startTagStack.isEmpty()) {
applySpansForTag(startTagStack.pop(), spannedText); applySpansForTag(startTagStack.pop(), spannedText);
} }
return spannedText; builder.setText(spannedText);
}
private static boolean parseCue(Matcher cueHeaderMatcher, ParsableByteArray webvttData,
WebvttCue.Builder builder, StringBuilder textBuilder) {
try {
// Parse the cue start and end times.
builder.setStartTime(WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(1)))
.setEndTime(WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(2)));
} catch (NumberFormatException e) {
Log.w(TAG, "Skipping cue with bad header: " + cueHeaderMatcher.group());
return false;
}
parseCueSettingsList(cueHeaderMatcher.group(3), builder);
// Parse the cue text.
textBuilder.setLength(0);
String line;
while ((line = webvttData.readLine()) != null && !line.isEmpty()) {
if (textBuilder.length() > 0) {
textBuilder.append("\n");
}
textBuilder.append(line.trim());
}
parseCueText(textBuilder.toString(), builder);
return true;
} }
// Internal methods // Internal methods
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment