Commit 035fab22 by olly Committed by Oliver Woodman

Rename skipToKeyframeBefore -> skipData and allow skipping to EOS

This change also ensures that format changes are read whilst the
renderer is enabled but without a codec. This is necessary to
ensure the drm session is updated (or replaced).

Updating the format is also needed so that the up-to-date format is
used in the case that the codec is initialized later due to the
surface being set. Previously, if an ABR change occurred between
the format being read and the surface being attached, we would
instantiate the codec and then immediately have to reconfigure it
when as a result of reading the up-to-date format. For a non-adaptive
codec this resulted in the codec being immediately released and
instantiated again!

Issue: #2582

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=151608096
parent 9bc20d23
...@@ -150,7 +150,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -150,7 +150,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
joiningDeadlineMs = C.TIME_UNSET; joiningDeadlineMs = C.TIME_UNSET;
clearReportedVideoSize(); clearReportedVideoSize();
formatHolder = new FormatHolder(); formatHolder = new FormatHolder();
flagsOnlyBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
outputMode = VpxDecoder.OUTPUT_MODE_NONE; outputMode = VpxDecoder.OUTPUT_MODE_NONE;
} }
...@@ -185,6 +185,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -185,6 +185,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
} }
// We have a format.
if (isRendererAvailable()) { if (isRendererAvailable()) {
drmSession = pendingDrmSession; drmSession = pendingDrmSession;
ExoMediaCrypto mediaCrypto = null; ExoMediaCrypto mediaCrypto = null;
...@@ -222,7 +223,20 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -222,7 +223,20 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw ExoPlaybackException.createForRenderer(e, getIndex());
} }
} else { } else {
skipToKeyframeBefore(positionUs); skipSource(positionUs);
// We need to read any format changes despite not having a codec so that drmSession can be
// updated, and so that we have the most recent format should the codec be initialized. We may
// also reach the end of the stream. Note that readSource will not read a sample into a
// flags-only buffer.
flagsOnlyBuffer.clear();
int result = readSource(formatHolder, flagsOnlyBuffer, false);
if (result == C.RESULT_FORMAT_READ) {
onInputFormatChanged(formatHolder.format);
} else if (result == C.RESULT_BUFFER_READ) {
Assertions.checkState(flagsOnlyBuffer.isEndOfStream());
inputStreamEnded = true;
outputStreamEnded = true;
}
} }
decoderCounters.ensureUpdated(); decoderCounters.ensureUpdated();
} }
......
...@@ -551,7 +551,7 @@ public final class ExoPlayerTest extends TestCase { ...@@ -551,7 +551,7 @@ public final class ExoPlayerTest extends TestCase {
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
// Do nothing. // Do nothing.
} }
......
...@@ -297,21 +297,22 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { ...@@ -297,21 +297,22 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
} }
/** /**
* Returns whether the upstream source is ready. * Attempts to skip to the keyframe before the specified position, or to the end of the stream if
* {@code positionUs} is beyond it.
* *
* @return Whether the source is ready. * @param positionUs The position in microseconds.
*/ */
protected final boolean isSourceReady() { protected void skipSource(long positionUs) {
return readEndOfStream ? streamIsFinal : stream.isReady(); stream.skipData(positionUs - streamOffsetUs);
} }
/** /**
* Attempts to skip to the keyframe before the specified time. * Returns whether the upstream source is ready.
* *
* @param timeUs The specified time. * @return Whether the source is ready.
*/ */
protected void skipToKeyframeBefore(long timeUs) { protected final boolean isSourceReady() {
stream.skipToKeyframeBefore(timeUs - streamOffsetUs); return readEndOfStream ? streamIsFinal : stream.isReady();
} }
} }
...@@ -146,7 +146,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements ...@@ -146,7 +146,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
audioTrack = new AudioTrack(audioCapabilities, audioProcessors, new AudioTrackListener()); audioTrack = new AudioTrack(audioCapabilities, audioProcessors, new AudioTrackListener());
formatHolder = new FormatHolder(); formatHolder = new FormatHolder();
flagsOnlyBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
decoderReinitializationState = REINITIALIZATION_STATE_NONE; decoderReinitializationState = REINITIALIZATION_STATE_NONE;
audioTrackNeedsConfigure = true; audioTrackNeedsConfigure = true;
} }
......
...@@ -64,6 +64,15 @@ public class DecoderInputBuffer extends Buffer { ...@@ -64,6 +64,15 @@ public class DecoderInputBuffer extends Buffer {
@BufferReplacementMode private final int bufferReplacementMode; @BufferReplacementMode private final int bufferReplacementMode;
/** /**
* Creates a new instance for which {@link #isFlagsOnly()} will return true.
*
* @return A new flags only input buffer.
*/
public static DecoderInputBuffer newFlagsOnlyInstance() {
return new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED);
}
/**
* @param bufferReplacementMode Determines the behavior of {@link #ensureSpaceForWrite(int)}. One * @param bufferReplacementMode Determines the behavior of {@link #ensureSpaceForWrite(int)}. One
* of {@link #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} and * of {@link #BUFFER_REPLACEMENT_MODE_DISABLED}, {@link #BUFFER_REPLACEMENT_MODE_NORMAL} and
* {@link #BUFFER_REPLACEMENT_MODE_DIRECT}. * {@link #BUFFER_REPLACEMENT_MODE_DIRECT}.
...@@ -110,6 +119,14 @@ public class DecoderInputBuffer extends Buffer { ...@@ -110,6 +119,14 @@ public class DecoderInputBuffer extends Buffer {
} }
/** /**
* Returns whether the buffer is only able to hold flags, meaning {@link #data} is null and
* its replacement mode is {@link #BUFFER_REPLACEMENT_MODE_DISABLED}.
*/
public final boolean isFlagsOnly() {
return data == null && bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DISABLED;
}
/**
* Returns whether the {@link C#BUFFER_FLAG_ENCRYPTED} flag is set. * Returns whether the {@link C#BUFFER_FLAG_ENCRYPTED} flag is set.
*/ */
public final boolean isEncrypted() { public final boolean isEncrypted() {
......
...@@ -76,7 +76,6 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -76,7 +76,6 @@ public final class DefaultTrackOutput implements TrackOutput {
private long totalBytesWritten; private long totalBytesWritten;
private Allocation lastAllocation; private Allocation lastAllocation;
private int lastAllocationOffset; private int lastAllocationOffset;
private boolean needKeyframe;
private boolean pendingSplice; private boolean pendingSplice;
private UpstreamFormatChangedListener upstreamFormatChangeListener; private UpstreamFormatChangedListener upstreamFormatChangeListener;
...@@ -92,7 +91,6 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -92,7 +91,6 @@ public final class DefaultTrackOutput implements TrackOutput {
scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE); scratch = new ParsableByteArray(INITIAL_SCRATCH_SIZE);
state = new AtomicInteger(); state = new AtomicInteger();
lastAllocationOffset = allocationLength; lastAllocationOffset = allocationLength;
needKeyframe = true;
} }
// Called by the consuming thread, but only when there is no loading thread. // Called by the consuming thread, but only when there is no loading thread.
...@@ -228,6 +226,16 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -228,6 +226,16 @@ public final class DefaultTrackOutput implements TrackOutput {
} }
/** /**
* Skips all samples currently in the buffer.
*/
public void skipAll() {
long nextOffset = infoQueue.skipAll();
if (nextOffset != C.POSITION_UNSET) {
dropDownstreamTo(nextOffset);
}
}
/**
* Attempts to skip to the keyframe before or at the specified time. Succeeds only if the buffer * Attempts to skip to the keyframe before or at the specified time. Succeeds only if the buffer
* contains a keyframe with a timestamp of {@code timeUs} or earlier. If * contains a keyframe with a timestamp of {@code timeUs} or earlier. If
* {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs}
...@@ -523,12 +531,6 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -523,12 +531,6 @@ public final class DefaultTrackOutput implements TrackOutput {
} }
pendingSplice = false; pendingSplice = false;
} }
if (needKeyframe) {
if ((flags & C.BUFFER_FLAG_KEY_FRAME) == 0) {
return;
}
needKeyframe = false;
}
timeUs += sampleOffsetUs; timeUs += sampleOffsetUs;
long absoluteOffset = totalBytesWritten - size - offset; long absoluteOffset = totalBytesWritten - size - offset;
infoQueue.commitSample(timeUs, flags, absoluteOffset, size, encryptionKey); infoQueue.commitSample(timeUs, flags, absoluteOffset, size, encryptionKey);
...@@ -558,7 +560,6 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -558,7 +560,6 @@ public final class DefaultTrackOutput implements TrackOutput {
totalBytesWritten = 0; totalBytesWritten = 0;
lastAllocation = null; lastAllocation = null;
lastAllocationOffset = allocationLength; lastAllocationOffset = allocationLength;
needKeyframe = true;
} }
/** /**
...@@ -615,6 +616,7 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -615,6 +616,7 @@ public final class DefaultTrackOutput implements TrackOutput {
private long largestDequeuedTimestampUs; private long largestDequeuedTimestampUs;
private long largestQueuedTimestampUs; private long largestQueuedTimestampUs;
private boolean upstreamKeyframeRequired;
private boolean upstreamFormatRequired; private boolean upstreamFormatRequired;
private Format upstreamFormat; private Format upstreamFormat;
private int upstreamSourceId; private int upstreamSourceId;
...@@ -631,6 +633,7 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -631,6 +633,7 @@ public final class DefaultTrackOutput implements TrackOutput {
largestDequeuedTimestampUs = Long.MIN_VALUE; largestDequeuedTimestampUs = Long.MIN_VALUE;
largestQueuedTimestampUs = Long.MIN_VALUE; largestQueuedTimestampUs = Long.MIN_VALUE;
upstreamFormatRequired = true; upstreamFormatRequired = true;
upstreamKeyframeRequired = true;
} }
public void clearSampleData() { public void clearSampleData() {
...@@ -638,6 +641,7 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -638,6 +641,7 @@ public final class DefaultTrackOutput implements TrackOutput {
relativeReadIndex = 0; relativeReadIndex = 0;
relativeWriteIndex = 0; relativeWriteIndex = 0;
queueSize = 0; queueSize = 0;
upstreamKeyframeRequired = true;
} }
// Called by the consuming thread, but only when there is no loading thread. // Called by the consuming thread, but only when there is no loading thread.
...@@ -780,6 +784,10 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -780,6 +784,10 @@ public final class DefaultTrackOutput implements TrackOutput {
return C.RESULT_FORMAT_READ; return C.RESULT_FORMAT_READ;
} }
if (buffer.isFlagsOnly()) {
return C.RESULT_NOTHING_READ;
}
buffer.timeUs = timesUs[relativeReadIndex]; buffer.timeUs = timesUs[relativeReadIndex];
buffer.setFlags(flags[relativeReadIndex]); buffer.setFlags(flags[relativeReadIndex]);
extrasHolder.size = sizes[relativeReadIndex]; extrasHolder.size = sizes[relativeReadIndex];
...@@ -801,6 +809,24 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -801,6 +809,24 @@ public final class DefaultTrackOutput implements TrackOutput {
} }
/** /**
* Skips all samples in the buffer.
*
* @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no
* dropping of data is required.
*/
public synchronized long skipAll() {
if (queueSize == 0) {
return C.POSITION_UNSET;
}
int lastSampleIndex = (relativeReadIndex + queueSize - 1) % capacity;
relativeReadIndex = (relativeReadIndex + queueSize) % capacity;
absoluteReadIndex += queueSize;
queueSize = 0;
return offsets[lastSampleIndex] + sizes[lastSampleIndex];
}
/**
* Attempts to locate the keyframe before or at the specified time. If * Attempts to locate the keyframe before or at the specified time. If
* {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs}
* falls within the buffer. * falls within the buffer.
...@@ -842,9 +868,9 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -842,9 +868,9 @@ public final class DefaultTrackOutput implements TrackOutput {
return C.POSITION_UNSET; return C.POSITION_UNSET;
} }
queueSize -= sampleCountToKeyframe;
relativeReadIndex = (relativeReadIndex + sampleCountToKeyframe) % capacity; relativeReadIndex = (relativeReadIndex + sampleCountToKeyframe) % capacity;
absoluteReadIndex += sampleCountToKeyframe; absoluteReadIndex += sampleCountToKeyframe;
queueSize -= sampleCountToKeyframe;
return offsets[relativeReadIndex]; return offsets[relativeReadIndex];
} }
...@@ -867,6 +893,12 @@ public final class DefaultTrackOutput implements TrackOutput { ...@@ -867,6 +893,12 @@ public final class DefaultTrackOutput implements TrackOutput {
public synchronized void commitSample(long timeUs, @C.BufferFlags int sampleFlags, long offset, public synchronized void commitSample(long timeUs, @C.BufferFlags int sampleFlags, long offset,
int size, byte[] encryptionKey) { int size, byte[] encryptionKey) {
if (upstreamKeyframeRequired) {
if ((sampleFlags & C.BUFFER_FLAG_KEY_FRAME) == 0) {
return;
}
upstreamKeyframeRequired = false;
}
Assertions.checkState(!upstreamFormatRequired); Assertions.checkState(!upstreamFormatRequired);
commitSampleTimestamp(timeUs); commitSampleTimestamp(timeUs);
timesUs[relativeWriteIndex] = timeUs; timesUs[relativeWriteIndex] = timeUs;
......
...@@ -169,6 +169,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -169,6 +169,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private final DrmSessionManager<FrameworkMediaCrypto> drmSessionManager; private final DrmSessionManager<FrameworkMediaCrypto> drmSessionManager;
private final boolean playClearSamplesWithoutKeys; private final boolean playClearSamplesWithoutKeys;
private final DecoderInputBuffer buffer; private final DecoderInputBuffer buffer;
private final DecoderInputBuffer flagsOnlyBuffer;
private final FormatHolder formatHolder; private final FormatHolder formatHolder;
private final List<Long> decodeOnlyPresentationTimestamps; private final List<Long> decodeOnlyPresentationTimestamps;
private final MediaCodec.BufferInfo outputBufferInfo; private final MediaCodec.BufferInfo outputBufferInfo;
...@@ -227,6 +228,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -227,6 +228,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys; this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
formatHolder = new FormatHolder(); formatHolder = new FormatHolder();
decodeOnlyPresentationTimestamps = new ArrayList<>(); decodeOnlyPresentationTimestamps = new ArrayList<>();
outputBufferInfo = new MediaCodec.BufferInfo(); outputBufferInfo = new MediaCodec.BufferInfo();
...@@ -448,6 +450,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -448,6 +450,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReconfigurationState = RECONFIGURATION_STATE_NONE;
codecReinitializationState = REINITIALIZATION_STATE_NONE; codecReinitializationState = REINITIALIZATION_STATE_NONE;
decoderCounters.decoderReleaseCount++; decoderCounters.decoderReleaseCount++;
buffer.data = null;
try { try {
codec.stop(); codec.stop();
} finally { } finally {
...@@ -486,12 +489,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -486,12 +489,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (format == null) { if (format == null) {
// We don't have a format yet, so try and read one. // We don't have a format yet, so try and read one.
buffer.clear(); buffer.clear();
int result = readSource(formatHolder, buffer, true); int result = readSource(formatHolder, flagsOnlyBuffer, true);
if (result == C.RESULT_FORMAT_READ) { if (result == C.RESULT_FORMAT_READ) {
onInputFormatChanged(formatHolder.format); onInputFormatChanged(formatHolder.format);
} else if (result == C.RESULT_BUFFER_READ) { } else if (result == C.RESULT_BUFFER_READ) {
// End of stream read having not read a format. // End of stream read having not read a format.
Assertions.checkState(buffer.isEndOfStream()); Assertions.checkState(flagsOnlyBuffer.isEndOfStream());
inputStreamEnded = true; inputStreamEnded = true;
processEndOfStream(); processEndOfStream();
return; return;
...@@ -500,14 +503,28 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -500,14 +503,28 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return; return;
} }
} }
// We have a format.
maybeInitCodec(); maybeInitCodec();
if (codec != null) { if (codec != null) {
TraceUtil.beginSection("drainAndFeed"); TraceUtil.beginSection("drainAndFeed");
while (drainOutputBuffer(positionUs, elapsedRealtimeUs)) {} while (drainOutputBuffer(positionUs, elapsedRealtimeUs)) {}
while (feedInputBuffer()) {} while (feedInputBuffer()) {}
TraceUtil.endSection(); TraceUtil.endSection();
} else if (format != null) { } else {
skipToKeyframeBefore(positionUs); skipSource(positionUs);
// We need to read any format changes despite not having a codec so that drmSession can be
// updated, and so that we have the most recent format should the codec be initialized. We may
// also reach the end of the stream. Note that readSource will not read a sample into a
// flags-only buffer.
flagsOnlyBuffer.clear();
int result = readSource(formatHolder, flagsOnlyBuffer, false);
if (result == C.RESULT_FORMAT_READ) {
onInputFormatChanged(formatHolder.format);
} else if (result == C.RESULT_BUFFER_READ) {
Assertions.checkState(flagsOnlyBuffer.isEndOfStream());
inputStreamEnded = true;
processEndOfStream();
}
} }
decoderCounters.ensureUpdated(); decoderCounters.ensureUpdated();
} }
......
...@@ -262,8 +262,8 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb ...@@ -262,8 +262,8 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
stream.skipToKeyframeBefore(startUs + timeUs); stream.skipData(startUs + positionUs);
} }
} }
......
...@@ -43,7 +43,7 @@ public final class EmptySampleStream implements SampleStream { ...@@ -43,7 +43,7 @@ public final class EmptySampleStream implements SampleStream {
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
// Do nothing. // Do nothing.
} }
......
...@@ -340,8 +340,13 @@ import java.io.IOException; ...@@ -340,8 +340,13 @@ import java.io.IOException;
loadingFinished, lastSeekPositionUs); loadingFinished, lastSeekPositionUs);
} }
/* package */ void skipToKeyframeBefore(int track, long timeUs) { /* package */ void skipData(int track, long positionUs) {
sampleQueues.valueAt(track).skipToKeyframeBefore(timeUs, true); DefaultTrackOutput sampleQueue = sampleQueues.valueAt(track);
if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) {
sampleQueue.skipAll();
} else {
sampleQueue.skipToKeyframeBefore(positionUs, true);
}
} }
// Loader.Callback implementation. // Loader.Callback implementation.
...@@ -569,8 +574,8 @@ import java.io.IOException; ...@@ -569,8 +574,8 @@ import java.io.IOException;
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
ExtractorMediaPeriod.this.skipToKeyframeBefore(track, timeUs); ExtractorMediaPeriod.this.skipData(track, positionUs);
} }
} }
......
...@@ -66,10 +66,11 @@ public interface SampleStream { ...@@ -66,10 +66,11 @@ public interface SampleStream {
int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired); int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired);
/** /**
* Attempts to skip to the keyframe before the specified time. * Attempts to skip to the keyframe before the specified position, or to the end of the stream if
* {@code positionUs} is beyond it.
* *
* @param timeUs The specified time. * @param positionUs The specified time.
*/ */
void skipToKeyframeBefore(long timeUs); void skipData(long positionUs);
} }
...@@ -235,8 +235,10 @@ import java.util.Arrays; ...@@ -235,8 +235,10 @@ import java.util.Arrays;
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
// Do nothing. if (positionUs > 0) {
streamState = STREAM_STATE_END_OF_STREAM;
}
} }
} }
......
...@@ -251,8 +251,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -251,8 +251,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
primarySampleQueue.skipToKeyframeBefore(timeUs, true); if (loadingFinished && positionUs > primarySampleQueue.getLargestQueuedTimestampUs()) {
primarySampleQueue.skipAll();
} else {
primarySampleQueue.skipToKeyframeBefore(positionUs, true);
}
} }
// Loader.Callback implementation. // Loader.Callback implementation.
...@@ -448,8 +452,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -448,8 +452,12 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
sampleQueue.skipToKeyframeBefore(timeUs, true); if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) {
sampleQueue.skipAll();
} else {
sampleQueue.skipToKeyframeBefore(positionUs, true);
}
} }
@Override @Override
......
...@@ -50,8 +50,8 @@ import java.io.IOException; ...@@ -50,8 +50,8 @@ import java.io.IOException;
} }
@Override @Override
public void skipToKeyframeBefore(long timeUs) { public void skipData(long positionUs) {
sampleStreamWrapper.skipToKeyframeBefore(group, timeUs); sampleStreamWrapper.skipData(group, positionUs);
} }
} }
...@@ -312,8 +312,13 @@ import java.util.LinkedList; ...@@ -312,8 +312,13 @@ import java.util.LinkedList;
loadingFinished, lastSeekPositionUs); loadingFinished, lastSeekPositionUs);
} }
/* package */ void skipToKeyframeBefore(int group, long timeUs) { /* package */ void skipData(int group, long positionUs) {
sampleQueues.valueAt(group).skipToKeyframeBefore(timeUs, true); DefaultTrackOutput sampleQueue = sampleQueues.valueAt(group);
if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) {
sampleQueue.skipAll();
} else {
sampleQueue.skipToKeyframeBefore(positionUs, true);
}
} }
private boolean finishedReadingChunk(HlsMediaChunk chunk) { private boolean finishedReadingChunk(HlsMediaChunk chunk) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment