Further cleanup subtitle implementations.

This commit is contained in:
Oliver Woodman 2015-06-12 17:44:01 +01:00
parent bdd1968abe
commit 02c978e16c
11 changed files with 64 additions and 51 deletions

View File

@ -94,7 +94,7 @@ public final class C {
/**
* An element of a custom ExoPlayer WebVTT header. An {@code WEBVTT_OFFSET + value} element can
* be added to a custom ExoPlayer WebVTT header to specify an offset time (in microseconds) that
* should be subtracted from the embedded MPEGTS value.
* should be added to the embedded MPEGTS value.
*
* @hide
*/

View File

@ -132,7 +132,7 @@ public final class VideoFormatSelectorUtil {
}
}
return Util.toIntArray(selectedIndexList);
return Util.toArray(selectedIndexList);
}
/**

View File

@ -165,8 +165,8 @@ public class DashChunkSource implements ChunkSource {
* note that the value sets an upper bound on the length of media that the player can buffer.
* Hence a small value may increase the probability of rebuffering and playback failures.
* @param elapsedRealtimeOffsetMs If known, an estimate of the instantaneous difference between
* server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified
* as the server's unix time minus the local elapsed time. It unknown, set to 0.
* server-side unix time and {@link SystemClock#elapsedRealtime()} in milliseconds, specified
* as the server's unix time minus the local elapsed time. It unknown, set to 0.
*/
public DashChunkSource(ManifestFetcher<MediaPresentationDescription> manifestFetcher,
int adaptationSetIndex, int[] representationIndices, DataSource dataSource,
@ -491,23 +491,23 @@ public class DashChunkSource implements ChunkSource {
DataSpec dataSpec = new DataSpec(segmentUri.getUri(), segmentUri.start, segmentUri.length,
representation.getCacheKey());
long presentationTimeOffsetUs = representation.presentationTimeOffsetUs;
long sampleOffsetUs = -1 * representation.presentationTimeOffsetUs;
if (representation.format.mimeType.equals(MimeTypes.TEXT_VTT)) {
if (representationHolder.vttHeaderOffsetUs != presentationTimeOffsetUs) {
if (representationHolder.vttHeaderOffsetUs != sampleOffsetUs) {
// Update the VTT header.
headerBuilder.setLength(0);
headerBuilder.append(C.WEBVTT_EXO_HEADER).append("=")
.append(C.WEBVTT_EXO_HEADER_OFFSET).append(presentationTimeOffsetUs)
.append(C.WEBVTT_EXO_HEADER_OFFSET).append(sampleOffsetUs)
.append("\n");
representationHolder.vttHeader = headerBuilder.toString().getBytes();
representationHolder.vttHeaderOffsetUs = presentationTimeOffsetUs;
representationHolder.vttHeaderOffsetUs = sampleOffsetUs;
}
return new SingleSampleMediaChunk(dataSource, dataSpec, Chunk.TRIGGER_INITIAL,
representation.format, startTimeUs, endTimeUs, absoluteSegmentNum, isLastSegment,
MediaFormat.createTextFormat(MimeTypes.TEXT_VTT), null, representationHolder.vttHeader);
} else {
return new ContainerMediaChunk(dataSource, dataSpec, trigger, representation.format,
startTimeUs, endTimeUs, absoluteSegmentNum, isLastSegment, 0,
startTimeUs, endTimeUs, absoluteSegmentNum, isLastSegment, sampleOffsetUs,
representationHolder.extractorWrapper, representationHolder.format, drmInitData, true);
}
}

View File

@ -19,8 +19,8 @@ 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.LongArray;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;
import android.text.Html;
import android.text.Spanned;
@ -36,8 +36,6 @@ import java.util.regex.Pattern;
/**
* A simple SubRip parser.
* <p/>
* @see <a href="https://en.wikipedia.org/wiki/SubRip">Wikipedia on SubRip</a>
*/
public final class SubripParser implements SubtitleParser {
@ -53,9 +51,9 @@ public final class SubripParser implements SubtitleParser {
@Override
public SubripSubtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
throws IOException {
throws IOException {
ArrayList<Cue> cues = new ArrayList<>();
ArrayList<Long> cueTimesUs = new ArrayList<>();
LongArray cueTimesUs = new LongArray();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, C.UTF8_NAME));
String currentLine;
@ -90,12 +88,9 @@ public final class SubripParser implements SubtitleParser {
cues.add(new Cue(text));
}
reader.close();
inputStream.close();
Cue[] cuesArray = new Cue[cues.size()];
cues.toArray(cuesArray);
long[] cueTimesUsArray = Util.toLongArray(cueTimesUs);
long[] cueTimesUsArray = cueTimesUs.toArray();
return new SubripSubtitle(startTimeUs, cuesArray, cueTimesUsArray);
}

View File

@ -35,12 +35,8 @@ public final class Tx3gParser implements SubtitleParser {
public Subtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
throws IOException {
DataInputStream dataInputStream = new DataInputStream(inputStream);
try {
String cueText = dataInputStream.readUTF();
return new Tx3gSubtitle(startTimeUs, new Cue(cueText));
} finally {
dataInputStream.close();
}
String cueText = dataInputStream.readUTF();
return new Tx3gSubtitle(startTimeUs, new Cue(cueText));
}
@Override

View File

@ -59,7 +59,7 @@ public class WebvttParser implements SubtitleParser {
private static final Pattern WEBVTT_CUE_SETTING = Pattern.compile(WEBVTT_CUE_SETTING_STRING);
private static final Pattern MEDIA_TIMESTAMP_OFFSET =
Pattern.compile(C.WEBVTT_EXO_HEADER_OFFSET + "\\d+");
Pattern.compile(C.WEBVTT_EXO_HEADER_OFFSET + "\\-?\\d+");
private static final Pattern MEDIA_TIMESTAMP = Pattern.compile("MPEGTS:\\d+");
private static final String NON_NUMERIC_STRING = ".*[^0-9].*";
@ -135,7 +135,7 @@ public class WebvttParser implements SubtitleParser {
throw new ParserException("X-TIMESTAMP-MAP doesn't contain media timestamp: " + line);
} else {
mediaTimestampUs = (Long.parseLong(timestampMatcher.group().substring(7)) * 1000)
/ SAMPLING_RATE - mediaTimestampOffsetUs;
/ SAMPLING_RATE + mediaTimestampOffsetUs;
}
mediaTimestampUs = getAdjustedStartTime(mediaTimestampUs);
}
@ -237,10 +237,7 @@ public class WebvttParser implements SubtitleParser {
subtitles.add(cue);
}
webvttData.close();
inputStream.close();
WebvttSubtitle subtitle = new WebvttSubtitle(subtitles, mediaTimestampUs);
return subtitle;
return new WebvttSubtitle(subtitles, mediaTimestampUs);
}
@Override

View File

@ -20,7 +20,7 @@ import java.util.Arrays;
/**
* An append-only, auto-growing {@code long[]}.
*/
public class LongArray {
public final class LongArray {
private static final int DEFAULT_INITIAL_CAPACITY = 32;
@ -74,4 +74,13 @@ public class LongArray {
return size;
}
/**
* Copies the current values into a newly allocated primitive array.
*
* @return The primitive array containing the copied values.
*/
public long[] toArray() {
return Arrays.copyOf(values, size);
}
}

View File

@ -459,7 +459,7 @@ public final class Util {
* @param list A list of integers.
* @return The list in array form, or null if the input list was null.
*/
public static int[] toIntArray(List<Integer> list) {
public static int[] toArray(List<Integer> list) {
if (list == null) {
return null;
}
@ -471,24 +471,6 @@ public final class Util {
return intArray;
}
/**
* Converts a list of longs to a primitive array.
*
* @param list A list of longs.
* @return The list in array form, or null if the input list was null.
*/
public static long[] toLongArray(List<Long> list) {
if (list == null) {
return null;
}
int length = list.size();
long[] longArray = new long[length];
for (int i = 0; i < length; i++) {
longArray[i] = list.get(i);
}
return longArray;
}
/**
* On platform API levels 19 and 20, okhttp's implementation of {@link InputStream#close} can
* block for a long time if the stream has a lot of data remaining. Call this method before

View File

@ -0,0 +1,9 @@
EXO-HEADER=OFFSET:-5000000
WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
00:00.000 --> 00:01.234
This is the first subtitle.
00:02.345 --> 00:03.456
This is the second subtitle.

View File

@ -25,7 +25,7 @@ import java.io.InputStream;
/**
* Unit test for {@link SubripParser}.
*/
public class SubripParserTest extends InstrumentationTestCase {
public final class SubripParserTest extends InstrumentationTestCase {
private static final String TYPICAL_SUBRIP_FILE = "subrip/typical";
private static final String EMPTY_SUBRIP_FILE = "subrip/empty";

View File

@ -30,6 +30,7 @@ public class WebvttParserTest extends InstrumentationTestCase {
private static final String TYPICAL_WEBVTT_FILE = "webvtt/typical";
private static final String TYPICAL_WITH_IDS_WEBVTT_FILE = "webvtt/typical_with_identifiers";
private static final String TYPICAL_WITH_TAGS_WEBVTT_FILE = "webvtt/typical_with_tags";
private static final String LIVE_TYPICAL_WEBVTT_FILE = "webvtt/live_typical";
private static final String EMPTY_WEBVTT_FILE = "webvtt/empty";
public void testParseNullWebvttFile() throws IOException {
@ -131,4 +132,28 @@ public class WebvttParserTest extends InstrumentationTestCase {
assertEquals(startTimeUs + 7000000, subtitle.getEventTime(7));
}
public void testParseLiveTypicalWebvttFile() throws IOException {
WebvttParser parser = new WebvttParser();
InputStream inputStream =
getInstrumentation().getContext().getResources().getAssets().open(LIVE_TYPICAL_WEBVTT_FILE);
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
// test start time and event count
long startTimeUs = 0;
assertEquals(startTimeUs, subtitle.getStartTime());
assertEquals(4, subtitle.getEventTimeCount());
// test first cue
assertEquals(startTimeUs, subtitle.getEventTime(0));
assertEquals("This is the first subtitle.",
subtitle.getCues(subtitle.getEventTime(0)).get(0).text.toString());
assertEquals(startTimeUs + 1234000, subtitle.getEventTime(1));
// test second cue
assertEquals(startTimeUs + 2345000, subtitle.getEventTime(2));
assertEquals("This is the second subtitle.",
subtitle.getCues(subtitle.getEventTime(2)).get(0).text.toString());
assertEquals(startTimeUs + 3456000, subtitle.getEventTime(3));
}
}