Remove custom VTT logic.

This commit is contained in:
Oliver Woodman 2015-08-11 18:16:56 +01:00
parent dbaeecc4da
commit 02c7525ff7
10 changed files with 32 additions and 131 deletions

View file

@ -1,6 +1,4 @@
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.

View file

@ -1,5 +1,4 @@
WEBVTT # This comment is allowed
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
00:00.000 --> 00:01.234
This is the first subtitle.

View file

@ -1,5 +1,4 @@
WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
1
00:00.000 --> 00:01.234

View file

@ -1,5 +1,4 @@
WEBVTT
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
00:00.000 --> 00:01.234
This is the <i>first</i> subtitle.

View file

@ -53,21 +53,20 @@ public class WebvttParserTest extends InstrumentationTestCase {
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
// test start time and event count
long startTimeUs = 5000000;
assertEquals(startTimeUs, subtitle.getStartTime());
assertEquals(0, subtitle.getStartTime());
assertEquals(4, subtitle.getEventTimeCount());
// test first cue
assertEquals(startTimeUs, subtitle.getEventTime(0));
assertEquals(0, subtitle.getEventTime(0));
assertEquals("This is the first subtitle.",
subtitle.getCues(subtitle.getEventTime(0)).get(0).text.toString());
assertEquals(startTimeUs + 1234000, subtitle.getEventTime(1));
assertEquals(1234000, subtitle.getEventTime(1));
// test second cue
assertEquals(startTimeUs + 2345000, subtitle.getEventTime(2));
assertEquals(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));
assertEquals(3456000, subtitle.getEventTime(3));
}
public void testParseTypicalWithIdsWebvttFile() throws IOException {
@ -78,21 +77,20 @@ public class WebvttParserTest extends InstrumentationTestCase {
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
// test start time and event count
long startTimeUs = 5000000;
assertEquals(startTimeUs, subtitle.getStartTime());
assertEquals(0, subtitle.getStartTime());
assertEquals(4, subtitle.getEventTimeCount());
// test first cue
assertEquals(startTimeUs, subtitle.getEventTime(0));
assertEquals(0, subtitle.getEventTime(0));
assertEquals("This is the first subtitle.",
subtitle.getCues(subtitle.getEventTime(0)).get(0).text.toString());
assertEquals(startTimeUs + 1234000, subtitle.getEventTime(1));
assertEquals(1234000, subtitle.getEventTime(1));
// test second cue
assertEquals(startTimeUs + 2345000, subtitle.getEventTime(2));
assertEquals(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));
assertEquals(3456000, subtitle.getEventTime(3));
}
public void testParseTypicalWithTagsWebvttFile() throws IOException {
@ -103,33 +101,32 @@ public class WebvttParserTest extends InstrumentationTestCase {
WebvttSubtitle subtitle = parser.parse(inputStream, C.UTF8_NAME, 0);
// test start time and event count
long startTimeUs = 5000000;
assertEquals(startTimeUs, subtitle.getStartTime());
assertEquals(0, subtitle.getStartTime());
assertEquals(8, subtitle.getEventTimeCount());
// test first cue
assertEquals(startTimeUs, subtitle.getEventTime(0));
assertEquals(0, subtitle.getEventTime(0));
assertEquals("This is the first subtitle.",
subtitle.getCues(subtitle.getEventTime(0)).get(0).text.toString());
assertEquals(startTimeUs + 1234000, subtitle.getEventTime(1));
assertEquals(1234000, subtitle.getEventTime(1));
// test second cue
assertEquals(startTimeUs + 2345000, subtitle.getEventTime(2));
assertEquals(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));
assertEquals(3456000, subtitle.getEventTime(3));
// test third cue
assertEquals(startTimeUs + 4000000, subtitle.getEventTime(4));
assertEquals(4000000, subtitle.getEventTime(4));
assertEquals("This is the third subtitle.",
subtitle.getCues(subtitle.getEventTime(4)).get(0).text.toString());
assertEquals(startTimeUs + 5000000, subtitle.getEventTime(5));
assertEquals(5000000, subtitle.getEventTime(5));
// test fourth cue
assertEquals(startTimeUs + 6000000, subtitle.getEventTime(6));
assertEquals(6000000, subtitle.getEventTime(6));
assertEquals("This is the <fourth> &subtitle.",
subtitle.getCues(subtitle.getEventTime(6)).get(0).text.toString());
assertEquals(startTimeUs + 7000000, subtitle.getEventTime(7));
assertEquals(7000000, subtitle.getEventTime(7));
}
public void testParseLiveTypicalWebvttFile() throws IOException {

View file

@ -90,18 +90,6 @@ public final class C {
*/
public static final int RESULT_END_OF_INPUT = -1;
/**
* A prefix for custom ExoPlayer WebVTT headers.
*/
public static final String WEBVTT_EXO_HEADER = "EXO-HEADER";
/**
* 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 added to the embedded MPEGTS value.
*/
public static final String WEBVTT_EXO_HEADER_OFFSET = "OFFSET:";
private C() {}
}

View file

@ -109,7 +109,7 @@ public final class SingleSampleChunkSource implements ChunkSource {
private SingleSampleMediaChunk initChunk() {
return new SingleSampleMediaChunk(dataSource, dataSpec, Chunk.TRIGGER_UNSPECIFIED, format, 0,
durationUs, 0, true, mediaFormat, null, null);
durationUs, 0, true, mediaFormat, null);
}
}

