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:
olly 2016-01-21 13:58:01 -08:00 committed by Oliver Woodman
parent 3f0244e214
commit d804446b34
15 changed files with 224 additions and 232 deletions

View File

@ -145,19 +145,11 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
}
@Override
protected void onEnabled(int track, long positionUs, boolean joining)
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
throws ExoPlaybackException {
super.onEnabled(track, positionUs, joining);
seekToInternal(positionUs);
}
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
if (outputStreamEnded) {
return;
}
sourceIsReady = continueBufferingSource(positionUs);
checkForDiscontinuity(positionUs);
// Try and read a format if we don't have one already.
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) {
return false;
}
if (result == SampleSource.DISCONTINUITY_READ) {
flushDecoder();
return true;
}
if (result == SampleSource.FORMAT_READ) {
format = formatHolder.format;
return true;
@ -304,16 +292,6 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
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() {
inputBuffer = null;
outputBuffer = null;
@ -344,18 +322,16 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
seekToInternal(positionUs);
}
private void seekToInternal(long positionUs) {
protected void onDiscontinuity(long positionUs) {
audioTrack.reset();
currentPositionUs = positionUs;
allowPositionDiscontinuity = true;
inputStreamEnded = false;
outputStreamEnded = false;
sourceIsReady = false;
if (decoder != null) {
flushDecoder();
}
}
@Override
@ -387,7 +363,7 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
}
private boolean readFormat(long positionUs) {
int result = readSource(positionUs, formatHolder, null, false);
int result = readSource(positionUs, formatHolder, null);
if (result == SampleSource.FORMAT_READ) {
format = formatHolder.format;
audioTrack.configure(format.getFrameworkMediaFormatV16(), false);

View File

@ -175,12 +175,11 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
}
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
throws ExoPlaybackException {
if (outputStreamEnded) {
return;
}
sourceIsReady = continueBufferingSource(positionUs);
checkForDiscontinuity(positionUs);
// Try and read a format if we don't have one already.
if (format == null && !readFormat(positionUs)) {
@ -311,15 +310,10 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
}
}
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder,
false);
int result = readSource(positionUs, formatHolder, inputBuffer.sampleHolder);
if (result == SampleSource.NOTHING_READ) {
return false;
}
if (result == SampleSource.DISCONTINUITY_READ) {
flushDecoder();
return true;
}
if (result == SampleSource.FORMAT_READ) {
format = formatHolder.format;
return true;
@ -339,16 +333,6 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
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() {
inputBuffer = null;
if (outputBuffer != null) {
@ -369,23 +353,14 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
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() {
protected void onDiscontinuity(long positionUs) {
sourceIsReady = false;
inputStreamEnded = false;
outputStreamEnded = false;
renderedFirstFrame = false;
if (decoder != null) {
flushDecoder();
}
}
@Override
@ -416,7 +391,7 @@ public final class LibvpxVideoTrackRenderer extends SampleSourceTrackRenderer {
}
private boolean readFormat(long positionUs) {
int result = readSource(positionUs, formatHolder, null, false);
int result = readSource(positionUs, formatHolder, null);
if (result == SampleSource.FORMAT_READ) {
format = formatHolder.format;
return true;

View File

@ -80,7 +80,8 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
private int[] trackStates;
private boolean[] pendingDiscontinuities;
private long seekPositionUs;
private long lastSeekPositionUs;
private long pendingSeekPositionUs;
/**
* Instantiates a new sample extractor reading from the specified {@code uri}.
@ -184,16 +185,21 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
return true;
}
@Override
public long readDiscontinuity(int track) {
if (pendingDiscontinuities[track]) {
pendingDiscontinuities[track] = false;
return lastSeekPositionUs;
}
return NO_DISCONTINUITY;
}
@Override
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
SampleHolder sampleHolder) {
Assertions.checkState(prepared);
Assertions.checkState(trackStates[track] != TRACK_STATE_DISABLED);
if (pendingDiscontinuities[track]) {
pendingDiscontinuities[track] = false;
return DISCONTINUITY_READ;
}
if (onlyReadDiscontinuity) {
return NOTHING_READ;
}
if (trackStates[track] != TRACK_STATE_FORMAT_SENT) {
@ -216,7 +222,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
if (sampleHolder.isEncrypted()) {
sampleHolder.cryptoInfo.setFromExtractorV16(extractor);
}
seekPositionUs = C.UNKNOWN_TIME_US;
pendingSeekPositionUs = C.UNKNOWN_TIME_US;
extractor.advance();
return SAMPLE_READ;
} else {
@ -285,8 +291,9 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
private void seekToUsInternal(long positionUs, boolean force) {
// Unless forced, avoid duplicate calls to the underlying extractor's seek method in the case
// that there have been no interleaving calls to readSample.
if (force || seekPositionUs != positionUs) {
seekPositionUs = positionUs;
if (force || pendingSeekPositionUs != positionUs) {
lastSeekPositionUs = positionUs;
pendingSeekPositionUs = positionUs;
extractor.seekTo(positionUs, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
for (int i = 0; i < trackStates.length; ++i) {
if (trackStates[i] != TRACK_STATE_DISABLED) {

View File

@ -239,13 +239,6 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
return this;
}
@Override
protected void onEnabled(int track, long positionUs, boolean joining)
throws ExoPlaybackException {
super.onEnabled(track, positionUs, joining);
seekToInternal(positionUs);
}
@Override
protected void onOutputFormatChanged(android.media.MediaFormat outputFormat) {
boolean passthrough = passthroughMediaFormat != null;
@ -312,13 +305,8 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
seekToInternal(positionUs);
}
private void seekToInternal(long positionUs) {
// TODO: Try and re-use the same AudioTrack instance once [Internal: b/7941810] is fixed.
protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
super.onDiscontinuity(positionUs);
audioTrack.reset();
currentPositionUs = positionUs;
allowPositionDiscontinuity = true;
@ -376,7 +364,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
// If we are out of sync, allow currentPositionUs to jump backwards.
if ((handleBufferResult & AudioTrack.RESULT_POSITION_DISCONTINUITY) != 0) {
handleDiscontinuity();
handleAudioTrackDiscontinuity();
allowPositionDiscontinuity = true;
}
@ -395,7 +383,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
audioTrack.handleEndOfStream();
}
protected void handleDiscontinuity() {
protected void handleAudioTrackDiscontinuity() {
// Do nothing
}

View File

@ -262,13 +262,6 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
codecReinitializationState = REINITIALIZATION_STATE_NONE;
}
@Override
protected void onEnabled(int track, long positionUs, boolean joining)
throws ExoPlaybackException {
super.onEnabled(track, positionUs, joining);
seekToInternal();
}
@Override
protected final boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException {
return handlesTrack(mediaCodecSelector, mediaFormat);
@ -458,15 +451,13 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
seekToInternal();
}
private void seekToInternal() {
protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
sourceState = SOURCE_STATE_NOT_READY;
inputStreamEnded = false;
outputStreamEnded = false;
if (codec != null) {
flushCodec();
}
}
@Override
@ -480,11 +471,11 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
}
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
sourceState = continueBufferingSource(positionUs)
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
throws ExoPlaybackException {
sourceState = sourceIsReady
? (sourceState == SOURCE_STATE_NOT_READY ? SOURCE_STATE_READY : sourceState)
: SOURCE_STATE_NOT_READY;
checkForDiscontinuity(positionUs);
if (format == null) {
readFormat(positionUs);
}
@ -501,22 +492,12 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
}
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) {
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 {
codecHotswapTimeMs = -1;
inputIndex = -1;
@ -598,7 +579,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
}
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) {
sourceState = SOURCE_STATE_READY_READ_MAY_FAIL;
}
@ -607,10 +588,6 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
if (result == SampleSource.NOTHING_READ) {
return false;
}
if (result == SampleSource.DISCONTINUITY_READ) {
flushCodec();
return true;
}
if (result == SampleSource.FORMAT_READ) {
if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) {
// We received two formats in a row. Clear the current buffer of any reconfiguration data

View File

@ -227,8 +227,6 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
protected void onEnabled(int track, long positionUs, boolean joining)
throws ExoPlaybackException {
super.onEnabled(track, positionUs, joining);
renderedFirstFrame = false;
consecutiveDroppedFrameCount = 0;
if (joining && allowedJoiningTimeUs > 0) {
joiningDeadlineUs = SystemClock.elapsedRealtime() * 1000L + allowedJoiningTimeUs;
}
@ -236,8 +234,8 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
super.onDiscontinuity(positionUs);
renderedFirstFrame = false;
consecutiveDroppedFrameCount = 0;
joiningDeadlineUs = -1;

View File

@ -46,9 +46,9 @@ public interface SampleSource {
*/
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
@ -104,7 +104,7 @@ public interface SampleSource {
* (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
* 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>
* 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
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
* {@link #readData(int, long, MediaFormatHolder, SampleHolder)}.
* <p>
* This method should only be called after the source has been prepared, and when the specified
* track is disabled.
@ -138,13 +138,27 @@ public interface SampleSource {
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>
* This method should only be called when the specified track is enabled.
* <p>
* 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
* 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 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.
* If the caller requires the sample data then it must ensure that {@link SampleHolder#data}
* 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},
* {@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,
SampleHolder sampleHolder, boolean onlyReadDiscontinuity);
SampleHolder sampleHolder);
/**
* Seeks to the specified time in microseconds.

View File

@ -48,7 +48,7 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
}
@Override
protected boolean doPrepare(long positionUs) throws ExoPlaybackException {
protected final boolean doPrepare(long positionUs) throws ExoPlaybackException {
boolean allSourcesPrepared = true;
for (int i = 0; i < sources.length; i++) {
allSourcesPrepared &= sources[i].prepare(positionUs);
@ -103,26 +103,30 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
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
protected void onEnabled(int track, long positionUs, boolean joining)
throws ExoPlaybackException {
positionUs = shiftInputPosition(positionUs);
enabledSource = sources[handledSourceIndices[track]];
enabledSourceTrackIndex = handledSourceTrackIndices[track];
enabledSource.enable(enabledSourceTrackIndex, positionUs);
onDiscontinuity(positionUs);
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
protected final void seekTo(long positionUs) throws ExoPlaybackException {
positionUs = shiftInputPosition(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
@ -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
protected void onDisabled() throws ExoPlaybackException {
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
protected final int getTrackCount() {
return handledSourceTrackIndices.length;
@ -190,4 +176,92 @@ public abstract class SampleSourceTrackRenderer extends TrackRenderer {
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);
}
}
}

View File

@ -119,12 +119,15 @@ public final class SingleSampleSource implements SampleSource, SampleSourceReade
}
}
@Override
public long readDiscontinuity(int track) {
return NO_DISCONTINUITY;
}
@Override
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
if (onlyReadDiscontinuity) {
return NOTHING_READ;
} else if (state == STATE_END_OF_STREAM) {
SampleHolder sampleHolder) {
if (state == STATE_END_OF_STREAM) {
return END_OF_STREAM;
} else if (state == STATE_SEND_FORMAT) {
formatHolder.format = format;

View File

@ -222,22 +222,22 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
return loadingFinished || !sampleQueue.isEmpty();
}
@Override
public long readDiscontinuity(int track) {
if (pendingDiscontinuity) {
pendingDiscontinuity = false;
return lastSeekPositionUs;
}
return NO_DISCONTINUITY;
}
@Override
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
SampleHolder sampleHolder) {
Assertions.checkState(state == STATE_ENABLED);
downstreamPositionUs = positionUs;
if (pendingDiscontinuity) {
pendingDiscontinuity = false;
return DISCONTINUITY_READ;
}
if (onlyReadDiscontinuity) {
return NOTHING_READ;
}
if (isPendingReset()) {
if (pendingDiscontinuity || isPendingReset()) {
return NOTHING_READ;
}

View File

@ -384,16 +384,20 @@ public final class ExtractorSampleSource implements SampleSource, SampleSourceRe
}
@Override
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
downstreamPositionUs = playbackPositionUs;
public long readDiscontinuity(int track) {
if (pendingDiscontinuities[track]) {
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;
}

View File

@ -281,22 +281,22 @@ public final class HlsSampleSource implements SampleSource, SampleSourceReader,
return false;
}
@Override
public long readDiscontinuity(int track) {
if (pendingDiscontinuities[track]) {
pendingDiscontinuities[track] = false;
return lastSeekPositionUs;
}
return NO_DISCONTINUITY;
}
@Override
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
SampleHolder sampleHolder) {
Assertions.checkState(prepared);
downstreamPositionUs = playbackPositionUs;
if (pendingDiscontinuities[track]) {
pendingDiscontinuities[track] = false;
return DISCONTINUITY_READ;
}
if (onlyReadDiscontinuity) {
return NOTHING_READ;
}
if (isPendingReset()) {
if (pendingDiscontinuities[track] || isPendingReset()) {
return NOTHING_READ;
}

View File

@ -93,29 +93,17 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
}
@Override
protected void onEnabled(int track, long positionUs, boolean joining)
throws ExoPlaybackException {
super.onEnabled(track, positionUs, joining);
seekToInternal();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
seekToInternal();
}
private void seekToInternal() {
protected void onDiscontinuity(long positionUs) {
pendingMetadata = null;
inputStreamEnded = false;
}
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
continueBufferingSource(positionUs);
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
throws ExoPlaybackException {
if (!inputStreamEnded && pendingMetadata == null) {
sampleHolder.clearData();
int result = readSource(positionUs, formatHolder, sampleHolder, false);
int result = readSource(positionUs, formatHolder, sampleHolder);
if (result == SampleSource.SAMPLE_READ) {
pendingMetadataTimestamp = sampleHolder.timeUs;
try {

View File

@ -185,26 +185,22 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
parserThread = new HandlerThread("textParser");
parserThread.start();
parserHelper = new SubtitleParserHelper(parserThread.getLooper(), subtitleParsers[parserIndex]);
seekToInternal();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
seekToInternal();
}
private void seekToInternal() {
protected void onDiscontinuity(long positionUs) {
inputStreamEnded = false;
subtitle = null;
nextSubtitle = null;
parserHelper.flush();
clearTextRenderer();
if (parserHelper != null) {
parserHelper.flush();
}
}
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
continueBufferingSource(positionUs);
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
throws ExoPlaybackException {
if (nextSubtitle == null) {
try {
nextSubtitle = parserHelper.getAndClearResult();
@ -247,7 +243,7 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
// Try and read the next subtitle from the source.
SampleHolder sampleHolder = parserHelper.getSampleHolder();
sampleHolder.clearData();
int result = readSource(positionUs, formatHolder, sampleHolder, false);
int result = readSource(positionUs, formatHolder, sampleHolder);
if (result == SampleSource.FORMAT_READ) {
parserHelper.setFormat(formatHolder.format);
} else if (result == SampleSource.SAMPLE_READ) {

View File

@ -97,16 +97,10 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
protected void onEnabled(int track, long positionUs, boolean joining)
throws ExoPlaybackException {
super.onEnabled(track, positionUs, joining);
seekToInternal();
}
@Override
protected void seekTo(long positionUs) throws ExoPlaybackException {
super.seekTo(positionUs);
seekToInternal();
}
private void seekToInternal() {
protected void onDiscontinuity(long positionUs) {
inputStreamEnded = false;
pendingCaptionLists.clear();
clearPendingSample();
@ -116,15 +110,15 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
}
@Override
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
continueBufferingSource(positionUs);
protected void doSomeWork(long positionUs, long elapsedRealtimeUs, boolean sourceIsReady)
throws ExoPlaybackException {
if (isSamplePending()) {
maybeParsePendingSample(positionUs);
}
int result = inputStreamEnded ? SampleSource.END_OF_STREAM : 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) {
maybeParsePendingSample(positionUs);
} else if (result == SampleSource.END_OF_STREAM) {