mirror of
https://github.com/samsonjs/media.git
synced 2026-04-11 12:15:47 +00:00
Simplify subtitle parsing.
- Currently all subtitles we parse contain timestamps relative to the sample timestamp, however we add the sample timestamp in inconsistent ways (sometimes in the Subtitle, sometimes in the SubtitleParser). This change converges on a single approach. It also paves the way for passing absolute offsets to use instead, and being able to apply them in a consistent way in a single place (PlayableSubtitle). This functionality will be required for ISO 14496-30 TTML embedded subtitles. Issue: #689
This commit is contained in:
parent
fbf590fdf6
commit
bf77f3b289
16 changed files with 127 additions and 115 deletions
|
|
@ -34,7 +34,7 @@ public final class SubripParserTest extends InstrumentationTestCase {
|
|||
SubripParser parser = new SubripParser();
|
||||
InputStream inputStream =
|
||||
getInstrumentation().getContext().getResources().getAssets().open(EMPTY_SUBRIP_FILE);
|
||||
SubripSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
|
||||
SubripSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME);
|
||||
// Assert that the subtitle is empty.
|
||||
assertEquals(0, subtitle.getEventTimeCount());
|
||||
assertTrue(subtitle.getCues(0).isEmpty());
|
||||
|
|
@ -44,10 +44,9 @@ public final class SubripParserTest extends InstrumentationTestCase {
|
|||
SubripParser parser = new SubripParser();
|
||||
InputStream inputStream =
|
||||
getInstrumentation().getContext().getResources().getAssets().open(TYPICAL_SUBRIP_FILE);
|
||||
SubripSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
|
||||
SubripSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME);
|
||||
|
||||
// Test start time and event count.
|
||||
assertEquals(0, subtitle.getStartTime());
|
||||
// Test event count.
|
||||
assertEquals(4, subtitle.getEventTimeCount());
|
||||
|
||||
// Test first cue.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class WebvttParserTest extends InstrumentationTestCase {
|
|||
getInstrumentation().getContext().getResources().getAssets().open(EMPTY_WEBVTT_FILE);
|
||||
|
||||
try {
|
||||
parser.parse(inputStream, C.UTF8_NAME, 0);
|
||||
parser.parse(inputStream, C.UTF8_NAME);
|
||||
fail("Expected IOException");
|
||||
} catch (IOException expected) {
|
||||
// Do nothing.
|
||||
|
|
@ -50,10 +50,9 @@ public class WebvttParserTest extends InstrumentationTestCase {
|
|||
WebvttParser parser = new WebvttParser();
|
||||
InputStream inputStream =
|
||||
getInstrumentation().getContext().getResources().getAssets().open(TYPICAL_WEBVTT_FILE);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME);
|
||||
|
||||
// test start time and event count
|
||||
assertEquals(0, subtitle.getStartTime());
|
||||
// test event count
|
||||
assertEquals(4, subtitle.getEventTimeCount());
|
||||
|
||||
// test first cue
|
||||
|
|
@ -74,10 +73,9 @@ public class WebvttParserTest extends InstrumentationTestCase {
|
|||
InputStream inputStream =
|
||||
getInstrumentation().getContext().getResources().getAssets()
|
||||
.open(TYPICAL_WITH_IDS_WEBVTT_FILE);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME);
|
||||
|
||||
// test start time and event count
|
||||
assertEquals(0, subtitle.getStartTime());
|
||||
// test event count
|
||||
assertEquals(4, subtitle.getEventTimeCount());
|
||||
|
||||
// test first cue
|
||||
|
|
@ -98,10 +96,9 @@ public class WebvttParserTest extends InstrumentationTestCase {
|
|||
InputStream inputStream =
|
||||
getInstrumentation().getContext().getResources().getAssets()
|
||||
.open(TYPICAL_WITH_TAGS_WEBVTT_FILE);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME);
|
||||
|
||||
// test start time and event count
|
||||
assertEquals(0, subtitle.getStartTime());
|
||||
// test event count
|
||||
assertEquals(8, subtitle.getEventTimeCount());
|
||||
|
||||
// test first cue
|
||||
|
|
@ -133,11 +130,10 @@ public class WebvttParserTest extends InstrumentationTestCase {
|
|||
WebvttParser parser = new WebvttParser();
|
||||
InputStream inputStream =
|
||||
getInstrumentation().getContext().getResources().getAssets().open(LIVE_TYPICAL_WEBVTT_FILE);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
|
||||
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME);
|
||||
|
||||
// test start time and event count
|
||||
// test event count
|
||||
long startTimeUs = 0;
|
||||
assertEquals(startTimeUs, subtitle.getStartTime());
|
||||
assertEquals(4, subtitle.getEventTimeCount());
|
||||
|
||||
// test first cue
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class WebvttSubtitleTest extends TestCase {
|
|||
private static final String FIRST_AND_SECOND_SUBTITLE_STRING =
|
||||
FIRST_SUBTITLE_STRING + "\n" + SECOND_SUBTITLE_STRING;
|
||||
|
||||
private WebvttSubtitle emptySubtitle = new WebvttSubtitle(new ArrayList<WebvttCue>(), 0);
|
||||
private WebvttSubtitle emptySubtitle = new WebvttSubtitle(new ArrayList<WebvttCue>());
|
||||
|
||||
private ArrayList<WebvttCue> simpleSubtitleCues = new ArrayList<>();
|
||||
{
|
||||
|
|
@ -42,7 +42,7 @@ public class WebvttSubtitleTest extends TestCase {
|
|||
WebvttCue secondCue = new WebvttCue(3000000, 4000000, SECOND_SUBTITLE_STRING);
|
||||
simpleSubtitleCues.add(secondCue);
|
||||
}
|
||||
private WebvttSubtitle simpleSubtitle = new WebvttSubtitle(simpleSubtitleCues, 0);
|
||||
private WebvttSubtitle simpleSubtitle = new WebvttSubtitle(simpleSubtitleCues);
|
||||
|
||||
private ArrayList<WebvttCue> overlappingSubtitleCues = new ArrayList<>();
|
||||
{
|
||||
|
|
@ -52,7 +52,7 @@ public class WebvttSubtitleTest extends TestCase {
|
|||
WebvttCue secondCue = new WebvttCue(2000000, 4000000, SECOND_SUBTITLE_STRING);
|
||||
overlappingSubtitleCues.add(secondCue);
|
||||
}
|
||||
private WebvttSubtitle overlappingSubtitle = new WebvttSubtitle(overlappingSubtitleCues, 0);
|
||||
private WebvttSubtitle overlappingSubtitle = new WebvttSubtitle(overlappingSubtitleCues);
|
||||
|
||||
private ArrayList<WebvttCue> nestedSubtitleCues = new ArrayList<>();
|
||||
{
|
||||
|
|
@ -62,7 +62,7 @@ public class WebvttSubtitleTest extends TestCase {
|
|||
WebvttCue secondCue = new WebvttCue(2000000, 3000000, SECOND_SUBTITLE_STRING);
|
||||
nestedSubtitleCues.add(secondCue);
|
||||
}
|
||||
private WebvttSubtitle nestedSubtitle = new WebvttSubtitle(nestedSubtitleCues, 0);
|
||||
private WebvttSubtitle nestedSubtitle = new WebvttSubtitle(nestedSubtitleCues);
|
||||
|
||||
public void testEventCount() {
|
||||
assertEquals(0, emptySubtitle.getEventTimeCount());
|
||||
|
|
@ -71,13 +71,6 @@ public class WebvttSubtitleTest extends TestCase {
|
|||
assertEquals(4, nestedSubtitle.getEventTimeCount());
|
||||
}
|
||||
|
||||
public void testStartTime() {
|
||||
assertEquals(0, emptySubtitle.getStartTime());
|
||||
assertEquals(0, simpleSubtitle.getStartTime());
|
||||
assertEquals(0, overlappingSubtitle.getStartTime());
|
||||
assertEquals(0, nestedSubtitle.getStartTime());
|
||||
}
|
||||
|
||||
public void testLastEventTime() {
|
||||
assertEquals(-1, emptySubtitle.getLastEventTime());
|
||||
assertEquals(4000000, simpleSubtitle.getLastEventTime());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package com.google.android.exoplayer.text;
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A subtitle that wraps another subtitle, making it playable by adjusting it to be correctly
|
||||
* aligned with the playback timebase.
|
||||
*/
|
||||
/* package */ final class PlayableSubtitle implements Subtitle {
|
||||
|
||||
/**
|
||||
* The start time of the subtitle.
|
||||
* <p>
|
||||
* May be less than {@code getEventTime(0)}, since a subtitle may begin prior to the time of the
|
||||
* first event.
|
||||
*/
|
||||
public final long startTimeUs;
|
||||
|
||||
private final Subtitle subtitle;
|
||||
|
||||
/**
|
||||
* @param startTimeUs The start time of the subtitle.
|
||||
* @param subtitle The subtitle to wrap.
|
||||
*/
|
||||
public PlayableSubtitle(long startTimeUs, Subtitle subtitle) {
|
||||
this.startTimeUs = startTimeUs;
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextEventTimeIndex(long timeUs) {
|
||||
return subtitle.getNextEventTimeIndex(timeUs - startTimeUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEventTimeCount() {
|
||||
return subtitle.getEventTimeCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEventTime(int index) {
|
||||
return subtitle.getEventTime(index) + startTimeUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastEventTime() {
|
||||
return subtitle.getLastEventTime() + startTimeUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cue> getCues(long timeUs) {
|
||||
return subtitle.getCues(timeUs - startTimeUs);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -22,16 +22,6 @@ import java.util.List;
|
|||
*/
|
||||
public interface Subtitle {
|
||||
|
||||
/**
|
||||
* Gets the start time of the subtitle.
|
||||
* <p>
|
||||
* Note that the value returned may be less than {@code getEventTime(0)}, since a subtitle may
|
||||
* begin prior to the time of the first event.
|
||||
*
|
||||
* @return The start time of the subtitle in microseconds.
|
||||
*/
|
||||
public long getStartTime();
|
||||
|
||||
/**
|
||||
* Gets the index of the first event that occurs after a given time (exclusive).
|
||||
*
|
||||
|
|
|
|||
|
|
@ -36,11 +36,9 @@ public interface SubtitleParser {
|
|||
*
|
||||
* @param inputStream The stream from which to parse the subtitle.
|
||||
* @param inputEncoding The encoding of the input stream.
|
||||
* @param startTimeUs The start time of the subtitle.
|
||||
* @return A parsed representation of the subtitle.
|
||||
* @throws IOException If a problem occurred reading from the stream.
|
||||
*/
|
||||
public Subtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
|
||||
throws IOException;
|
||||
public Subtitle parse(InputStream inputStream, String inputEncoding) throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer.text;
|
|||
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.Util;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.os.Handler;
|
||||
|
|
@ -31,14 +32,14 @@ import java.io.InputStream;
|
|||
* Wraps a {@link SubtitleParser}, exposing an interface similar to {@link MediaCodec} for
|
||||
* asynchronous parsing of subtitles.
|
||||
*/
|
||||
public final class SubtitleParserHelper implements Handler.Callback {
|
||||
/* package */ final class SubtitleParserHelper implements Handler.Callback {
|
||||
|
||||
private final SubtitleParser parser;
|
||||
|
||||
private final Handler handler;
|
||||
private SampleHolder sampleHolder;
|
||||
private boolean parsing;
|
||||
private Subtitle result;
|
||||
private PlayableSubtitle result;
|
||||
private IOException error;
|
||||
|
||||
/**
|
||||
|
|
@ -94,7 +95,8 @@ public final class SubtitleParserHelper implements Handler.Callback {
|
|||
parsing = true;
|
||||
result = null;
|
||||
error = null;
|
||||
handler.obtainMessage(0, sampleHolder).sendToTarget();
|
||||
handler.obtainMessage(0, Util.getTopInt(sampleHolder.timeUs),
|
||||
Util.getBottomInt(sampleHolder.timeUs), sampleHolder).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +108,7 @@ public final class SubtitleParserHelper implements Handler.Callback {
|
|||
* @return The result of the parsing operation, or null.
|
||||
* @throws IOException If the parsing operation failed.
|
||||
*/
|
||||
public synchronized Subtitle getAndClearResult() throws IOException {
|
||||
public synchronized PlayableSubtitle getAndClearResult() throws IOException {
|
||||
try {
|
||||
if (error != null) {
|
||||
throw error;
|
||||
|
|
@ -120,22 +122,21 @@ public final class SubtitleParserHelper implements Handler.Callback {
|
|||
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
Subtitle result;
|
||||
IOException error;
|
||||
long sampleTimeUs = Util.getLong(msg.arg1, msg.arg2);
|
||||
SampleHolder holder = (SampleHolder) msg.obj;
|
||||
Subtitle parsedSubtitle = null;
|
||||
IOException error = null;
|
||||
try {
|
||||
InputStream inputStream = new ByteArrayInputStream(holder.data.array(), 0, holder.size);
|
||||
result = parser.parse(inputStream, null, sampleHolder.timeUs);
|
||||
error = null;
|
||||
parsedSubtitle = parser.parse(inputStream, null);
|
||||
} catch (IOException e) {
|
||||
result = null;
|
||||
error = e;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (sampleHolder != holder) {
|
||||
// A flush has occurred since this holder was posted. Do nothing.
|
||||
} else {
|
||||
this.result = result;
|
||||
this.result = new PlayableSubtitle(sampleTimeUs, parsedSubtitle);
|
||||
this.error = error;
|
||||
this.parsing = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
|||
|
||||
private int parserIndex;
|
||||
private boolean inputStreamEnded;
|
||||
private Subtitle subtitle;
|
||||
private Subtitle nextSubtitle;
|
||||
private PlayableSubtitle subtitle;
|
||||
private PlayableSubtitle nextSubtitle;
|
||||
private SubtitleParserHelper parserHelper;
|
||||
private HandlerThread parserThread;
|
||||
private int nextSubtitleEventIndex;
|
||||
|
|
@ -208,7 +208,7 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
|||
}
|
||||
|
||||
if (subtitleNextEventTimeUs == Long.MAX_VALUE && nextSubtitle != null
|
||||
&& nextSubtitle.getStartTime() <= positionUs) {
|
||||
&& nextSubtitle.startTimeUs <= positionUs) {
|
||||
// Advance to the next subtitle. Sync the next event index and trigger an update.
|
||||
subtitle = nextSubtitle;
|
||||
nextSubtitle = null;
|
||||
|
|
|
|||
|
|
@ -50,8 +50,7 @@ public final class SubripParser implements SubtitleParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SubripSubtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
|
||||
throws IOException {
|
||||
public SubripSubtitle parse(InputStream inputStream, String inputEncoding) throws IOException {
|
||||
ArrayList<Cue> cues = new ArrayList<>();
|
||||
LongArray cueTimesUs = new LongArray();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, C.UTF8_NAME));
|
||||
|
|
@ -69,8 +68,8 @@ public final class SubripParser implements SubtitleParser {
|
|||
currentLine = reader.readLine();
|
||||
Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine);
|
||||
if (matcher.find()) {
|
||||
cueTimesUs.add(startTimeUs + parseTimestampUs(matcher.group(1)));
|
||||
cueTimesUs.add(startTimeUs + parseTimestampUs(matcher.group(2)));
|
||||
cueTimesUs.add(parseTimestampUs(matcher.group(1)));
|
||||
cueTimesUs.add(parseTimestampUs(matcher.group(2)));
|
||||
} else {
|
||||
throw new ParserException("Expected timing line: " + currentLine);
|
||||
}
|
||||
|
|
@ -91,7 +90,7 @@ public final class SubripParser implements SubtitleParser {
|
|||
Cue[] cuesArray = new Cue[cues.size()];
|
||||
cues.toArray(cuesArray);
|
||||
long[] cueTimesUsArray = cueTimesUs.toArray();
|
||||
return new SubripSubtitle(startTimeUs, cuesArray, cueTimesUsArray);
|
||||
return new SubripSubtitle(cuesArray, cueTimesUsArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -28,27 +28,18 @@ import java.util.List;
|
|||
*/
|
||||
/* package */ final class SubripSubtitle implements Subtitle {
|
||||
|
||||
private final long startTimeUs;
|
||||
|
||||
private final Cue[] cues;
|
||||
private final long[] cueTimesUs;
|
||||
|
||||
/**
|
||||
* @param startTimeUs The start time of the subtitle, in microseconds.
|
||||
* @param cues The cues in the subtitle.
|
||||
* @param cueTimesUs Interleaved cue start and end times, in microseconds.
|
||||
*/
|
||||
public SubripSubtitle(long startTimeUs, Cue[] cues, long[] cueTimesUs) {
|
||||
this.startTimeUs = startTimeUs;
|
||||
public SubripSubtitle(Cue[] cues, long[] cueTimesUs) {
|
||||
this.cues = cues;
|
||||
this.cueTimesUs = cueTimesUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return startTimeUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextEventTimeIndex(long timeUs) {
|
||||
int index = Util.binarySearchCeil(cueTimesUs, timeUs, false, false);
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ public final class TtmlParser implements SubtitleParser {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param strictParsing If true, {@link #parse(InputStream, String, long)} will throw a
|
||||
* @param strictParsing If true, {@link #parse(InputStream, String)} will throw a
|
||||
* {@link ParserException} if the stream contains invalid data. If false, the parser will
|
||||
* make a best effort to ignore minor errors in the stream. Note however that a
|
||||
* {@link ParserException} will still be thrown when this is not possible.
|
||||
|
|
@ -99,8 +99,7 @@ public final class TtmlParser implements SubtitleParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Subtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
|
||||
throws IOException {
|
||||
public Subtitle parse(InputStream inputStream, String inputEncoding) throws IOException {
|
||||
try {
|
||||
XmlPullParser xmlParser = xmlParserFactory.newPullParser();
|
||||
xmlParser.setInput(inputStream, inputEncoding);
|
||||
|
|
@ -137,7 +136,7 @@ public final class TtmlParser implements SubtitleParser {
|
|||
parent.addChild(TtmlNode.buildTextNode(xmlParser.getText()));
|
||||
} else if (eventType == XmlPullParser.END_TAG) {
|
||||
if (xmlParser.getName().equals(TtmlNode.TAG_TT)) {
|
||||
ttmlSubtitle = new TtmlSubtitle(nodeStack.getLast(), startTimeUs);
|
||||
ttmlSubtitle = new TtmlSubtitle(nodeStack.getLast());
|
||||
}
|
||||
nodeStack.removeLast();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,23 +28,16 @@ import java.util.List;
|
|||
public final class TtmlSubtitle implements Subtitle {
|
||||
|
||||
private final TtmlNode root;
|
||||
private final long startTimeUs;
|
||||
private final long[] eventTimesUs;
|
||||
|
||||
public TtmlSubtitle(TtmlNode root, long startTimeUs) {
|
||||
public TtmlSubtitle(TtmlNode root) {
|
||||
this.root = root;
|
||||
this.startTimeUs = startTimeUs;
|
||||
this.eventTimesUs = root.getEventTimesUs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return startTimeUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextEventTimeIndex(long timeUs) {
|
||||
int index = Util.binarySearchCeil(eventTimesUs, timeUs - startTimeUs, false, false);
|
||||
int index = Util.binarySearchCeil(eventTimesUs, timeUs, false, false);
|
||||
return index < eventTimesUs.length ? index : -1;
|
||||
}
|
||||
|
||||
|
|
@ -55,17 +48,17 @@ public final class TtmlSubtitle implements Subtitle {
|
|||
|
||||
@Override
|
||||
public long getEventTime(int index) {
|
||||
return eventTimesUs[index] + startTimeUs;
|
||||
return eventTimesUs[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastEventTime() {
|
||||
return (eventTimesUs.length == 0 ? -1 : eventTimesUs[eventTimesUs.length - 1]) + startTimeUs;
|
||||
return (eventTimesUs.length == 0 ? -1 : eventTimesUs[eventTimesUs.length - 1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cue> getCues(long timeUs) {
|
||||
CharSequence cueText = root.getText(timeUs - startTimeUs);
|
||||
CharSequence cueText = root.getText(timeUs);
|
||||
if (cueText == null) {
|
||||
return Collections.<Cue>emptyList();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@ import java.io.InputStream;
|
|||
public final class Tx3gParser implements SubtitleParser {
|
||||
|
||||
@Override
|
||||
public Subtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
|
||||
throws IOException {
|
||||
public Subtitle parse(InputStream inputStream, String inputEncoding) throws IOException {
|
||||
DataInputStream dataInputStream = new DataInputStream(inputStream);
|
||||
String cueText = dataInputStream.readUTF();
|
||||
return new Tx3gSubtitle(startTimeUs, new Cue(cueText));
|
||||
return new Tx3gSubtitle(new Cue(cueText));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -27,22 +27,15 @@ import java.util.List;
|
|||
*/
|
||||
/* package */ final class Tx3gSubtitle implements Subtitle {
|
||||
|
||||
private final long startTimeUs;
|
||||
private final List<Cue> cues;
|
||||
|
||||
public Tx3gSubtitle(long startTimeUs, Cue cue) {
|
||||
this.startTimeUs = startTimeUs;
|
||||
public Tx3gSubtitle(Cue cue) {
|
||||
this.cues = Collections.singletonList(cue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return startTimeUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextEventTimeIndex(long timeUs) {
|
||||
return timeUs < startTimeUs ? 0 : -1;
|
||||
return timeUs < 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -53,17 +46,17 @@ import java.util.List;
|
|||
@Override
|
||||
public long getEventTime(int index) {
|
||||
Assertions.checkArgument(index == 0);
|
||||
return startTimeUs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastEventTime() {
|
||||
return startTimeUs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cue> getCues(long timeUs) {
|
||||
return timeUs >= startTimeUs ? cues : Collections.<Cue>emptyList();
|
||||
return timeUs >= 0 ? cues : Collections.<Cue>emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public final class WebvttParser implements SubtitleParser {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param strictParsing If true, {@link #parse(InputStream, String, long)} will throw a
|
||||
* @param strictParsing If true, {@link #parse(InputStream, String)} will throw a
|
||||
* {@link ParserException} if the stream contains invalid data. If false, the parser will
|
||||
* make a best effort to ignore minor errors in the stream. Note however that a
|
||||
* {@link ParserException} will still be thrown when this is not possible.
|
||||
|
|
@ -85,7 +85,7 @@ public final class WebvttParser implements SubtitleParser {
|
|||
}
|
||||
|
||||
@Override
|
||||
public final WebvttSubtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
|
||||
public final WebvttSubtitle parse(InputStream inputStream, String inputEncoding)
|
||||
throws IOException {
|
||||
ArrayList<WebvttCue> subtitles = new ArrayList<>();
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ public final class WebvttParser implements SubtitleParser {
|
|||
if (!matcher.find()) {
|
||||
throw new ParserException("Expected cue start time: " + line);
|
||||
} else {
|
||||
startTime = parseTimestampUs(matcher.group()) + startTimeUs;
|
||||
startTime = parseTimestampUs(matcher.group());
|
||||
}
|
||||
|
||||
// parse end timestamp
|
||||
|
|
@ -151,7 +151,7 @@ public final class WebvttParser implements SubtitleParser {
|
|||
throw new ParserException("Expected cue end time: " + line);
|
||||
} else {
|
||||
endTimeString = matcher.group();
|
||||
endTime = parseTimestampUs(endTimeString) + startTimeUs;
|
||||
endTime = parseTimestampUs(endTimeString);
|
||||
}
|
||||
|
||||
// parse the (optional) cue setting list
|
||||
|
|
@ -213,7 +213,7 @@ public final class WebvttParser implements SubtitleParser {
|
|||
subtitles.add(cue);
|
||||
}
|
||||
|
||||
return new WebvttSubtitle(subtitles, startTimeUs);
|
||||
return new WebvttSubtitle(subtitles);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -34,18 +34,14 @@ public final class WebvttSubtitle implements Subtitle {
|
|||
|
||||
private final List<WebvttCue> cues;
|
||||
private final int numCues;
|
||||
private final long startTimeUs;
|
||||
private final long[] cueTimesUs;
|
||||
private final long[] sortedCueTimesUs;
|
||||
|
||||
/**
|
||||
* @param cues A list of the cues in this subtitle.
|
||||
* @param startTimeUs The start time of the subtitle.
|
||||
*/
|
||||
public WebvttSubtitle(List<WebvttCue> cues, long startTimeUs) {
|
||||
public WebvttSubtitle(List<WebvttCue> cues) {
|
||||
this.cues = cues;
|
||||
this.startTimeUs = startTimeUs;
|
||||
|
||||
numCues = cues.size();
|
||||
cueTimesUs = new long[2 * numCues];
|
||||
for (int cueIndex = 0; cueIndex < numCues; cueIndex++) {
|
||||
|
|
@ -58,11 +54,6 @@ public final class WebvttSubtitle implements Subtitle {
|
|||
Arrays.sort(sortedCueTimesUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStartTime() {
|
||||
return startTimeUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextEventTimeIndex(long timeUs) {
|
||||
Assertions.checkArgument(timeUs >= 0);
|
||||
|
|
|
|||
Loading…
Reference in a new issue