mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Implement seeking via a single code path.
When a seek is performed, renderers currently perform the actions that they need to take in two places: Some changes are performed in seekTo implementations. Other changes are performed when discontinuities are read from the source. In HLS we need to perform what is effectively a seek originating in the source. To support this, this CL allows discontinuities read from the source to modify the playback position. All actions that renderers perform as a result of a seek are moved to be performed when a discontinuity is received. Best way to understand CL: - Look at SampleSource interface change and then at the concrete implementations, to make sure they've been changed properly. - Look at SampleSourceTrackRenderer change. - Look at concrete renderers. The general pattern is that code previously performed in seekTo and READ_DISCONTINUITY is merged into onDiscontinuity(). Note: This will be further untangled in V2. Issue #676 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=112720746
This commit is contained in:
parent
3f0244e214
commit
d804446b34
@ -145,19 +145,11 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
super.onEnabled(track, positionUs, joining);
|
|
||||||
seekToInternal(positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
|
||||||
if (outputStreamEnded) {
|
if (outputStreamEnded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sourceIsReady = continueBufferingSource(positionUs);
|
|
||||||
checkForDiscontinuity(positionUs);
|
|
||||||
|
|
||||||
// Try and read a format if we don't have one already.
|
// Try and read a format if we don't have one already.
|
||||||
if (format == null && !readFormat(positionUs)) {
|
if (format == null && !readFormat(positionUs)) {
|
||||||
@ -275,14 +267,10 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder, false);
|
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder);
|
||||||
if (result == SampleSource.NOTHING_READ) {
|
if (result == SampleSource.NOTHING_READ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
|
||||||
flushDecoder();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (result == SampleSource.FORMAT_READ) {
|
if (result == SampleSource.FORMAT_READ) {
|
||||||
format = formatHolder.format;
|
format = formatHolder.format;
|
||||||
return true;
|
return true;
|
||||||
@ -304,16 +292,6 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForDiscontinuity(long positionUs) {
|
|
||||||
if (decoder == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int result = readSource(positionUs, formatHolder, null, true);
|
|
||||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
|
||||||
flushDecoder();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void flushDecoder() {
|
private void flushDecoder() {
|
||||||
inputBuffer = null;
|
inputBuffer = null;
|
||||||
outputBuffer = null;
|
outputBuffer = null;
|
||||||
@ -344,18 +322,16 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected void onDiscontinuity(long positionUs) {
|
||||||
super.seekTo(positionUs);
|
|
||||||
seekToInternal(positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal(long positionUs) {
|
|
||||||
audioTrack.reset();
|
audioTrack.reset();
|
||||||
currentPositionUs = positionUs;
|
currentPositionUs = positionUs;
|
||||||
allowPositionDiscontinuity = true;
|
allowPositionDiscontinuity = true;
|
||||||
inputStreamEnded = false;
|
inputStreamEnded = false;
|
||||||
outputStreamEnded = false;
|
outputStreamEnded = false;
|
||||||
sourceIsReady = false;
|
sourceIsReady = false;
|
||||||
|
if (decoder != null) {
|
||||||
|
flushDecoder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -387,7 +363,7 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean readFormat(long positionUs) {
|
private boolean readFormat(long positionUs) {
|
||||||
int result = readSource(positionUs, formatHolder, null, false);
|
int result = readSource(positionUs, formatHolder, null);
|
||||||
if (result == SampleSource.FORMAT_READ) {
|
if (result == SampleSource.FORMAT_READ) {
|
||||||
format = formatHolder.format;
|
format = formatHolder.format;
|
||||||
audioTrack.configure(format.getFrameworkMediaFormatV16(), false);
|
audioTrack.configure(format.getFrameworkMediaFormatV16(), false);
|
||||||
|
@ -175,12 +175,11 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
|
throws ExoPlaybackException {
|
||||||
if (outputStreamEnded) {
|
if (outputStreamEnded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sourceIsReady = continueBufferingSource(positionUs);
|
|
||||||
checkForDiscontinuity(positionUs);
|
|
||||||
|
|
||||||
// Try and read a format if we don't have one already.
|
// Try and read a format if we don't have one already.
|
||||||
if (format == null && !readFormat(positionUs)) {
|
if (format == null && !readFormat(positionUs)) {
|
||||||
@ -311,15 +310,10 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder,
|
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder);
|
||||||
false);
|
|
||||||
if (result == SampleSource.NOTHING_READ) {
|
if (result == SampleSource.NOTHING_READ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
|
||||||
flushDecoder();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (result == SampleSource.FORMAT_READ) {
|
if (result == SampleSource.FORMAT_READ) {
|
||||||
format = formatHolder.format;
|
format = formatHolder.format;
|
||||||
return true;
|
return true;
|
||||||
@ -339,16 +333,6 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForDiscontinuity(long positionUs) {
|
|
||||||
if (decoder == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int result = readSource(positionUs, formatHolder, null, true);
|
|
||||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
|
||||||
flushDecoder();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void flushDecoder() {
|
private void flushDecoder() {
|
||||||
inputBuffer = null;
|
inputBuffer = null;
|
||||||
if (outputBuffer != null) {
|
if (outputBuffer != null) {
|
||||||
@ -369,23 +353,14 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected void onDiscontinuity(long positionUs) {
|
||||||
super.seekTo(positionUs);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
|
||||||
throws ExoPlaybackException {
|
|
||||||
super.onEnabled(track, positionUs, joining);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal() {
|
|
||||||
sourceIsReady = false;
|
sourceIsReady = false;
|
||||||
inputStreamEnded = false;
|
inputStreamEnded = false;
|
||||||
outputStreamEnded = false;
|
outputStreamEnded = false;
|
||||||
renderedFirstFrame = false;
|
renderedFirstFrame = false;
|
||||||
|
if (decoder != null) {
|
||||||
|
flushDecoder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -416,7 +391,7 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean readFormat(long positionUs) {
|
private boolean readFormat(long positionUs) {
|
||||||
int result = readSource(positionUs, formatHolder, null, false);
|
int result = readSource(positionUs, formatHolder, null);
|
||||||
if (result == SampleSource.FORMAT_READ) {
|
if (result == SampleSource.FORMAT_READ) {
|
||||||
format = formatHolder.format;
|
format = formatHolder.format;
|
||||||
return true;
|
return true;
|
||||||
|
@ -80,7 +80,8 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||||||
private int[] trackStates;
|
private int[] trackStates;
|
||||||
private boolean[] pendingDiscontinuities;
|
private boolean[] pendingDiscontinuities;
|
||||||
|
|
||||||
private long seekPositionUs;
|
private long lastSeekPositionUs;
|
||||||
|
private long pendingSeekPositionUs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new sample extractor reading from the specified {@code uri}.
|
* Instantiates a new sample extractor reading from the specified {@code uri}.
|
||||||
@ -184,16 +185,21 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readDiscontinuity(int track) {
|
||||||
|
if (pendingDiscontinuities[track]) {
|
||||||
|
pendingDiscontinuities[track] = false;
|
||||||
|
return lastSeekPositionUs;
|
||||||
|
}
|
||||||
|
return NO_DISCONTINUITY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
||||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
SampleHolder sampleHolder) {
|
||||||
Assertions.checkState(prepared);
|
Assertions.checkState(prepared);
|
||||||
Assertions.checkState(trackStates[track] != TRACK_STATE_DISABLED);
|
Assertions.checkState(trackStates[track] != TRACK_STATE_DISABLED);
|
||||||
if (pendingDiscontinuities[track]) {
|
if (pendingDiscontinuities[track]) {
|
||||||
pendingDiscontinuities[track] = false;
|
|
||||||
return DISCONTINUITY_READ;
|
|
||||||
}
|
|
||||||
if (onlyReadDiscontinuity) {
|
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
if (trackStates[track] != TRACK_STATE_FORMAT_SENT) {
|
if (trackStates[track] != TRACK_STATE_FORMAT_SENT) {
|
||||||
@ -216,7 +222,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||||||
if (sampleHolder.isEncrypted()) {
|
if (sampleHolder.isEncrypted()) {
|
||||||
sampleHolder.cryptoInfo.setFromExtractorV16(extractor);
|
sampleHolder.cryptoInfo.setFromExtractorV16(extractor);
|
||||||
}
|
}
|
||||||
seekPositionUs = C.UNKNOWN_TIME_US;
|
pendingSeekPositionUs = C.UNKNOWN_TIME_US;
|
||||||
extractor.advance();
|
extractor.advance();
|
||||||
return SAMPLE_READ;
|
return SAMPLE_READ;
|
||||||
} else {
|
} else {
|
||||||
@ -285,8 +291,9 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||||||
private void seekToUsInternal(long positionUs, boolean force) {
|
private void seekToUsInternal(long positionUs, boolean force) {
|
||||||
// Unless forced, avoid duplicate calls to the underlying extractor's seek method in the case
|
// Unless forced, avoid duplicate calls to the underlying extractor's seek method in the case
|
||||||
// that there have been no interleaving calls to readSample.
|
// that there have been no interleaving calls to readSample.
|
||||||
if (force || seekPositionUs != positionUs) {
|
if (force || pendingSeekPositionUs != positionUs) {
|
||||||
seekPositionUs = positionUs;
|
lastSeekPositionUs = positionUs;
|
||||||
|
pendingSeekPositionUs = positionUs;
|
||||||
extractor.seekTo(positionUs, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
|
extractor.seekTo(positionUs, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
|
||||||
for (int i = 0; i < trackStates.length; ++i) {
|
for (int i = 0; i < trackStates.length; ++i) {
|
||||||
if (trackStates[i] != TRACK_STATE_DISABLED) {
|
if (trackStates[i] != TRACK_STATE_DISABLED) {
|
||||||
|
@ -239,13 +239,6 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
|
||||||
throws ExoPlaybackException {
|
|
||||||
super.onEnabled(track, positionUs, joining);
|
|
||||||
seekToInternal(positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onOutputFormatChanged(android.media.MediaFormat outputFormat) {
|
protected void onOutputFormatChanged(android.media.MediaFormat outputFormat) {
|
||||||
boolean passthrough = passthroughMediaFormat != null;
|
boolean passthrough = passthroughMediaFormat != null;
|
||||||
@ -312,13 +305,8 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
|
||||||
super.seekTo(positionUs);
|
super.onDiscontinuity(positionUs);
|
||||||
seekToInternal(positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal(long positionUs) {
|
|
||||||
// TODO: Try and re-use the same AudioTrack instance once [Internal: b/7941810] is fixed.
|
|
||||||
audioTrack.reset();
|
audioTrack.reset();
|
||||||
currentPositionUs = positionUs;
|
currentPositionUs = positionUs;
|
||||||
allowPositionDiscontinuity = true;
|
allowPositionDiscontinuity = true;
|
||||||
@ -376,7 +364,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
|||||||
|
|
||||||
// If we are out of sync, allow currentPositionUs to jump backwards.
|
// If we are out of sync, allow currentPositionUs to jump backwards.
|
||||||
if ((handleBufferResult & AudioTrack.RESULT_POSITION_DISCONTINUITY) != 0) {
|
if ((handleBufferResult & AudioTrack.RESULT_POSITION_DISCONTINUITY) != 0) {
|
||||||
handleDiscontinuity();
|
handleAudioTrackDiscontinuity();
|
||||||
allowPositionDiscontinuity = true;
|
allowPositionDiscontinuity = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +383,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
|||||||
audioTrack.handleEndOfStream();
|
audioTrack.handleEndOfStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleDiscontinuity() {
|
protected void handleAudioTrackDiscontinuity() {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,13 +262,6 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
codecReinitializationState = REINITIALIZATION_STATE_NONE;
|
codecReinitializationState = REINITIALIZATION_STATE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
|
||||||
throws ExoPlaybackException {
|
|
||||||
super.onEnabled(track, positionUs, joining);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException {
|
protected final boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException {
|
||||||
return handlesTrack(mediaCodecSelector, mediaFormat);
|
return handlesTrack(mediaCodecSelector, mediaFormat);
|
||||||
@ -458,15 +451,13 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
|
||||||
super.seekTo(positionUs);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal() {
|
|
||||||
sourceState = SOURCE_STATE_NOT_READY;
|
sourceState = SOURCE_STATE_NOT_READY;
|
||||||
inputStreamEnded = false;
|
inputStreamEnded = false;
|
||||||
outputStreamEnded = false;
|
outputStreamEnded = false;
|
||||||
|
if (codec != null) {
|
||||||
|
flushCodec();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -480,11 +471,11 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
sourceState = continueBufferingSource(positionUs)
|
throws ExoPlaybackException {
|
||||||
|
sourceState = sourceIsReady
|
||||||
? (sourceState == SOURCE_STATE_NOT_READY ? SOURCE_STATE_READY : sourceState)
|
? (sourceState == SOURCE_STATE_NOT_READY ? SOURCE_STATE_READY : sourceState)
|
||||||
: SOURCE_STATE_NOT_READY;
|
: SOURCE_STATE_NOT_READY;
|
||||||
checkForDiscontinuity(positionUs);
|
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
readFormat(positionUs);
|
readFormat(positionUs);
|
||||||
}
|
}
|
||||||
@ -501,22 +492,12 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readFormat(long positionUs) throws ExoPlaybackException {
|
private void readFormat(long positionUs) throws ExoPlaybackException {
|
||||||
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
int result = readSource(positionUs, formatHolder, null);
|
||||||
if (result == SampleSource.FORMAT_READ) {
|
if (result == SampleSource.FORMAT_READ) {
|
||||||
onInputFormatChanged(formatHolder);
|
onInputFormatChanged(formatHolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForDiscontinuity(long positionUs) throws ExoPlaybackException {
|
|
||||||
if (codec == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int result = readSource(positionUs, formatHolder, sampleHolder, true);
|
|
||||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
|
||||||
flushCodec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void flushCodec() throws ExoPlaybackException {
|
private void flushCodec() throws ExoPlaybackException {
|
||||||
codecHotswapTimeMs = -1;
|
codecHotswapTimeMs = -1;
|
||||||
inputIndex = -1;
|
inputIndex = -1;
|
||||||
@ -598,7 +579,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
}
|
}
|
||||||
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
|
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
|
||||||
}
|
}
|
||||||
result = readSource(positionUs, formatHolder, sampleHolder, false);
|
result = readSource(positionUs, formatHolder, sampleHolder);
|
||||||
if (firstFeed && sourceState == SOURCE_STATE_READY && result == SampleSource.NOTHING_READ) {
|
if (firstFeed && sourceState == SOURCE_STATE_READY && result == SampleSource.NOTHING_READ) {
|
||||||
sourceState = SOURCE_STATE_READY_READ_MAY_FAIL;
|
sourceState = SOURCE_STATE_READY_READ_MAY_FAIL;
|
||||||
}
|
}
|
||||||
@ -607,10 +588,6 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
|||||||
if (result == SampleSource.NOTHING_READ) {
|
if (result == SampleSource.NOTHING_READ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (result == SampleSource.DISCONTINUITY_READ) {
|
|
||||||
flushCodec();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (result == SampleSource.FORMAT_READ) {
|
if (result == SampleSource.FORMAT_READ) {
|
||||||
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
|
||||||
// We received two formats in a row. Clear the current buffer of any reconfiguration data
|
// We received two formats in a row. Clear the current buffer of any reconfiguration data
|
||||||
|
@ -227,8 +227,6 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
|||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
protected void onEnabled(int track, long positionUs, boolean joining)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
super.onEnabled(track, positionUs, joining);
|
super.onEnabled(track, positionUs, joining);
|
||||||
renderedFirstFrame = false;
|
|
||||||
consecutiveDroppedFrameCount = 0;
|
|
||||||
if (joining && allowedJoiningTimeUs > 0) {
|
if (joining && allowedJoiningTimeUs > 0) {
|
||||||
joiningDeadlineUs = SystemClock.elapsedRealtime() * 1000L + allowedJoiningTimeUs;
|
joiningDeadlineUs = SystemClock.elapsedRealtime() * 1000L + allowedJoiningTimeUs;
|
||||||
}
|
}
|
||||||
@ -236,8 +234,8 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
|
||||||
super.seekTo(positionUs);
|
super.onDiscontinuity(positionUs);
|
||||||
renderedFirstFrame = false;
|
renderedFirstFrame = false;
|
||||||
consecutiveDroppedFrameCount = 0;
|
consecutiveDroppedFrameCount = 0;
|
||||||
joiningDeadlineUs = -1;
|
joiningDeadlineUs = -1;
|
||||||
|
@ -46,9 +46,9 @@ public interface SampleSource {
|
|||||||
*/
|
*/
|
||||||
public static final int FORMAT_READ = -4;
|
public static final int FORMAT_READ = -4;
|
||||||
/**
|
/**
|
||||||
* A discontinuity in the sample stream.
|
* Returned from {@link SampleSourceReader#readDiscontinuity(int)} to indicate no discontinuity.
|
||||||
*/
|
*/
|
||||||
public static final int DISCONTINUITY_READ = -5;
|
public static final long NO_DISCONTINUITY = Long.MIN_VALUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A consumer of samples should call this method to register themselves and gain access to the
|
* A consumer of samples should call this method to register themselves and gain access to the
|
||||||
@ -104,7 +104,7 @@ public interface SampleSource {
|
|||||||
* (i.e. @link {@link MediaFormat#adaptive} is true). Hence the track formats returned through
|
* (i.e. @link {@link MediaFormat#adaptive} is true). Hence the track formats returned through
|
||||||
* this method should not be used to configure decoders. Decoder configuration should be
|
* this method should not be used to configure decoders. Decoder configuration should be
|
||||||
* performed using the formats obtained when reading the media stream through calls to
|
* performed using the formats obtained when reading the media stream through calls to
|
||||||
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
* {@link #readData(int, long, MediaFormatHolder, SampleHolder)}.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should only be called after the source has been prepared.
|
* This method should only be called after the source has been prepared.
|
||||||
*
|
*
|
||||||
@ -115,7 +115,7 @@ public interface SampleSource {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable the specified track. This allows the track's format and samples to be read from
|
* Enable the specified track. This allows the track's format and samples to be read from
|
||||||
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
* {@link #readData(int, long, MediaFormatHolder, SampleHolder)}.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should only be called after the source has been prepared, and when the specified
|
* This method should only be called after the source has been prepared, and when the specified
|
||||||
* track is disabled.
|
* track is disabled.
|
||||||
@ -138,13 +138,27 @@ public interface SampleSource {
|
|||||||
public boolean continueBuffering(int track, long positionUs);
|
public boolean continueBuffering(int track, long positionUs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to read either a sample, a new format or or a discontinuity from the source.
|
* Attempts to read a pending discontinuity from the source.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the specified track is enabled.
|
||||||
|
*
|
||||||
|
* @param track The track from which to read.
|
||||||
|
* @return If a discontinuity was read then the playback position after the discontinuity. Else
|
||||||
|
* {@link #NO_DISCONTINUITY}.
|
||||||
|
*/
|
||||||
|
public long readDiscontinuity(int track);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to read a sample or a new format from the source.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should only be called when the specified track is enabled.
|
* This method should only be called when the specified track is enabled.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that where multiple tracks are enabled, {@link #NOTHING_READ} may be returned if the
|
* Note that where multiple tracks are enabled, {@link #NOTHING_READ} may be returned if the
|
||||||
* next piece of data to be read from the {@link SampleSource} corresponds to a different track
|
* next piece of data to be read from the {@link SampleSource} corresponds to a different track
|
||||||
* than the one for which data was requested.
|
* than the one for which data was requested.
|
||||||
|
* <p>
|
||||||
|
* This method will always return {@link #NOTHING_READ} in the case that there's a pending
|
||||||
|
* discontinuity to be read from {@link #readDiscontinuity(int)} for the specified track.
|
||||||
*
|
*
|
||||||
* @param track The track from which to read.
|
* @param track The track from which to read.
|
||||||
* @param positionUs The current playback position.
|
* @param positionUs The current playback position.
|
||||||
@ -153,13 +167,11 @@ public interface SampleSource {
|
|||||||
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample.
|
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample.
|
||||||
* If the caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
* If the caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
||||||
* references a valid output buffer.
|
* references a valid output buffer.
|
||||||
* @param onlyReadDiscontinuity Whether to only read a discontinuity. If true, only
|
|
||||||
* {@link #DISCONTINUITY_READ} or {@link #NOTHING_READ} can be returned.
|
|
||||||
* @return The result, which can be {@link #SAMPLE_READ}, {@link #FORMAT_READ},
|
* @return The result, which can be {@link #SAMPLE_READ}, {@link #FORMAT_READ},
|
||||||
* {@link #DISCONTINUITY_READ}, {@link #NOTHING_READ} or {@link #END_OF_STREAM}.
|
* {@link #NOTHING_READ} or {@link #END_OF_STREAM}.
|
||||||
*/
|
*/
|
||||||
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
||||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity);
|
SampleHolder sampleHolder);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seeks to the specified time in microseconds.
|
* Seeks to the specified time in microseconds.
|
||||||
|
@ -48,7 +48,7 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean doPrepare(long positionUs) throws ExoPlaybackException {
|
protected final boolean doPrepare(long positionUs) throws ExoPlaybackException {
|
||||||
boolean allSourcesPrepared = true;
|
boolean allSourcesPrepared = true;
|
||||||
for (int i = 0; i < sources.length; i++) {
|
for (int i = 0; i < sources.length; i++) {
|
||||||
allSourcesPrepared &= sources[i].prepare(positionUs);
|
allSourcesPrepared &= sources[i].prepare(positionUs);
|
||||||
@ -103,26 +103,30 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether this renderer is capable of handling the provided track.
|
|
||||||
*
|
|
||||||
* @param mediaFormat The format of the track.
|
|
||||||
* @return True if the renderer can handle the track, false otherwise.
|
|
||||||
* @throws DecoderQueryException Thrown if there was an error querying decoders.
|
|
||||||
*/
|
|
||||||
protected abstract boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
protected void onEnabled(int track, long positionUs, boolean joining)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
|
positionUs = shiftInputPosition(positionUs);
|
||||||
enabledSource = sources[handledSourceIndices[track]];
|
enabledSource = sources[handledSourceIndices[track]];
|
||||||
enabledSourceTrackIndex = handledSourceTrackIndices[track];
|
enabledSourceTrackIndex = handledSourceTrackIndices[track];
|
||||||
enabledSource.enable(enabledSourceTrackIndex, positionUs);
|
enabledSource.enable(enabledSourceTrackIndex, positionUs);
|
||||||
|
onDiscontinuity(positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected final void seekTo(long positionUs) throws ExoPlaybackException {
|
||||||
|
positionUs = shiftInputPosition(positionUs);
|
||||||
enabledSource.seekToUs(positionUs);
|
enabledSource.seekToUs(positionUs);
|
||||||
|
checkForDiscontinuity(positionUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void doSomeWork(long positionUs, long elapsedRealtimeUs)
|
||||||
|
throws ExoPlaybackException {
|
||||||
|
positionUs = shiftInputPosition(positionUs);
|
||||||
|
boolean sourceIsReady = enabledSource.continueBuffering(enabledSourceTrackIndex, positionUs);
|
||||||
|
positionUs = checkForDiscontinuity(positionUs);
|
||||||
|
doSomeWork(positionUs, elapsedRealtimeUs, sourceIsReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -147,14 +151,6 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maybeThrowError(SampleSourceReader source) throws ExoPlaybackException {
|
|
||||||
try {
|
|
||||||
source.maybeThrowError();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new ExoPlaybackException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDisabled() throws ExoPlaybackException {
|
protected void onDisabled() throws ExoPlaybackException {
|
||||||
enabledSource.disable(enabledSourceTrackIndex);
|
enabledSource.disable(enabledSourceTrackIndex);
|
||||||
@ -169,16 +165,6 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final boolean continueBufferingSource(long positionUs) {
|
|
||||||
return enabledSource.continueBuffering(enabledSourceTrackIndex, positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final int readSource(long positionUs, MediaFormatHolder formatHolder,
|
|
||||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
|
||||||
return enabledSource.readData(enabledSourceTrackIndex, positionUs, formatHolder, sampleHolder,
|
|
||||||
onlyReadDiscontinuity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected final int getTrackCount() {
|
protected final int getTrackCount() {
|
||||||
return handledSourceTrackIndices.length;
|
return handledSourceTrackIndices.length;
|
||||||
@ -190,4 +176,92 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
|
|||||||
return source.getFormat(handledSourceTrackIndices[track]);
|
return source.getFormat(handledSourceTrackIndices[track]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shifts positions passed to {@link #onEnabled(int, long, boolean)}, {@link #seekTo(long)} and
|
||||||
|
* {@link #doSomeWork(long, long)}.
|
||||||
|
* <p>
|
||||||
|
* The default implementation does not modify the position. Except in very specific cases,
|
||||||
|
* subclasses should not override this method.
|
||||||
|
*
|
||||||
|
* @param positionUs The position in microseconds.
|
||||||
|
* @return The adjusted position in microseconds.
|
||||||
|
*/
|
||||||
|
protected long shiftInputPosition(long positionUs) {
|
||||||
|
return positionUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods to be called by subclasses.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads from the enabled upstream source.
|
||||||
|
*
|
||||||
|
* @param positionUs The current playback position.
|
||||||
|
* @param formatHolder A {@link MediaFormatHolder} object to populate in the case of a new format.
|
||||||
|
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample.
|
||||||
|
* If the caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
||||||
|
* references a valid output buffer.
|
||||||
|
* @return The result, which can be {@link SampleSource#SAMPLE_READ},
|
||||||
|
* {@link SampleSource#FORMAT_READ}, {@link SampleSource#NOTHING_READ} or
|
||||||
|
* {@link SampleSource#END_OF_STREAM}.
|
||||||
|
*/
|
||||||
|
protected final int readSource(long positionUs, MediaFormatHolder formatHolder,
|
||||||
|
SampleHolder sampleHolder) {
|
||||||
|
return enabledSource.readData(enabledSourceTrackIndex, positionUs, formatHolder, sampleHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abstract methods.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this renderer is capable of handling the provided track.
|
||||||
|
*
|
||||||
|
* @param mediaFormat The format of the track.
|
||||||
|
* @return True if the renderer can handle the track, false otherwise.
|
||||||
|
* @throws DecoderQueryException Thrown if there was an error querying decoders.
|
||||||
|
*/
|
||||||
|
protected abstract boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when a discontinuity is encountered. Also invoked when the renderer is enabled, for
|
||||||
|
* convenience.
|
||||||
|
*
|
||||||
|
* @param positionUs The playback position after the discontinuity, or the position at which
|
||||||
|
* the renderer is being enabled.
|
||||||
|
* @throws ExoPlaybackException If an error occurs handling the discontinuity.
|
||||||
|
*/
|
||||||
|
protected abstract void onDiscontinuity(long positionUs) throws ExoPlaybackException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by {@link #doSomeWork(long, long)}.
|
||||||
|
*
|
||||||
|
* @param positionUs The current media time in microseconds, measured at the start of the
|
||||||
|
* current iteration of the rendering loop.
|
||||||
|
* @param elapsedRealtimeUs {@link android.os.SystemClock#elapsedRealtime()} in microseconds,
|
||||||
|
* measured at the start of the current iteration of the rendering loop.
|
||||||
|
* @param sourceIsReady The result of the most recent call to
|
||||||
|
* {@link SampleSourceReader#continueBuffering(int, long)}.
|
||||||
|
* @throws ExoPlaybackException If an error occurs.
|
||||||
|
* @throws ExoPlaybackException
|
||||||
|
*/
|
||||||
|
protected abstract void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
|
throws ExoPlaybackException;
|
||||||
|
|
||||||
|
// Private methods.
|
||||||
|
|
||||||
|
private long checkForDiscontinuity(long positionUs) throws ExoPlaybackException {
|
||||||
|
long discontinuityPositionUs = enabledSource.readDiscontinuity(enabledSourceTrackIndex);
|
||||||
|
if (discontinuityPositionUs != SampleSource.NO_DISCONTINUITY) {
|
||||||
|
onDiscontinuity(discontinuityPositionUs);
|
||||||
|
return discontinuityPositionUs;
|
||||||
|
}
|
||||||
|
return positionUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void maybeThrowError(SampleSourceReader source) throws ExoPlaybackException {
|
||||||
|
try {
|
||||||
|
source.maybeThrowError();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ExoPlaybackException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -119,12 +119,15 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readDiscontinuity(int track) {
|
||||||
|
return NO_DISCONTINUITY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
||||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
SampleHolder sampleHolder) {
|
||||||
if (onlyReadDiscontinuity) {
|
if (state == STATE_END_OF_STREAM) {
|
||||||
return NOTHING_READ;
|
|
||||||
} else if (state == STATE_END_OF_STREAM) {
|
|
||||||
return END_OF_STREAM;
|
return END_OF_STREAM;
|
||||||
} else if (state == STATE_SEND_FORMAT) {
|
} else if (state == STATE_SEND_FORMAT) {
|
||||||
formatHolder.format = format;
|
formatHolder.format = format;
|
||||||
|
@ -222,22 +222,22 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
|||||||
return loadingFinished || !sampleQueue.isEmpty();
|
return loadingFinished || !sampleQueue.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readDiscontinuity(int track) {
|
||||||
|
if (pendingDiscontinuity) {
|
||||||
|
pendingDiscontinuity = false;
|
||||||
|
return lastSeekPositionUs;
|
||||||
|
}
|
||||||
|
return NO_DISCONTINUITY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
||||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
SampleHolder sampleHolder) {
|
||||||
Assertions.checkState(state == STATE_ENABLED);
|
Assertions.checkState(state == STATE_ENABLED);
|
||||||
downstreamPositionUs = positionUs;
|
downstreamPositionUs = positionUs;
|
||||||
|
|
||||||
if (pendingDiscontinuity) {
|
if (pendingDiscontinuity || isPendingReset()) {
|
||||||
pendingDiscontinuity = false;
|
|
||||||
return DISCONTINUITY_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onlyReadDiscontinuity) {
|
|
||||||
return NOTHING_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPendingReset()) {
|
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,16 +384,20 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
|
public long readDiscontinuity(int track) {
|
||||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
|
||||||
downstreamPositionUs = playbackPositionUs;
|
|
||||||
|
|
||||||
if (pendingDiscontinuities[track]) {
|
if (pendingDiscontinuities[track]) {
|
||||||
pendingDiscontinuities[track] = false;
|
pendingDiscontinuities[track] = false;
|
||||||
return DISCONTINUITY_READ;
|
return lastSeekPositionUs;
|
||||||
}
|
}
|
||||||
|
return NO_DISCONTINUITY;
|
||||||
|
}
|
||||||
|
|
||||||
if (onlyReadDiscontinuity || isPendingReset()) {
|
@Override
|
||||||
|
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
|
||||||
|
SampleHolder sampleHolder) {
|
||||||
|
downstreamPositionUs = playbackPositionUs;
|
||||||
|
|
||||||
|
if (pendingDiscontinuities[track] || isPendingReset()) {
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,22 +281,22 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long readDiscontinuity(int track) {
|
||||||
|
if (pendingDiscontinuities[track]) {
|
||||||
|
pendingDiscontinuities[track] = false;
|
||||||
|
return lastSeekPositionUs;
|
||||||
|
}
|
||||||
|
return NO_DISCONTINUITY;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
|
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
|
||||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
SampleHolder sampleHolder) {
|
||||||
Assertions.checkState(prepared);
|
Assertions.checkState(prepared);
|
||||||
downstreamPositionUs = playbackPositionUs;
|
downstreamPositionUs = playbackPositionUs;
|
||||||
|
|
||||||
if (pendingDiscontinuities[track]) {
|
if (pendingDiscontinuities[track] || isPendingReset()) {
|
||||||
pendingDiscontinuities[track] = false;
|
|
||||||
return DISCONTINUITY_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (onlyReadDiscontinuity) {
|
|
||||||
return NOTHING_READ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPendingReset()) {
|
|
||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,29 +93,17 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
protected void onDiscontinuity(long positionUs) {
|
||||||
throws ExoPlaybackException {
|
|
||||||
super.onEnabled(track, positionUs, joining);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
|
||||||
super.seekTo(positionUs);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal() {
|
|
||||||
pendingMetadata = null;
|
pendingMetadata = null;
|
||||||
inputStreamEnded = false;
|
inputStreamEnded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
continueBufferingSource(positionUs);
|
throws ExoPlaybackException {
|
||||||
if (!inputStreamEnded && pendingMetadata == null) {
|
if (!inputStreamEnded && pendingMetadata == null) {
|
||||||
sampleHolder.clearData();
|
sampleHolder.clearData();
|
||||||
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
int result = readSource(positionUs, formatHolder, sampleHolder);
|
||||||
if (result == SampleSource.SAMPLE_READ) {
|
if (result == SampleSource.SAMPLE_READ) {
|
||||||
pendingMetadataTimestamp = sampleHolder.timeUs;
|
pendingMetadataTimestamp = sampleHolder.timeUs;
|
||||||
try {
|
try {
|
||||||
|
@ -185,26 +185,22 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
|||||||
parserThread = new HandlerThread("textParser");
|
parserThread = new HandlerThread("textParser");
|
||||||
parserThread.start();
|
parserThread.start();
|
||||||
parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]);
|
parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]);
|
||||||
seekToInternal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected void onDiscontinuity(long positionUs) {
|
||||||
super.seekTo(positionUs);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal() {
|
|
||||||
inputStreamEnded = false;
|
inputStreamEnded = false;
|
||||||
subtitle = null;
|
subtitle = null;
|
||||||
nextSubtitle = null;
|
nextSubtitle = null;
|
||||||
parserHelper.flush();
|
|
||||||
clearTextRenderer();
|
clearTextRenderer();
|
||||||
|
if (parserHelper != null) {
|
||||||
|
parserHelper.flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
continueBufferingSource(positionUs);
|
throws ExoPlaybackException {
|
||||||
if (nextSubtitle == null) {
|
if (nextSubtitle == null) {
|
||||||
try {
|
try {
|
||||||
nextSubtitle = parserHelper.getAndClearResult();
|
nextSubtitle = parserHelper.getAndClearResult();
|
||||||
@ -247,7 +243,7 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
|
|||||||
// Try and read the next subtitle from the source.
|
// Try and read the next subtitle from the source.
|
||||||
SampleHolder sampleHolder = parserHelper.getSampleHolder();
|
SampleHolder sampleHolder = parserHelper.getSampleHolder();
|
||||||
sampleHolder.clearData();
|
sampleHolder.clearData();
|
||||||
int result = readSource(positionUs, formatHolder, sampleHolder, false);
|
int result = readSource(positionUs, formatHolder, sampleHolder);
|
||||||
if (result == SampleSource.FORMAT_READ) {
|
if (result == SampleSource.FORMAT_READ) {
|
||||||
parserHelper.setFormat(formatHolder.format);
|
parserHelper.setFormat(formatHolder.format);
|
||||||
} else if (result == SampleSource.SAMPLE_READ) {
|
} else if (result == SampleSource.SAMPLE_READ) {
|
||||||
|
@ -97,16 +97,10 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
protected void onEnabled(int track, long positionUs, boolean joining)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
super.onEnabled(track, positionUs, joining);
|
super.onEnabled(track, positionUs, joining);
|
||||||
seekToInternal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void seekTo(long positionUs) throws ExoPlaybackException {
|
protected void onDiscontinuity(long positionUs) {
|
||||||
super.seekTo(positionUs);
|
|
||||||
seekToInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal() {
|
|
||||||
inputStreamEnded = false;
|
inputStreamEnded = false;
|
||||||
pendingCaptionLists.clear();
|
pendingCaptionLists.clear();
|
||||||
clearPendingSample();
|
clearPendingSample();
|
||||||
@ -116,15 +110,15 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
|
||||||
continueBufferingSource(positionUs);
|
throws ExoPlaybackException {
|
||||||
if (isSamplePending()) {
|
if (isSamplePending()) {
|
||||||
maybeParsePendingSample(positionUs);
|
maybeParsePendingSample(positionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = inputStreamEnded ? SampleSource.END_OF_STREAM : SampleSource.SAMPLE_READ;
|
int result = inputStreamEnded ? SampleSource.END_OF_STREAM : SampleSource.SAMPLE_READ;
|
||||||
while (!isSamplePending() && result == SampleSource.SAMPLE_READ) {
|
while (!isSamplePending() && result == SampleSource.SAMPLE_READ) {
|
||||||
result = readSource(positionUs, formatHolder, sampleHolder, false);
|
result = readSource(positionUs, formatHolder, sampleHolder);
|
||||||
if (result == SampleSource.SAMPLE_READ) {
|
if (result == SampleSource.SAMPLE_READ) {
|
||||||
maybeParsePendingSample(positionUs);
|
maybeParsePendingSample(positionUs);
|
||||||
} else if (result == SampleSource.END_OF_STREAM) {
|
} else if (result == SampleSource.END_OF_STREAM) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user