From ebfd5a7fe039d53108e8afcd6772f3371eef9aa7 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 15 Jan 2018 07:04:15 -0800 Subject: [PATCH] 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 --- .../exoplayer2/source/SampleMetadataQueue.java | 8 ++++++-- .../android/exoplayer2/source/SampleQueue.java | 5 +++++ .../exoplayer2/source/chunk/ChunkSampleStream.java | 13 +++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java index 65c443d425..54db9d7880 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleMetadataQueue.java @@ -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, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 78b16bf377..a4feb924b8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -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. */ diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index 947664720b..b0a2686ef6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -120,11 +120,16 @@ public class ChunkSampleStream 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 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); -- GitLab