Commit 29b12e2f by tonihei Committed by Ian Baker

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
parent 92437f3a
...@@ -499,12 +499,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -499,12 +499,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
maybeNotifyDownstreamFormat(track); maybeNotifyDownstreamFormat(track);
SampleQueue sampleQueue = sampleQueues[track]; SampleQueue sampleQueue = sampleQueues[track];
int skipCount; int skipCount = sampleQueue.getSkipCount(positionUs, loadingFinished);
if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.skip(skipCount);
skipCount = sampleQueue.advanceToEnd();
} else {
skipCount = sampleQueue.advanceTo(positionUs);
}
if (skipCount == 0) { if (skipCount == 0) {
maybeStartDeferredRetry(track); maybeStartDeferredRetry(track);
} }
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.source; package com.google.android.exoplayer2.source;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import android.os.Looper; import android.os.Looper;
import android.util.Log; import android.util.Log;
import androidx.annotation.CallSuper; import androidx.annotation.CallSuper;
...@@ -402,34 +404,39 @@ public class SampleQueue implements TrackOutput { ...@@ -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. * @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); int relativeReadIndex = getRelativeIndex(readPosition);
if (!hasNextSample() || timeUs < timesUs[relativeReadIndex]) { if (!hasNextSample() || timeUs < timesUs[relativeReadIndex]) {
return 0; return 0;
} }
if (timeUs > largestQueuedTimestampUs && allowEndOfQueue) {
return length - readPosition;
}
int offset = int offset =
findSampleBefore(relativeReadIndex, length - readPosition, timeUs, /* keyframe= */ true); findSampleBefore(relativeReadIndex, length - readPosition, timeUs, /* keyframe= */ true);
if (offset == -1) { if (offset == -1) {
return 0; return 0;
} }
readPosition += offset;
return 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() { public final synchronized void skip(int count) {
int skipCount = length - readPosition; checkArgument(count >= 0 && readPosition + count <= length);
readPosition = length; readPosition += count;
return skipCount;
} }
/** /**
...@@ -788,7 +795,7 @@ public class SampleQueue implements TrackOutput { ...@@ -788,7 +795,7 @@ public class SampleQueue implements TrackOutput {
private long discardUpstreamSampleMetadata(int discardFromIndex) { private long discardUpstreamSampleMetadata(int discardFromIndex) {
int discardCount = getWriteIndex() - discardFromIndex; int discardCount = getWriteIndex() - discardFromIndex;
Assertions.checkArgument(0 <= discardCount && discardCount <= (length - readPosition)); checkArgument(0 <= discardCount && discardCount <= (length - readPosition));
length -= discardCount; length -= discardCount;
largestQueuedTimestampUs = Math.max(largestDiscardedTimestampUs, getLargestTimestamp(length)); largestQueuedTimestampUs = Math.max(largestDiscardedTimestampUs, getLargestTimestamp(length));
isLastSampleQueued = discardCount == 0 && isLastSampleQueued; isLastSampleQueued = discardCount == 0 && isLastSampleQueued;
......
...@@ -392,12 +392,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -392,12 +392,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
if (isPendingReset()) { if (isPendingReset()) {
return 0; return 0;
} }
int skipCount; int skipCount = primarySampleQueue.getSkipCount(positionUs, loadingFinished);
if (loadingFinished && positionUs > primarySampleQueue.getLargestQueuedTimestampUs()) { primarySampleQueue.skip(skipCount);
skipCount = primarySampleQueue.advanceToEnd();
} else {
skipCount = primarySampleQueue.advanceTo(positionUs);
}
maybeNotifyPrimaryTrackFormatChanged(); maybeNotifyPrimaryTrackFormatChanged();
return skipCount; return skipCount;
} }
...@@ -789,12 +785,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S ...@@ -789,12 +785,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
return 0; return 0;
} }
maybeNotifyDownstreamFormat(); maybeNotifyDownstreamFormat();
int skipCount; int skipCount = sampleQueue.getSkipCount(positionUs, loadingFinished);
if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { sampleQueue.skip(skipCount);
skipCount = sampleQueue.advanceToEnd();
} else {
skipCount = sampleQueue.advanceTo(positionUs);
}
return skipCount; return skipCount;
} }
......
...@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.C.RESULT_BUFFER_READ; ...@@ -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_FORMAT_READ;
import static com.google.android.exoplayer2.C.RESULT_NOTHING_READ; import static com.google.android.exoplayer2.C.RESULT_NOTHING_READ;
import static com.google.common.truth.Truth.assertThat; 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.lang.Long.MIN_VALUE;
import static java.util.Arrays.copyOfRange; import static java.util.Arrays.copyOfRange;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
...@@ -590,9 +591,10 @@ public final class SampleQueueTest { ...@@ -590,9 +591,10 @@ public final class SampleQueueTest {
} }
@Test @Test
public void advanceToEnd() { public void skipToEnd() {
writeTestData(); writeTestData();
sampleQueue.advanceToEnd(); sampleQueue.skip(
sampleQueue.getSkipCount(/* timeUs= */ MAX_VALUE, /* allowEndOfQueue= */ true));
assertAllocationCount(10); assertAllocationCount(10);
sampleQueue.discardToRead(); sampleQueue.discardToRead();
assertAllocationCount(0); assertAllocationCount(0);
...@@ -604,10 +606,11 @@ public final class SampleQueueTest { ...@@ -604,10 +606,11 @@ public final class SampleQueueTest {
} }
@Test @Test
public void advanceToEndRetainsUnassignedData() { public void skipToEndRetainsUnassignedData() {
sampleQueue.format(FORMAT_1); sampleQueue.format(FORMAT_1);
sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE); sampleQueue.sampleData(new ParsableByteArray(DATA), ALLOCATION_SIZE);
sampleQueue.advanceToEnd(); sampleQueue.skip(
sampleQueue.getSkipCount(/* timeUs= */ MAX_VALUE, /* allowEndOfQueue= */ true));
assertAllocationCount(1); assertAllocationCount(1);
sampleQueue.discardToRead(); sampleQueue.discardToRead();
// Skipping shouldn't discard data that may belong to a sample whose metadata has yet to be // 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 { ...@@ -635,41 +638,47 @@ public final class SampleQueueTest {
} }
@Test @Test
public void advanceToBeforeBuffer() { public void skipToBeforeBuffer() {
writeTestData(); 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). // Should have no effect (we're already at the first frame).
assertThat(skipCount).isEqualTo(0); assertThat(skipCount).isEqualTo(0);
sampleQueue.skip(skipCount);
assertReadTestData(); assertReadTestData();
assertNoSamplesToRead(FORMAT_2); assertNoSamplesToRead(FORMAT_2);
} }
@Test @Test
public void advanceToStartOfBuffer() { public void skipToStartOfBuffer() {
writeTestData(); 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). // Should have no effect (we're already at the first frame).
assertThat(skipCount).isEqualTo(0); assertThat(skipCount).isEqualTo(0);
sampleQueue.skip(skipCount);
assertReadTestData(); assertReadTestData();
assertNoSamplesToRead(FORMAT_2); assertNoSamplesToRead(FORMAT_2);
} }
@Test @Test
public void advanceToEndOfBuffer() { public void skipToEndOfBuffer() {
writeTestData(); 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). // Should advance to 2nd keyframe (the 4th frame).
assertThat(skipCount).isEqualTo(4); assertThat(skipCount).isEqualTo(4);
sampleQueue.skip(skipCount);
assertReadTestData(/* startFormat= */ null, DATA_SECOND_KEYFRAME_INDEX); assertReadTestData(/* startFormat= */ null, DATA_SECOND_KEYFRAME_INDEX);
assertNoSamplesToRead(FORMAT_2); assertNoSamplesToRead(FORMAT_2);
} }
@Test @Test
public void advanceToAfterBuffer() { public void skipToAfterBuffer() {
writeTestData(); 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). // Should advance to 2nd keyframe (the 4th frame).
assertThat(skipCount).isEqualTo(4); assertThat(skipCount).isEqualTo(4);
sampleQueue.skip(skipCount);
assertReadTestData(/* startFormat= */ null, DATA_SECOND_KEYFRAME_INDEX); assertReadTestData(/* startFormat= */ null, DATA_SECOND_KEYFRAME_INDEX);
assertNoSamplesToRead(FORMAT_2); assertNoSamplesToRead(FORMAT_2);
} }
......
...@@ -595,11 +595,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; ...@@ -595,11 +595,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} }
SampleQueue sampleQueue = sampleQueues[sampleQueueIndex]; SampleQueue sampleQueue = sampleQueues[sampleQueueIndex];
if (loadingFinished && positionUs > sampleQueue.getLargestQueuedTimestampUs()) { int skipCount = sampleQueue.getSkipCount(positionUs, loadingFinished);
return sampleQueue.advanceToEnd(); sampleQueue.skip(skipCount);
} else { return skipCount;
return sampleQueue.advanceTo(positionUs);
}
} }
// SequenceableLoader implementation // SequenceableLoader implementation
......
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