Expose first index in SampleQueue

This will be needed when retaining a back-buffer. Being able to
query the first index allows us to work out when we've discarded
all samples that were obtained from a particular chunk, which
we'll use to determine when to remove chunks from
ChunkSampleStream.mediaChunks.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175172085
This commit is contained in:
olly 2017-11-09 09:58:18 -08:00 committed by Oliver Woodman
parent 694bd997cb
commit eb4e05199f
3 changed files with 60 additions and 27 deletions

View File

@ -51,8 +51,8 @@ import com.google.android.exoplayer2.util.Util;
private Format[] formats;
private int length;
private int absoluteStartIndex;
private int relativeStartIndex;
private int absoluteFirstIndex;
private int relativeFirstIndex;
private int readPosition;
private long largestDiscardedTimestampUs;
@ -87,8 +87,8 @@ import com.google.android.exoplayer2.util.Util;
*/
public void reset(boolean resetUpstreamFormat) {
length = 0;
absoluteStartIndex = 0;
relativeStartIndex = 0;
absoluteFirstIndex = 0;
relativeFirstIndex = 0;
readPosition = 0;
upstreamKeyframeRequired = true;
largestDiscardedTimestampUs = Long.MIN_VALUE;
@ -103,7 +103,7 @@ import com.google.android.exoplayer2.util.Util;
* Returns the current absolute write index.
*/
public int getWriteIndex() {
return absoluteStartIndex + length;
return absoluteFirstIndex + length;
}
/**
@ -132,11 +132,18 @@ import com.google.android.exoplayer2.util.Util;
// Called by the consuming thread.
/**
* Returns the current absolute start index.
*/
public int getFirstIndex() {
return absoluteFirstIndex;
}
/**
* Returns the current absolute read index.
*/
public int getReadIndex() {
return absoluteStartIndex + readPosition;
return absoluteFirstIndex + readPosition;
}
/**
@ -297,11 +304,11 @@ import com.google.android.exoplayer2.util.Util;
* {@link C#POSITION_UNSET} if no discarding of data is necessary.
*/
public synchronized long discardTo(long timeUs, boolean toKeyframe, boolean stopAtReadPosition) {
if (length == 0 || timeUs < timesUs[relativeStartIndex]) {
if (length == 0 || timeUs < timesUs[relativeFirstIndex]) {
return C.POSITION_UNSET;
}
int searchLength = stopAtReadPosition && readPosition != length ? readPosition + 1 : length;
int discardCount = findSampleBefore(relativeStartIndex, searchLength, timeUs, toKeyframe);
int discardCount = findSampleBefore(relativeFirstIndex, searchLength, timeUs, toKeyframe);
if (discardCount == -1) {
return C.POSITION_UNSET;
}
@ -382,15 +389,15 @@ import com.google.android.exoplayer2.util.Util;
int[] newSizes = new int[newCapacity];
CryptoData[] newCryptoDatas = new CryptoData[newCapacity];
Format[] newFormats = new Format[newCapacity];
int beforeWrap = capacity - relativeStartIndex;
System.arraycopy(offsets, relativeStartIndex, newOffsets, 0, beforeWrap);
System.arraycopy(timesUs, relativeStartIndex, newTimesUs, 0, beforeWrap);
System.arraycopy(flags, relativeStartIndex, newFlags, 0, beforeWrap);
System.arraycopy(sizes, relativeStartIndex, newSizes, 0, beforeWrap);
System.arraycopy(cryptoDatas, relativeStartIndex, newCryptoDatas, 0, beforeWrap);
System.arraycopy(formats, relativeStartIndex, newFormats, 0, beforeWrap);
System.arraycopy(sourceIds, relativeStartIndex, newSourceIds, 0, beforeWrap);
int afterWrap = relativeStartIndex;
int beforeWrap = capacity - relativeFirstIndex;
System.arraycopy(offsets, relativeFirstIndex, newOffsets, 0, beforeWrap);
System.arraycopy(timesUs, relativeFirstIndex, newTimesUs, 0, beforeWrap);
System.arraycopy(flags, relativeFirstIndex, newFlags, 0, beforeWrap);
System.arraycopy(sizes, relativeFirstIndex, newSizes, 0, beforeWrap);
System.arraycopy(cryptoDatas, relativeFirstIndex, newCryptoDatas, 0, beforeWrap);
System.arraycopy(formats, relativeFirstIndex, newFormats, 0, beforeWrap);
System.arraycopy(sourceIds, relativeFirstIndex, newSourceIds, 0, beforeWrap);
int afterWrap = relativeFirstIndex;
System.arraycopy(offsets, 0, newOffsets, beforeWrap, afterWrap);
System.arraycopy(timesUs, 0, newTimesUs, beforeWrap, afterWrap);
System.arraycopy(flags, 0, newFlags, beforeWrap, afterWrap);
@ -405,7 +412,7 @@ import com.google.android.exoplayer2.util.Util;
cryptoDatas = newCryptoDatas;
formats = newFormats;
sourceIds = newSourceIds;
relativeStartIndex = 0;
relativeFirstIndex = 0;
length = capacity;
capacity = newCapacity;
}
@ -440,7 +447,7 @@ import com.google.android.exoplayer2.util.Util;
relativeSampleIndex = capacity - 1;
}
}
discardUpstreamSamples(absoluteStartIndex + retainCount);
discardUpstreamSamples(absoluteFirstIndex + retainCount);
return true;
}
@ -454,7 +461,7 @@ import com.google.android.exoplayer2.util.Util;
* @param length The length of the range being searched.
* @param timeUs The specified time.
* @param keyframe Whether only keyframes should be considered.
* @return The offset from {@code relativeStartIndex} to the found sample, or -1 if no matching
* @return The offset from {@code relativeFirstIndex} to the found sample, or -1 if no matching
* sample was found.
*/
private int findSampleBefore(int relativeStartIndex, int length, long timeUs, boolean keyframe) {
@ -487,20 +494,20 @@ import com.google.android.exoplayer2.util.Util;
largestDiscardedTimestampUs = Math.max(largestDiscardedTimestampUs,
getLargestTimestamp(discardCount));
length -= discardCount;
absoluteStartIndex += discardCount;
relativeStartIndex += discardCount;
if (relativeStartIndex >= capacity) {
relativeStartIndex -= capacity;
absoluteFirstIndex += discardCount;
relativeFirstIndex += discardCount;
if (relativeFirstIndex >= capacity) {
relativeFirstIndex -= capacity;
}
readPosition -= discardCount;
if (readPosition < 0) {
readPosition = 0;
}
if (length == 0) {
int relativeLastDiscardIndex = (relativeStartIndex == 0 ? capacity : relativeStartIndex) - 1;
int relativeLastDiscardIndex = (relativeFirstIndex == 0 ? capacity : relativeFirstIndex) - 1;
return offsets[relativeLastDiscardIndex] + sizes[relativeLastDiscardIndex];
} else {
return offsets[relativeStartIndex];
return offsets[relativeFirstIndex];
}
}
@ -537,7 +544,7 @@ import com.google.android.exoplayer2.util.Util;
* @param offset The offset, which must be in the range [0, length].
*/
private int getRelativeIndex(int offset) {
int relativeIndex = relativeStartIndex + offset;
int relativeIndex = relativeFirstIndex + offset;
return relativeIndex < capacity ? relativeIndex : relativeIndex - capacity;
}

View File

@ -181,6 +181,13 @@ public final class SampleQueue implements TrackOutput {
return metadataQueue.hasNextSample();
}
/**
* Returns the absolute index of the first sample.
*/
public int getFirstIndex() {
return metadataQueue.getFirstIndex();
}
/**
* Returns the current absolute read index.
*/

View File

@ -215,12 +215,14 @@ public final class SampleQueueTest {
public void testReadMultiWithRewind() {
writeTestData();
assertReadTestData();
assertThat(sampleQueue.getFirstIndex()).isEqualTo(0);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
assertAllocationCount(10);
// Rewind.
sampleQueue.rewind();
assertAllocationCount(10);
// Read again.
assertThat(sampleQueue.getFirstIndex()).isEqualTo(0);
assertThat(sampleQueue.getReadIndex()).isEqualTo(0);
assertReadTestData();
}
@ -230,11 +232,14 @@ public final class SampleQueueTest {
writeTestData();
assertReadTestData();
sampleQueue.discardToRead();
assertThat(sampleQueue.getFirstIndex()).isEqualTo(8);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
assertAllocationCount(0);
// Rewind.
sampleQueue.rewind();
assertAllocationCount(0);
// Can't read again.
assertThat(sampleQueue.getFirstIndex()).isEqualTo(8);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
assertReadEndOfStream(false);
}
@ -332,6 +337,7 @@ public final class SampleQueueTest {
writeTestData();
// Should discard everything.
sampleQueue.discardToEnd();
assertThat(sampleQueue.getFirstIndex()).isEqualTo(8);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
assertAllocationCount(0);
// We should still be able to read the upstream format.
@ -346,28 +352,39 @@ public final class SampleQueueTest {
writeTestData();
// Shouldn't discard anything.
sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(0);
assertThat(sampleQueue.getReadIndex()).isEqualTo(0);
assertAllocationCount(10);
// Read the first sample.
assertReadTestData(null, 0, 1);
// Shouldn't discard anything.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1] - 1, false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(0);
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(10);
// Should discard the read sample.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1], false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(1);
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(9);
// Shouldn't discard anything.
sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(1);
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(9);
// Should be able to read the remaining samples.
assertReadTestData(TEST_FORMAT_1, 1, 7);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(1);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
// Should discard up to the second last sample
sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP - 1, false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(6);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
assertAllocationCount(3);
// Should discard up the last sample
sampleQueue.discardTo(LAST_SAMPLE_TIMESTAMP, false, true);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(7);
assertThat(sampleQueue.getReadIndex()).isEqualTo(8);
assertAllocationCount(1);
}
@ -376,10 +393,12 @@ public final class SampleQueueTest {
writeTestData();
// Shouldn't discard anything.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1] - 1, false, false);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(0);
assertThat(sampleQueue.getReadIndex()).isEqualTo(0);
assertAllocationCount(10);
// Should discard the first sample.
sampleQueue.discardTo(TEST_SAMPLE_TIMESTAMPS[1], false, false);
assertThat(sampleQueue.getFirstIndex()).isEqualTo(1);
assertThat(sampleQueue.getReadIndex()).isEqualTo(1);
assertAllocationCount(9);
// Should be able to read the remaining samples.