From 29b12e2f8d28ef9ba5f6a0bd0fb61d161f0dc2fc Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 13 Jul 2020 15:44:12 +0100 Subject: [PATCH] Split SampleQueue.advanceTo into two operations. The method currently advances the read position and returns the number of skipped samples. This prevents checking how many samples are skipped before the operation is executed. Instead, we have a new method that returns the number of to be skipped samples and a skip method that executes the skipping. PiperOrigin-RevId: 320953439 --- .../source/ProgressiveMediaPeriod.java | 8 ++--- .../exoplayer2/source/SampleQueue.java | 29 +++++++++------- .../source/chunk/ChunkSampleStream.java | 16 +++------ .../exoplayer2/source/SampleQueueTest.java | 33 ++++++++++++------- .../source/hls/HlsSampleStreamWrapper.java | 8 ++--- 5 files changed, 48 insertions(+), 46 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java index 7bc1c36ba7..cd1b49d101 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ProgressiveMediaPeriod.java @@ -499,12 +499,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; } maybeNotifyDownstreamFormat(track); SampleQueue sampleQueue = sampleQueues[track]; - int skipCount; - if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { - skipCount = sampleQueue.advanceToEnd(); - } else { - skipCount = sampleQueue.advanceTo(positionUs); - } + int skipCount = sampleQueue.getSkipCount(positionUs, loadingFinished); + sampleQueue.skip(skipCount); if (skipCount == 0) { maybeStartDeferredRetry(track); } 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 ab6e0e3d97..b45d8e06fe 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 @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer2.source; +import static com.google.android.exoplayer2.util.Assertions.checkArgument; + import android.os.Looper; import android.util.Log; import androidx.annotation.CallSuper; @@ -402,34 +404,39 @@ public class SampleQueue implements TrackOutput { } /** - * Advances the read position to the keyframe before or at the specified time. + * Returns the number of samples that need to be {@link #skip(int) skipped} to advance the read + * position to the keyframe before or at the specified time. * * @param timeUs The time to advance to. - * @return The number of samples that were skipped, which may be equal to 0. + * @param allowEndOfQueue Whether the end of the queue is considered a keyframe when {@code + * timeUs} is larger than the largest queued timestamp. + * @return The number of samples that need to be skipped, which may be equal to 0. */ - public final synchronized int advanceTo(long timeUs) { + public final synchronized int getSkipCount(long timeUs, boolean allowEndOfQueue) { int relativeReadIndex = getRelativeIndex(readPosition); if (!hasNextSample() || timeUs < timesUs[relativeReadIndex]) { return 0; } + if (timeUs > largestQueuedTimestampUs && allowEndOfQueue) { + return length - readPosition; + } int offset = findSampleBefore(relativeReadIndex, length - readPosition, timeUs, /* keyframe= */ true); if (offset == -1) { return 0; } - readPosition += offset; return offset; } /** - * Advances the read position to the end of the queue. + * Advances the read position by the specified number of samples. * - * @return The number of samples that were skipped. + * @param count The number of samples to advance the read position by. Must be at least 0 and at + * most {@link #getWriteIndex()} - {@link #getReadIndex()}. */ - public final synchronized int advanceToEnd() { - int skipCount = length - readPosition; - readPosition = length; - return skipCount; + public final synchronized void skip(int count) { + checkArgument(count >= 0 && readPosition + count <= length); + readPosition += count; } /** @@ -788,7 +795,7 @@ public class SampleQueue implements TrackOutput { private long discardUpstreamSampleMetadata(int discardFromIndex) { int discardCount = getWriteIndex() - discardFromIndex; - Assertions.checkArgument(0 <= discardCount && discardCount <= (length - readPosition)); + checkArgument(0 <= discardCount && discardCount <= (length - readPosition)); length -= discardCount; largestQueuedTimestampUs = Math.max(largestDiscardedTimestampUs, getLargestTimestamp(length)); isLastSampleQueued = discardCount == 0 && isLastSampleQueued; 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 2491432bb7..9238ef1c7c 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 @@ -392,12 +392,8 @@ public class ChunkSampleStream implements SampleStream, S if (isPendingReset()) { return 0; } - int skipCount; - if (loadingFinished && positionUs > primarySampleQueue.getLargestQueuedTimestampUs()) { - skipCount = primarySampleQueue.advanceToEnd(); - } else { - skipCount = primarySampleQueue.advanceTo(positionUs); - } + int skipCount = primarySampleQueue.getSkipCount(positionUs, loadingFinished); + primarySampleQueue.skip(skipCount); maybeNotifyPrimaryTrackFormatChanged(); return skipCount; } @@ -789,12 +785,8 @@ public class ChunkSampleStream implements SampleStream, S return 0; } maybeNotifyDownstreamFormat(); - int skipCount; - if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { - skipCount = sampleQueue.advanceToEnd(); - } else { - skipCount = sampleQueue.advanceTo(positionUs); - } + int skipCount = sampleQueue.getSkipCount(positionUs, loadingFinished); + sampleQueue.skip(skipCount); return skipCount; } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java index 16444b99bf..4583c542b3 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/SampleQueueTest.java @@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.C.RESULT_BUFFER_READ; import static com.google.android.exoplayer2.C.RESULT_FORMAT_READ; import static com.google.android.exoplayer2.C.RESULT_NOTHING_READ; import static com.google.common.truth.Truth.assertThat; +import static java.lang.Long.MAX_VALUE; import static java.lang.Long.MIN_VALUE; import static java.util.Arrays.copyOfRange; import static org.junit.Assert.assertArrayEquals; @@ -590,9 +591,10 @@ public final class SampleQueueTest { } @Test - public void advanceToEnd() { + public void skipToEnd() { writeTestData(); - sampleQueue.advanceToEnd(); + sampleQueue.skip( + sampleQueue.getSkipCount(/* timeUs= */ MAX_VALUE, /* allowEndOfQueue= */ true)); assertAllocationCount(10); sampleQueue.discardToRead(); assertAllocationCount(0); @@ -604,10 +606,11 @@ public final class SampleQueueTest { } @Test - public void advanceToEndRetainsUnassignedData() { + public void skipToEndRetainsUnassignedData() { sampleQueue.format(FORMAT_1); sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE); - sampleQueue.advanceToEnd(); + sampleQueue.skip( + sampleQueue.getSkipCount(/* timeUs= */ MAX_VALUE, /* allowEndOfQueue= */ true)); assertAllocationCount(1); sampleQueue.discardToRead(); // Skipping shouldn't discard data that may belong to a sample whose metadata has yet to be @@ -635,41 +638,47 @@ public final class SampleQueueTest { } @Test - public void advanceToBeforeBuffer() { + public void skipToBeforeBuffer() { writeTestData(); - int skipCount = sampleQueue.advanceTo(SAMPLE_TIMESTAMPS[0] - 1); + int skipCount = + sampleQueue.getSkipCount(SAMPLE_TIMESTAMPS[0] - 1, /* allowEndOfQueue= */ false); // Should have no effect (we're already at the first frame). assertThat(skipCount).isEqualTo(0); + sampleQueue.skip(skipCount); assertReadTestData(); assertNoSamplesToRead(FORMAT_2); } @Test - public void advanceToStartOfBuffer() { + public void skipToStartOfBuffer() { writeTestData(); - int skipCount = sampleQueue.advanceTo(SAMPLE_TIMESTAMPS[0]); + int skipCount = sampleQueue.getSkipCount(SAMPLE_TIMESTAMPS[0], /* allowEndOfQueue= */ false); // Should have no effect (we're already at the first frame). assertThat(skipCount).isEqualTo(0); + sampleQueue.skip(skipCount); assertReadTestData(); assertNoSamplesToRead(FORMAT_2); } @Test - public void advanceToEndOfBuffer() { + public void skipToEndOfBuffer() { writeTestData(); - int skipCount = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP); + int skipCount = sampleQueue.getSkipCount(LAST_SAMPLE_TIMESTAMP, /* allowEndOfQueue= */ false); // Should advance to 2nd keyframe (the 4th frame). assertThat(skipCount).isEqualTo(4); + sampleQueue.skip(skipCount); assertReadTestData(/* startFormat= */ null, DATA_SECOND_KEYFRAME_INDEX); assertNoSamplesToRead(FORMAT_2); } @Test - public void advanceToAfterBuffer() { + public void skipToAfterBuffer() { writeTestData(); - int skipCount = sampleQueue.advanceTo(LAST_SAMPLE_TIMESTAMP + 1); + int skipCount = + sampleQueue.getSkipCount(LAST_SAMPLE_TIMESTAMP + 1, /* allowEndOfQueue= */ false); // Should advance to 2nd keyframe (the 4th frame). assertThat(skipCount).isEqualTo(4); + sampleQueue.skip(skipCount); assertReadTestData(/* startFormat= */ null, DATA_SECOND_KEYFRAME_INDEX); assertNoSamplesToRead(FORMAT_2); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 530f9cb366..e7f55807f8 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -595,11 +595,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } SampleQueue sampleQueue = sampleQueues[sampleQueueIndex]; - if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { - return sampleQueue.advanceToEnd(); - } else { - return sampleQueue.advanceTo(positionUs); - } + int skipCount = sampleQueue.getSkipCount(positionUs, loadingFinished); + sampleQueue.skip(skipCount); + return skipCount; } // SequenceableLoader implementation