View file

@ -20,7 +20,6 @@ import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.drm.DrmInitData;
import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSpec;
import com.google.android.exoplayer.util.ParsableByteArray;
import com.google.android.exoplayer.util.Util;
import java.io.IOException;
@ -32,9 +31,6 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
private final MediaFormat sampleFormat;
private final DrmInitData sampleDrmInitData;
private final byte[] headerData;
private boolean writtenHeader;
private volatile int bytesLoaded;
private volatile boolean loadCanceled;
@ -51,18 +47,14 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
* @param sampleFormat The format of the sample.
* @param sampleDrmInitData The {@link DrmInitData} for the sample. Null if the sample is not drm
* protected.
* @param headerData Custom header data for the sample. May be null. If set, the header data is
* prepended to the sample data. It is not reflected in the values returned by
* {@link #bytesLoaded()}.
*/
public SingleSampleMediaChunk(DataSource dataSource, DataSpec dataSpec, int trigger,
Format format, long startTimeUs, long endTimeUs, int chunkIndex, boolean isLastChunk,
MediaFormat sampleFormat, DrmInitData sampleDrmInitData, byte[] headerData) {
MediaFormat sampleFormat, DrmInitData sampleDrmInitData) {
super(dataSource, dataSpec, trigger, format, startTimeUs, endTimeUs, chunkIndex, isLastChunk,
true);
this.sampleFormat = sampleFormat;
this.sampleDrmInitData = sampleDrmInitData;
this.headerData = headerData;
}
@Override
@ -95,13 +87,6 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
@SuppressWarnings("NonAtomicVolatileUpdate")
@Override
public void load() throws IOException, InterruptedException {
if (!writtenHeader) {
if (headerData != null) {
getOutput().sampleData(new ParsableByteArray(headerData), headerData.length);
}
writtenHeader = true;
}
DataSpec loadDataSpec = Util.getRemainderDataSpec(dataSpec, bytesLoaded);
try {
// Create and open the input.
@ -113,9 +98,6 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
result = getOutput().sampleData(dataSource, Integer.MAX_VALUE, true);
}
int sampleSize = bytesLoaded;
if (headerData != null) {
sampleSize += headerData.length;
}
getOutput().sampleMetadata(startTimeUs, C.SAMPLE_FLAG_SYNC, sampleSize, 0, null);
} finally {
dataSource.close();

View file

@ -16,7 +16,6 @@
package com.google.android.exoplayer.dash;
import com.google.android.exoplayer.BehindLiveWindowException;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TimeRange;
import com.google.android.exoplayer.TrackInfo;
@ -104,7 +103,6 @@ public class DashChunkSource implements ChunkSource {
private final FormatEvaluator formatEvaluator;
private final Evaluation evaluation;
private final Clock systemClock;
private final StringBuilder headerBuilder;
private final long liveEdgeLatencyUs;
private final long elapsedRealtimeOffsetUs;
private final int maxWidth;
@ -258,7 +256,6 @@ public class DashChunkSource implements ChunkSource {
this.eventHandler = eventHandler;
this.eventListener = eventListener;
this.evaluation = new Evaluation();
this.headerBuilder = new StringBuilder();
this.seekRangeValues = new long[2];
drmInitData = getDrmInitData(currentManifest, adaptationSetIndex);
@ -645,19 +642,9 @@ public class DashChunkSource implements ChunkSource {
long sampleOffsetUs = representation.periodStartMs * 1000
- representation.presentationTimeOffsetUs;
if (representation.format.mimeType.equals(MimeTypes.TEXT_VTT)) {
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(sampleOffsetUs)
.append("\n");
representationHolder.vttHeader = headerBuilder.toString().getBytes();
representationHolder.vttHeaderOffsetUs = sampleOffsetUs;
}
return new SingleSampleMediaChunk(dataSource, dataSpec, Chunk.TRIGGER_INITIAL,
representation.format, startTimeUs, endTimeUs, absoluteSegmentNum, isLastSegment,
MediaFormat.createTextFormat(MimeTypes.TEXT_VTT, representation.format.language), null,
representationHolder.vttHeader);
MediaFormat.createTextFormat(MimeTypes.TEXT_VTT, representation.format.language), null);
} else {
return new ContainerMediaChunk(dataSource, dataSpec, trigger, representation.format,
startTimeUs, endTimeUs, absoluteSegmentNum, isLastSegment, sampleOffsetUs,
@ -741,8 +728,6 @@ public class DashChunkSource implements ChunkSource {
public MediaFormat format;
public int segmentNumShift;
public long vttHeaderOffsetUs;
public byte[] vttHeader;
public RepresentationHolder(Representation representation,
ChunkExtractorWrapper extractorWrapper) {

View file

@ -38,12 +38,10 @@ import java.util.regex.Pattern;
* <p>
* @see <a href="http://dev.w3.org/html5/webvtt">WebVTT specification</a>
*/
public class WebvttParser implements SubtitleParser {
public final class WebvttParser implements SubtitleParser {
private static final String TAG = "WebvttParser";
private static final long SAMPLING_RATE = 90;
private static final String WEBVTT_FILE_HEADER_STRING = "^\uFEFF?WEBVTT((\\u0020|\u0009).*)?$";
private static final Pattern WEBVTT_FILE_HEADER =
Pattern.compile(WEBVTT_FILE_HEADER_STRING);
@ -62,10 +60,6 @@ public class WebvttParser implements SubtitleParser {
private static final String WEBVTT_CUE_SETTING_STRING = "\\S*:\\S*";
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+");
private static final Pattern MEDIA_TIMESTAMP = Pattern.compile("MPEGTS:\\d+");
private static final String NON_NUMERIC_STRING = ".*[^0-9].*";
private final StringBuilder textBuilder;
@ -94,33 +88,13 @@ public class WebvttParser implements SubtitleParser {
public final WebvttSubtitle parse(InputStream inputStream, String inputEncoding, long startTimeUs)
throws IOException {
ArrayList<WebvttCue> subtitles = new ArrayList<>();
long mediaTimestampUs = startTimeUs;
long mediaTimestampOffsetUs = 0;
BufferedReader webvttData = new BufferedReader(new InputStreamReader(inputStream, C.UTF8_NAME));
String line;
// file should start with "WEBVTT" on the first line or "EXO-HEADER"
// file should start with "WEBVTT"
line = webvttData.readLine();
if (line == null) {
throw new ParserException("Expected WEBVTT or EXO-HEADER. Got null");
}
if (line.startsWith(C.WEBVTT_EXO_HEADER)) {
// parse the timestamp offset, if present
Matcher matcher = MEDIA_TIMESTAMP_OFFSET.matcher(line);
if (matcher.find()) {
mediaTimestampOffsetUs = Long.parseLong(matcher.group().substring(7));
}
// read the next line, which should now be WEBVTT
line = webvttData.readLine();
if (line == null) {
throw new ParserException("Expected WEBVTT. Got null");
}
}
if (!WEBVTT_FILE_HEADER.matcher(line).matches()) {
if (line == null || !WEBVTT_FILE_HEADER.matcher(line).matches()) {
throw new ParserException("Expected WEBVTT. Got " + line);
}
@ -135,21 +109,11 @@ public class WebvttParser implements SubtitleParser {
break;
}
Matcher matcher = WEBVTT_METADATA_HEADER.matcher(line);
if (!matcher.find()) {
handleNoncompliantLine(line);
}
if (line.startsWith("X-TIMESTAMP-MAP")) {
// parse the media timestamp
Matcher timestampMatcher = MEDIA_TIMESTAMP.matcher(line);
if (!timestampMatcher.find()) {
throw new ParserException("X-TIMESTAMP-MAP doesn't contain media timestamp: " + line);
} else {
mediaTimestampUs = (Long.parseLong(timestampMatcher.group().substring(7)) * 1000)
/ SAMPLING_RATE + mediaTimestampOffsetUs;
if (strictParsing) {
Matcher matcher = WEBVTT_METADATA_HEADER.matcher(line);
if (!matcher.find()) {
throw new ParserException("Unexpected line: " + line);
}
mediaTimestampUs = getAdjustedStartTime(mediaTimestampUs);
}
}
@ -178,7 +142,7 @@ public class WebvttParser implements SubtitleParser {
if (!matcher.find()) {
throw new ParserException("Expected cue start time: " + line);
} else {
startTime = parseTimestampUs(matcher.group()) + mediaTimestampUs;
startTime = parseTimestampUs(matcher.group()) + startTimeUs;
}
// parse end timestamp
@ -187,7 +151,7 @@ public class WebvttParser implements SubtitleParser {
throw new ParserException("Expected cue end time: " + line);
} else {
endTimeString = matcher.group();
endTime = parseTimestampUs(endTimeString) + mediaTimestampUs;
endTime = parseTimestampUs(endTimeString) + startTimeUs;
}
// parse the (optional) cue setting list
@ -249,7 +213,7 @@ public class WebvttParser implements SubtitleParser {
subtitles.add(cue);
}
return new WebvttSubtitle(subtitles, mediaTimestampUs);
return new WebvttSubtitle(subtitles, startTimeUs);
}
@Override
@ -257,16 +221,6 @@ public class WebvttParser implements SubtitleParser {
return MimeTypes.TEXT_VTT.equals(mimeType);
}
protected long getAdjustedStartTime(long startTimeUs) {
return startTimeUs;
}
protected void handleNoncompliantLine(String line) throws ParserException {
if (strictParsing) {
throw new ParserException("Unexpected line: " + line);
}
}
private static int parseIntPercentage(String s) throws NumberFormatException {
if (!s.endsWith("%")) {
throw new NumberFormatException(s + " doesn't end with '%'");