Commit 45c7fe9b by olly Committed by Oliver Woodman

Drain embedded track sample queues when not enabled.

I think it's likely we'll revert back to discarding media
in sync with the playback position for ExtractorMediaSource
and HlsMediaSource too, where the tracks are muxed with ones
we're requesting anyway.

Note: discardBuffer is named as it is because it'll also be
used to discard for enabled tracks soon, as a result of the
remaining TODO in ChunkSampleStream. For enabled tracks the
discard will also be conditional on the samples having been
consumed, obviously.

Issue: #2362
Issue: #2176

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=149525857
parent 09471def
...@@ -461,6 +461,11 @@ public final class ExoPlayerTest extends TestCase { ...@@ -461,6 +461,11 @@ public final class ExoPlayerTest extends TestCase {
} }
@Override @Override
public void discardBuffer(long positionUs) {
// Do nothing.
}
@Override
public long readDiscontinuity() { public long readDiscontinuity() {
assertTrue(preparedPeriod); assertTrue(preparedPeriod);
return C.TIME_UNSET; return C.TIME_UNSET;
......
...@@ -455,6 +455,8 @@ import java.io.IOException; ...@@ -455,6 +455,8 @@ import java.io.IOException;
TraceUtil.beginSection("doSomeWork"); TraceUtil.beginSection("doSomeWork");
updatePlaybackPositions(); updatePlaybackPositions();
playingPeriodHolder.mediaPeriod.discardBuffer(playbackInfo.positionUs);
boolean allRenderersEnded = true; boolean allRenderersEnded = true;
boolean allRenderersReadyOrEnded = true; boolean allRenderersReadyOrEnded = true;
for (Renderer renderer : enabledRenderers) { for (Renderer renderer : enabledRenderers) {
......
...@@ -110,6 +110,11 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb ...@@ -110,6 +110,11 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
} }
@Override @Override
public void discardBuffer(long positionUs) {
mediaPeriod.discardBuffer(positionUs + startUs);
}
@Override
public long readDiscontinuity() { public long readDiscontinuity() {
if (pendingInitialDiscontinuity) { if (pendingInitialDiscontinuity) {
for (ClippingSampleStream sampleStream : sampleStreams) { for (ClippingSampleStream sampleStream : sampleStreams) {
......
...@@ -235,6 +235,11 @@ import java.io.IOException; ...@@ -235,6 +235,11 @@ import java.io.IOException;
} }
@Override @Override
public void discardBuffer(long positionUs) {
// Do nothing.
}
@Override
public boolean continueLoading(long playbackPositionUs) { public boolean continueLoading(long playbackPositionUs) {
if (loadingFinished || (prepared && enabledTrackCount == 0)) { if (loadingFinished || (prepared && enabledTrackCount == 0)) {
return false; return false;
......
...@@ -105,6 +105,13 @@ public interface MediaPeriod extends SequenceableLoader { ...@@ -105,6 +105,13 @@ public interface MediaPeriod extends SequenceableLoader {
SampleStream[] streams, boolean[] streamResetFlags, long positionUs); SampleStream[] streams, boolean[] streamResetFlags, long positionUs);
/** /**
* Discards buffered media up to the specified position.
*
* @param positionUs The position in microseconds.
*/
void discardBuffer(long positionUs);
/**
* Attempts to read a discontinuity. * Attempts to read a discontinuity.
* <p> * <p>
* After this method has returned a value other than {@link C#TIME_UNSET}, all * After this method has returned a value other than {@link C#TIME_UNSET}, all
......
...@@ -129,6 +129,13 @@ import java.util.IdentityHashMap; ...@@ -129,6 +129,13 @@ import java.util.IdentityHashMap;
} }
@Override @Override
public void discardBuffer(long positionUs) {
for (MediaPeriod period : enabledPeriods) {
period.discardBuffer(positionUs);
}
}
@Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return sequenceableLoader.continueLoading(positionUs);
} }
......
...@@ -112,6 +112,11 @@ import java.util.Arrays; ...@@ -112,6 +112,11 @@ import java.util.Arrays;
} }
@Override @Override
public void discardBuffer(long positionUs) {
// Do nothing.
}
@Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
if (loadingFinished || loader.isLoading()) { if (loadingFinished || loader.isLoading()) {
return false; return false;
......
...@@ -40,6 +40,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -40,6 +40,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
private final int primaryTrackType; private final int primaryTrackType;
private final int[] embeddedTrackTypes; private final int[] embeddedTrackTypes;
private final boolean[] embeddedTracksSelected;
private final T chunkSource; private final T chunkSource;
private final SequenceableLoader.Callback<ChunkSampleStream<T>> callback; private final SequenceableLoader.Callback<ChunkSampleStream<T>> callback;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
...@@ -49,7 +50,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -49,7 +50,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
private final LinkedList<BaseMediaChunk> mediaChunks; private final LinkedList<BaseMediaChunk> mediaChunks;
private final List<BaseMediaChunk> readOnlyMediaChunks; private final List<BaseMediaChunk> readOnlyMediaChunks;
private final DefaultTrackOutput primarySampleQueue; private final DefaultTrackOutput primarySampleQueue;
private final EmbeddedSampleStream[] embeddedSampleStreams; private final DefaultTrackOutput[] embeddedSampleQueues;
private final BaseMediaChunkOutput mediaChunkOutput; private final BaseMediaChunkOutput mediaChunkOutput;
private Format primaryDownstreamTrackFormat; private Format primaryDownstreamTrackFormat;
...@@ -84,7 +85,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -84,7 +85,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks); readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks);
int embeddedTrackCount = embeddedTrackTypes == null ? 0 : embeddedTrackTypes.length; int embeddedTrackCount = embeddedTrackTypes == null ? 0 : embeddedTrackTypes.length;
embeddedSampleStreams = newEmbeddedSampleStreamArray(embeddedTrackCount); embeddedSampleQueues = new DefaultTrackOutput[embeddedTrackCount];
embeddedTracksSelected = new boolean[embeddedTrackCount];
int[] trackTypes = new int[1 + embeddedTrackCount]; int[] trackTypes = new int[1 + embeddedTrackCount];
DefaultTrackOutput[] sampleQueues = new DefaultTrackOutput[1 + embeddedTrackCount]; DefaultTrackOutput[] sampleQueues = new DefaultTrackOutput[1 + embeddedTrackCount];
...@@ -93,9 +95,10 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -93,9 +95,10 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
sampleQueues[0] = primarySampleQueue; sampleQueues[0] = primarySampleQueue;
for (int i = 0; i < embeddedTrackCount; i++) { for (int i = 0; i < embeddedTrackCount; i++) {
DefaultTrackOutput trackOutput = new DefaultTrackOutput(allocator);
embeddedSampleQueues[i] = trackOutput;
sampleQueues[i + 1] = trackOutput;
trackTypes[i + 1] = embeddedTrackTypes[i]; trackTypes[i + 1] = embeddedTrackTypes[i];
sampleQueues[i + 1] = new DefaultTrackOutput(allocator);
embeddedSampleStreams[i] = new EmbeddedSampleStream(sampleQueues[i + 1]);
} }
mediaChunkOutput = new BaseMediaChunkOutput(trackTypes, sampleQueues); mediaChunkOutput = new BaseMediaChunkOutput(trackTypes, sampleQueues);
...@@ -104,26 +107,36 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -104,26 +107,36 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
} }
/** /**
* Returns whether a {@link SampleStream} is for an embedded track of a {@link ChunkSampleStream}. * Discards buffered media for embedded tracks that are not currently selected, up to the
*/ * specified position.
public static boolean isPrimarySampleStream(SampleStream sampleStream) { *
return sampleStream instanceof ChunkSampleStream; * @param positionUs The position to discard up to, in microseconds.
}
/**
* Returns whether a {@link SampleStream} is for an embedded track of a {@link ChunkSampleStream}.
*/ */
public static boolean isEmbeddedSampleStream(SampleStream sampleStream) { public void discardUnselectedEmbeddedTracksTo(long positionUs) {
return sampleStream instanceof ChunkSampleStream.EmbeddedSampleStream; for (int i = 0; i < embeddedSampleQueues.length; i++) {
if (!embeddedTracksSelected[i]) {
embeddedSampleQueues[i].skipToKeyframeBefore(positionUs, true);
}
}
} }
/** /**
* Returns the {@link SampleStream} for the embedded track with the specified type. * Selects the embedded track, returning a new {@link EmbeddedSampleStream} from which the track's
* samples can be consumed. {@link EmbeddedSampleStream#release()} must be called on the returned
* stream when the track is no longer required, and before calling this method again to obtain
* another stream for the same track.
*
* @param positionUs The current playback position in microseconds.
* @param trackType The type of the embedded track to enable.
* @return The {@link EmbeddedSampleStream} for the embedded track.
*/ */
public SampleStream getEmbeddedSampleStream(int trackType) { public EmbeddedSampleStream selectEmbeddedTrack(long positionUs, int trackType) {
for (int i = 0; i < embeddedTrackTypes.length; i++) { for (int i = 0; i < embeddedSampleQueues.length; i++) {
if (embeddedTrackTypes[i] == trackType) { if (embeddedTrackTypes[i] == trackType) {
return embeddedSampleStreams[i]; Assertions.checkState(!embeddedTracksSelected[i]);
embeddedTracksSelected[i] = true;
embeddedSampleQueues[i].skipToKeyframeBefore(positionUs, true);
return new EmbeddedSampleStream(this, embeddedSampleQueues[i], i);
} }
} }
// Should never happen. // Should never happen.
...@@ -179,8 +192,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -179,8 +192,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
} }
// TODO: For this to work correctly, the embedded streams must not discard anything from their // TODO: For this to work correctly, the embedded streams must not discard anything from their
// sample queues beyond the current read position of the primary stream. // sample queues beyond the current read position of the primary stream.
for (EmbeddedSampleStream embeddedSampleStream : embeddedSampleStreams) { for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) {
embeddedSampleStream.skipToKeyframeBefore(positionUs); embeddedSampleQueue.skipToKeyframeBefore(positionUs);
} }
} else { } else {
// We failed, and need to restart. // We failed, and need to restart.
...@@ -191,8 +204,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -191,8 +204,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
loader.cancelLoading(); loader.cancelLoading();
} else { } else {
primarySampleQueue.reset(true); primarySampleQueue.reset(true);
for (EmbeddedSampleStream embeddedSampleStream : embeddedSampleStreams) { for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) {
embeddedSampleStream.reset(true); embeddedSampleQueue.reset(true);
} }
} }
} }
...@@ -205,8 +218,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -205,8 +218,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
*/ */
public void release() { public void release() {
primarySampleQueue.disable(); primarySampleQueue.disable();
for (EmbeddedSampleStream embeddedSampleStream : embeddedSampleStreams) { for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) {
embeddedSampleStream.disable(); embeddedSampleQueue.disable();
} }
loader.release(); loader.release();
} }
...@@ -232,7 +245,6 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -232,7 +245,6 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
if (isPendingReset()) { if (isPendingReset()) {
return C.RESULT_NOTHING_READ; return C.RESULT_NOTHING_READ;
} }
// TODO: For embedded streams that aren't being used, we need to drain their queues here.
discardDownstreamMediaChunks(primarySampleQueue.getReadIndex()); discardDownstreamMediaChunks(primarySampleQueue.getReadIndex());
return primarySampleQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, return primarySampleQueue.readData(formatHolder, buffer, formatRequired, loadingFinished,
lastSeekPositionUs); lastSeekPositionUs);
...@@ -264,8 +276,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -264,8 +276,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
loadable.bytesLoaded()); loadable.bytesLoaded());
if (!released) { if (!released) {
primarySampleQueue.reset(true); primarySampleQueue.reset(true);
for (EmbeddedSampleStream embeddedStream : embeddedSampleStreams) { for (DefaultTrackOutput embeddedSampleQueue : embeddedSampleQueues) {
embeddedStream.reset(true); embeddedSampleQueue.reset(true);
} }
callback.onContinueLoadingRequested(this); callback.onContinueLoadingRequested(this);
} }
...@@ -284,8 +296,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -284,8 +296,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
BaseMediaChunk removed = mediaChunks.removeLast(); BaseMediaChunk removed = mediaChunks.removeLast();
Assertions.checkState(removed == loadable); Assertions.checkState(removed == loadable);
primarySampleQueue.discardUpstreamSamples(removed.getFirstSampleIndex(0)); primarySampleQueue.discardUpstreamSamples(removed.getFirstSampleIndex(0));
for (int i = 0; i < embeddedSampleStreams.length; i++) { for (int i = 0; i < embeddedSampleQueues.length; i++) {
embeddedSampleStreams[i].discardUpstreamSamples(removed.getFirstSampleIndex(i + 1)); embeddedSampleQueues[i].discardUpstreamSamples(removed.getFirstSampleIndex(i + 1));
} }
if (mediaChunks.isEmpty()) { if (mediaChunks.isEmpty()) {
pendingResetPositionUs = lastSeekPositionUs; pendingResetPositionUs = lastSeekPositionUs;
...@@ -406,25 +418,28 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -406,25 +418,28 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
loadingFinished = false; loadingFinished = false;
} }
primarySampleQueue.discardUpstreamSamples(removed.getFirstSampleIndex(0)); primarySampleQueue.discardUpstreamSamples(removed.getFirstSampleIndex(0));
for (int i = 0; i < embeddedSampleStreams.length; i++) { for (int i = 0; i < embeddedSampleQueues.length; i++) {
embeddedSampleStreams[i].discardUpstreamSamples(removed.getFirstSampleIndex(i + 1)); embeddedSampleQueues[i].discardUpstreamSamples(removed.getFirstSampleIndex(i + 1));
} }
eventDispatcher.upstreamDiscarded(primaryTrackType, startTimeUs, endTimeUs); eventDispatcher.upstreamDiscarded(primaryTrackType, startTimeUs, endTimeUs);
return true; return true;
} }
@SuppressWarnings("unchecked") /**
private static <T extends ChunkSource> ChunkSampleStream<T>.EmbeddedSampleStream[] * A {@link SampleStream} embedded in a {@link ChunkSampleStream}.
newEmbeddedSampleStreamArray(int length) { */
return new ChunkSampleStream.EmbeddedSampleStream[length]; public final class EmbeddedSampleStream implements SampleStream {
}
private final class EmbeddedSampleStream implements SampleStream { public final ChunkSampleStream<T> parent;
private final DefaultTrackOutput sampleQueue; private final DefaultTrackOutput sampleQueue;
private final int index;
public EmbeddedSampleStream(DefaultTrackOutput sampleQueue) { public EmbeddedSampleStream(ChunkSampleStream<T> parent, DefaultTrackOutput sampleQueue,
int index) {
this.parent = parent;
this.sampleQueue = sampleQueue; this.sampleQueue = sampleQueue;
this.index = index;
} }
@Override @Override
...@@ -452,16 +467,9 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -452,16 +467,9 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
lastSeekPositionUs); lastSeekPositionUs);
} }
public void reset(boolean enable) { public void release() {
sampleQueue.reset(enable); Assertions.checkState(embeddedTracksSelected[index]);
} embeddedTracksSelected[index] = false;
public void disable() {
sampleQueue.disable();
}
public void discardUpstreamSamples(int discardFromIndex) {
sampleQueue.discardUpstreamSamples(discardFromIndex);
} }
} }
......
...@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.source.SequenceableLoader; ...@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.source.SequenceableLoader;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.chunk.ChunkSampleStream; import com.google.android.exoplayer2.source.chunk.ChunkSampleStream;
import com.google.android.exoplayer2.source.chunk.ChunkSampleStream.EmbeddedSampleStream;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest; import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.Representation; import com.google.android.exoplayer2.source.dash.manifest.Representation;
...@@ -125,7 +126,7 @@ import java.util.List; ...@@ -125,7 +126,7 @@ import java.util.List;
HashMap<Integer, ChunkSampleStream<DashChunkSource>> primarySampleStreams = new HashMap<>(); HashMap<Integer, ChunkSampleStream<DashChunkSource>> primarySampleStreams = new HashMap<>();
// First pass for primary tracks. // First pass for primary tracks.
for (int i = 0; i < selections.length; i++) { for (int i = 0; i < selections.length; i++) {
if (ChunkSampleStream.isPrimarySampleStream(streams[i])) { if (streams[i] instanceof ChunkSampleStream) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ChunkSampleStream<DashChunkSource> stream = (ChunkSampleStream<DashChunkSource>) streams[i]; ChunkSampleStream<DashChunkSource> stream = (ChunkSampleStream<DashChunkSource>) streams[i];
if (selections[i] == null || !mayRetainStreamFlags[i]) { if (selections[i] == null || !mayRetainStreamFlags[i]) {
...@@ -149,26 +150,31 @@ import java.util.List; ...@@ -149,26 +150,31 @@ import java.util.List;
} }
// Second pass for embedded tracks. // Second pass for embedded tracks.
for (int i = 0; i < selections.length; i++) { for (int i = 0; i < selections.length; i++) {
if (ChunkSampleStream.isEmbeddedSampleStream(streams[i])) { if ((streams[i] instanceof EmbeddedSampleStream || streams[i] instanceof EmptySampleStream)
// Always clear even if the selection is unchanged, since the parent primary sample stream && (selections[i] == null || !mayRetainStreamFlags[i])) {
// may have been replaced. // The stream is for an embedded track and is either no longer selected or needs replacing.
releaseIfEmbeddedSampleStream(streams[i]);
streams[i] = null; streams[i] = null;
} }
if (streams[i] == null && selections[i] != null) { // We need to consider replacing the stream even if it's non-null because the primary stream
// may have been replaced, selected or deselected.
if (selections[i] != null) {
int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup()); int trackGroupIndex = trackGroups.indexOf(selections[i].getTrackGroup());
if (trackGroupIndex >= adaptationSetCount) { if (trackGroupIndex >= adaptationSetCount) {
EmbeddedTrackInfo embeddedTrackInfo = int embeddedTrackIndex = trackGroupIndex - adaptationSetCount;
embeddedTrackInfos[trackGroupIndex - adaptationSetCount]; EmbeddedTrackInfo embeddedTrackInfo = embeddedTrackInfos[embeddedTrackIndex];
int adaptationSetIndex = embeddedTrackInfo.adaptationSetIndex; int adaptationSetIndex = embeddedTrackInfo.adaptationSetIndex;
ChunkSampleStream<DashChunkSource> primarySampleStream = ChunkSampleStream<?> primaryStream = primarySampleStreams.get(adaptationSetIndex);
primarySampleStreams.get(adaptationSetIndex); SampleStream stream = streams[i];
if (primarySampleStream != null) { boolean mayRetainStream = primaryStream == null ? stream instanceof EmptySampleStream
streams[i] = primarySampleStream.getEmbeddedSampleStream(embeddedTrackInfo.trackType); : (stream instanceof EmbeddedSampleStream
} else { && ((EmbeddedSampleStream) stream).parent == primaryStream);
// The primary track in which this one is embedded is not selected. if (!mayRetainStream) {
streams[i] = new EmptySampleStream(); releaseIfEmbeddedSampleStream(stream);
streams[i] = primaryStream == null ? new EmptySampleStream()
: primaryStream.selectEmbeddedTrack(positionUs, embeddedTrackInfo.trackType);
streamResetFlags[i] = true;
} }
streamResetFlags[i] = true;
} }
} }
} }
...@@ -179,6 +185,13 @@ import java.util.List; ...@@ -179,6 +185,13 @@ import java.util.List;
} }
@Override @Override
public void discardBuffer(long positionUs) {
for (ChunkSampleStream<DashChunkSource> sampleStream : sampleStreams) {
sampleStream.discardUnselectedEmbeddedTracksTo(positionUs);
}
}
@Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return sequenceableLoader.continueLoading(positionUs);
} }
...@@ -321,6 +334,12 @@ import java.util.List; ...@@ -321,6 +334,12 @@ import java.util.List;
return new ChunkSampleStream[length]; return new ChunkSampleStream[length];
} }
private static void releaseIfEmbeddedSampleStream(SampleStream sampleStream) {
if (sampleStream instanceof EmbeddedSampleStream) {
((EmbeddedSampleStream) sampleStream).release();
}
}
private static final class EmbeddedTrackInfo { private static final class EmbeddedTrackInfo {
public final int adaptationSetIndex; public final int adaptationSetIndex;
......
...@@ -190,6 +190,11 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper ...@@ -190,6 +190,11 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
} }
@Override @Override
public void discardBuffer(long positionUs) {
// Do nothing.
}
@Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return sequenceableLoader.continueLoading(positionUs);
} }
......
...@@ -137,6 +137,11 @@ import java.util.ArrayList; ...@@ -137,6 +137,11 @@ import java.util.ArrayList;
} }
@Override @Override
public void discardBuffer(long positionUs) {
// Do nothing.
}
@Override
public boolean continueLoading(long positionUs) { public boolean continueLoading(long positionUs) {
return sequenceableLoader.continueLoading(positionUs); return sequenceableLoader.continueLoading(positionUs);
} }
......
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