mirror of
https://github.com/samsonjs/media.git
synced 2026-04-07 11:35:46 +00:00
Remove custom VTT logic.
This commit is contained in:
parent
dbaeecc4da
commit
02c7525ff7
10 changed files with 32 additions and 131 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
WEBVTT
|
||||
X-TIMESTAMP-MAP=LOCAL:00:00.000,MPEGTS:450000
|
||||
|
||||
1
|
||||
00:00.000 --> 00:01.234
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 '%'");
|
||||
|
|
|
|||
Loading…
Reference in a new issue