mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
commit
5abb413f4e
3 changed files with 51 additions and 30 deletions
|
|
@ -673,7 +673,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
||||||
@Override
|
@Override
|
||||||
protected boolean isReady() {
|
protected boolean isReady() {
|
||||||
return format != null && !waitingForKeys
|
return format != null && !waitingForKeys
|
||||||
&& sourceState != SOURCE_STATE_NOT_READY || outputIndex >= 0 || isWithinHotswapPeriod();
|
&& (sourceState != SOURCE_STATE_NOT_READY || outputIndex >= 0 || isWithinHotswapPeriod());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,8 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
|
|
||||||
private static final int NO_RESET_PENDING = -1;
|
private static final int NO_RESET_PENDING = -1;
|
||||||
|
|
||||||
|
private static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 1;
|
||||||
|
|
||||||
private final int eventSourceId;
|
private final int eventSourceId;
|
||||||
private final LoadControl loadControl;
|
private final LoadControl loadControl;
|
||||||
private final ChunkSource chunkSource;
|
private final ChunkSource chunkSource;
|
||||||
|
|
@ -150,6 +152,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
private final boolean frameAccurateSeeking;
|
private final boolean frameAccurateSeeking;
|
||||||
private final Handler eventHandler;
|
private final Handler eventHandler;
|
||||||
private final EventListener eventListener;
|
private final EventListener eventListener;
|
||||||
|
private final int minLoadableRetryCount;
|
||||||
|
|
||||||
private int state;
|
private int state;
|
||||||
private long downstreamPositionUs;
|
private long downstreamPositionUs;
|
||||||
|
|
@ -175,6 +178,13 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
public ChunkSampleSource(ChunkSource chunkSource, LoadControl loadControl,
|
public ChunkSampleSource(ChunkSource chunkSource, LoadControl loadControl,
|
||||||
int bufferSizeContribution, boolean frameAccurateSeeking, Handler eventHandler,
|
int bufferSizeContribution, boolean frameAccurateSeeking, Handler eventHandler,
|
||||||
EventListener eventListener, int eventSourceId) {
|
EventListener eventListener, int eventSourceId) {
|
||||||
|
this(chunkSource, loadControl, bufferSizeContribution, frameAccurateSeeking, eventHandler,
|
||||||
|
eventListener, eventSourceId, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkSampleSource(ChunkSource chunkSource, LoadControl loadControl,
|
||||||
|
int bufferSizeContribution, boolean frameAccurateSeeking, Handler eventHandler,
|
||||||
|
EventListener eventListener, int eventSourceId, int minLoadableRetryCount) {
|
||||||
this.chunkSource = chunkSource;
|
this.chunkSource = chunkSource;
|
||||||
this.loadControl = loadControl;
|
this.loadControl = loadControl;
|
||||||
this.bufferSizeContribution = bufferSizeContribution;
|
this.bufferSizeContribution = bufferSizeContribution;
|
||||||
|
|
@ -182,6 +192,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
this.eventSourceId = eventSourceId;
|
this.eventSourceId = eventSourceId;
|
||||||
|
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||||
currentLoadableHolder = new ChunkOperationHolder();
|
currentLoadableHolder = new ChunkOperationHolder();
|
||||||
mediaChunks = new LinkedList<MediaChunk>();
|
mediaChunks = new LinkedList<MediaChunk>();
|
||||||
readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks);
|
readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks);
|
||||||
|
|
@ -287,9 +298,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
|
|
||||||
downstreamPositionUs = positionUs;
|
downstreamPositionUs = positionUs;
|
||||||
if (isPendingReset()) {
|
if (isPendingReset()) {
|
||||||
if (currentLoadableException != null) {
|
maybeThrowLoadableException();
|
||||||
throw currentLoadableException;
|
|
||||||
}
|
|
||||||
IOException chunkSourceException = chunkSource.getError();
|
IOException chunkSourceException = chunkSource.getError();
|
||||||
if (chunkSourceException != null) {
|
if (chunkSourceException != null) {
|
||||||
throw chunkSourceException;
|
throw chunkSourceException;
|
||||||
|
|
@ -342,9 +351,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
onSampleRead(mediaChunk, sampleHolder);
|
onSampleRead(mediaChunk, sampleHolder);
|
||||||
return SAMPLE_READ;
|
return SAMPLE_READ;
|
||||||
} else {
|
} else {
|
||||||
if (currentLoadableException != null) {
|
maybeThrowLoadableException();
|
||||||
throw currentLoadableException;
|
|
||||||
}
|
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -369,6 +376,12 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeThrowLoadableException() throws IOException {
|
||||||
|
if (currentLoadableException != null && currentLoadableExceptionCount > minLoadableRetryCount) {
|
||||||
|
throw currentLoadableException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private MediaChunk getMediaChunk(long positionUs) {
|
private MediaChunk getMediaChunk(long positionUs) {
|
||||||
Iterator<MediaChunk> mediaChunkIterator = mediaChunks.iterator();
|
Iterator<MediaChunk> mediaChunkIterator = mediaChunks.iterator();
|
||||||
while (mediaChunkIterator.hasNext()) {
|
while (mediaChunkIterator.hasNext()) {
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,13 @@ public class WebvttParser implements SubtitleParser {
|
||||||
|
|
||||||
private static final long SAMPLING_RATE = 90;
|
private static final long SAMPLING_RATE = 90;
|
||||||
|
|
||||||
|
private static final String WEBVTT_METADATA_HEADER_STRING = "\\S*[:=]\\S*";
|
||||||
|
private static final Pattern WEBVTT_METADATA_HEADER =
|
||||||
|
Pattern.compile(WEBVTT_METADATA_HEADER_STRING);
|
||||||
|
|
||||||
private static final String WEBVTT_TIMESTAMP_STRING = "(\\d+:)?[0-5]\\d:[0-5]\\d\\.\\d{3}";
|
private static final String WEBVTT_TIMESTAMP_STRING = "(\\d+:)?[0-5]\\d:[0-5]\\d\\.\\d{3}";
|
||||||
private static final Pattern WEBVTT_TIMESTAMP = Pattern.compile(WEBVTT_TIMESTAMP_STRING);
|
private static final Pattern WEBVTT_TIMESTAMP = Pattern.compile(WEBVTT_TIMESTAMP_STRING);
|
||||||
|
|
||||||
private static final Pattern MEDIA_TIMESTAMP_OFFSET = Pattern.compile(OFFSET + "\\d+");
|
private static final Pattern MEDIA_TIMESTAMP_OFFSET = Pattern.compile(OFFSET + "\\d+");
|
||||||
private static final Pattern MEDIA_TIMESTAMP = Pattern.compile("MPEGTS:\\d+");
|
private static final Pattern MEDIA_TIMESTAMP = Pattern.compile("MPEGTS:\\d+");
|
||||||
|
|
||||||
|
|
@ -90,30 +95,33 @@ public class WebvttParser implements SubtitleParser {
|
||||||
throw new ParserException("Expected WEBVTT. Got " + line);
|
throw new ParserException("Expected WEBVTT. Got " + line);
|
||||||
}
|
}
|
||||||
|
|
||||||
// after "WEBVTT" there should be either an empty line or an "X-TIMESTAMP-MAP" line and then
|
// parse the remainder of the header
|
||||||
// and empty line
|
while (true) {
|
||||||
line = webvttData.readLine();
|
|
||||||
if (!line.isEmpty()) {
|
|
||||||
if (!line.startsWith("X-TIMESTAMP-MAP")) {
|
|
||||||
throw new ParserException("Expected an empty line or X-TIMESTAMP-MAP. Got " + line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the media timestamp
|
|
||||||
Matcher matcher = MEDIA_TIMESTAMP.matcher(line);
|
|
||||||
if (!matcher.find()) {
|
|
||||||
throw new ParserException("X-TIMESTAMP-MAP doesn't contain media timestmap: " + line);
|
|
||||||
} else {
|
|
||||||
mediaTimestampUs = (Long.parseLong(matcher.group().substring(7)) * 1000) / SAMPLING_RATE
|
|
||||||
- mediaTimestampOffsetUs;
|
|
||||||
}
|
|
||||||
mediaTimestampUs = getAdjustedStartTime(mediaTimestampUs);
|
|
||||||
|
|
||||||
// read in the next line (which should be an empty line)
|
|
||||||
line = webvttData.readLine();
|
line = webvttData.readLine();
|
||||||
}
|
if (line == null) {
|
||||||
if (!line.isEmpty()) {
|
// we reached EOF before finishing the header
|
||||||
throw new ParserException("Expected an empty line after WEBVTT or X-TIMESTAMP-MAP. Got "
|
throw new ParserException("Expected an empty line after webvtt header");
|
||||||
+ line);
|
} else if (line.isEmpty()) {
|
||||||
|
// we've read the newline that separates the header from the body
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = WEBVTT_METADATA_HEADER.matcher(line);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
throw new ParserException("Expected webvtt metadata header; got: " + 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;
|
||||||
|
}
|
||||||
|
mediaTimestampUs = getAdjustedStartTime(mediaTimestampUs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process the cues and text
|
// process the cues and text
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue