Don't discard embedded queues beyond primary queue.

ChunkSampleStream.seekToUs assumes that if we can seek within the
primary sample queue, we can also seek within the embedded queues.
This assumption can be violated fairly easily if discardBuffer is
called with toKeyframe=true, since this can cause samples to be
discarded from the embedded queues within the period for which a
seek in the primary sample queue will succeed. This change fixes
the issue.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=181965902
This commit is contained in:
olly 2018-01-15 07:04:15 -08:00 committed by Oliver Woodman
parent 7b534cd9fd
commit ebfd5a7fe0
3 changed files with 20 additions and 6 deletions

View File

@ -186,6 +186,11 @@ import com.google.android.exoplayer2.util.Util;
return largestQueuedTimestampUs;
}
/** Returns the timestamp of the first sample, or {@link Long#MIN_VALUE} if the queue is empty. */
public synchronized long getFirstTimestampUs() {
return length == 0 ? Long.MIN_VALUE : timesUs[relativeFirstIndex];
}
/**
* Rewinds the read position to the first sample retained in the queue.
*/
@ -487,8 +492,7 @@ import com.google.android.exoplayer2.util.Util;
* Discards the specified number of samples.
*
* @param discardCount The number of samples to discard.
* @return The corresponding offset up to which data should be discarded, or
* {@link C#POSITION_UNSET} if no discarding of data is necessary.
* @return The corresponding offset up to which data should be discarded.
*/
private long discardSamples(int discardCount) {
largestDiscardedTimestampUs = Math.max(largestDiscardedTimestampUs,

View File

@ -226,6 +226,11 @@ public final class SampleQueue implements TrackOutput {
return metadataQueue.getLargestQueuedTimestampUs();
}
/** Returns the timestamp of the first sample, or {@link Long#MIN_VALUE} if the queue is empty. */
public long getFirstTimestampUs() {
return metadataQueue.getFirstTimestampUs();
}
/**
* Rewinds the read position to the first sample in the queue.
*/

View File

@ -120,11 +120,16 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
* the specified position, rather than any sample before or at that position.
*/
public void discardBuffer(long positionUs, boolean toKeyframe) {
int oldFirstIndex = primarySampleQueue.getFirstIndex();
primarySampleQueue.discardTo(positionUs, toKeyframe, true);
for (int i = 0; i < embeddedSampleQueues.length; i++) {
embeddedSampleQueues[i].discardTo(positionUs, toKeyframe, embeddedTracksSelected[i]);
int newFirstIndex = primarySampleQueue.getFirstIndex();
if (newFirstIndex > oldFirstIndex) {
long discardToUs = primarySampleQueue.getFirstTimestampUs();
for (int i = 0; i < embeddedSampleQueues.length; i++) {
embeddedSampleQueues[i].discardTo(discardToUs, toKeyframe, embeddedTracksSelected[i]);
}
discardDownstreamMediaChunks(newFirstIndex);
}
discardDownstreamMediaChunks(primarySampleQueue.getFirstIndex());
}
/**
@ -209,7 +214,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
boolean seekInsideBuffer = !isPendingReset() && (primarySampleQueue.advanceTo(positionUs, true,
positionUs < getNextLoadPositionUs()) != SampleQueue.ADVANCE_FAILED);
if (seekInsideBuffer) {
// We succeeded. Discard samples and corresponding chunks prior to the seek position.
// We succeeded. Advance the embedded sample queues to the seek position.
for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) {
embeddedSampleQueue.rewind();
embeddedSampleQueue.advanceTo(positionUs, true, false);