Commit 2c09f8e0 by olly Committed by Oliver Woodman

Decouple start and read indices in SampleMetadataQueue

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=159426366
parent 86f06faa
...@@ -35,7 +35,6 @@ import com.google.android.exoplayer2.util.Util; ...@@ -35,7 +35,6 @@ import com.google.android.exoplayer2.util.Util;
public int size; public int size;
public long offset; public long offset;
public long nextOffset;
public CryptoData cryptoData; public CryptoData cryptoData;
} }
...@@ -54,8 +53,9 @@ import com.google.android.exoplayer2.util.Util; ...@@ -54,8 +53,9 @@ import com.google.android.exoplayer2.util.Util;
private int length; private int length;
private int absoluteStartIndex; private int absoluteStartIndex;
private int relativeStartIndex; private int relativeStartIndex;
private int relativeEndIndex; private int readPosition;
private long nextOffset;
private long largestDequeuedTimestampUs; private long largestDequeuedTimestampUs;
private long largestQueuedTimestampUs; private long largestQueuedTimestampUs;
private boolean upstreamKeyframeRequired; private boolean upstreamKeyframeRequired;
...@@ -79,10 +79,10 @@ import com.google.android.exoplayer2.util.Util; ...@@ -79,10 +79,10 @@ import com.google.android.exoplayer2.util.Util;
} }
public void clearSampleData() { public void clearSampleData() {
length = 0;
absoluteStartIndex = 0; absoluteStartIndex = 0;
relativeStartIndex = 0; relativeStartIndex = 0;
relativeEndIndex = 0; readPosition = 0;
length = 0;
upstreamKeyframeRequired = true; upstreamKeyframeRequired = true;
} }
...@@ -108,8 +108,9 @@ import com.google.android.exoplayer2.util.Util; ...@@ -108,8 +108,9 @@ import com.google.android.exoplayer2.util.Util;
*/ */
public long discardUpstreamSamples(int discardFromIndex) { public long discardUpstreamSamples(int discardFromIndex) {
int discardCount = getWriteIndex() - discardFromIndex; int discardCount = getWriteIndex() - discardFromIndex;
Assertions.checkArgument(0 <= discardCount && discardCount <= length); Assertions.checkArgument(0 <= discardCount && discardCount <= (length - readPosition));
int relativeEndIndex = (relativeStartIndex + length) % capacity;
if (discardCount == 0) { if (discardCount == 0) {
if (absoluteStartIndex == 0 && length == 0) { if (absoluteStartIndex == 0 && length == 0) {
// Nothing has been written to the queue. // Nothing has been written to the queue.
...@@ -144,7 +145,7 @@ import com.google.android.exoplayer2.util.Util; ...@@ -144,7 +145,7 @@ import com.google.android.exoplayer2.util.Util;
* Returns the current absolute read index. * Returns the current absolute read index.
*/ */
public int getReadIndex() { public int getReadIndex() {
return absoluteStartIndex; return absoluteStartIndex + readPosition;
} }
/** /**
...@@ -152,14 +153,15 @@ import com.google.android.exoplayer2.util.Util; ...@@ -152,14 +153,15 @@ import com.google.android.exoplayer2.util.Util;
* {@link #hasNextSample()} is {@code false}. * {@link #hasNextSample()} is {@code false}.
*/ */
public int peekSourceId() { public int peekSourceId() {
return hasNextSample() ? sourceIds[relativeStartIndex] : upstreamSourceId; int relativeReadIndex = (relativeStartIndex + readPosition) % capacity;
return hasNextSample() ? sourceIds[relativeReadIndex] : upstreamSourceId;
} }
/** /**
* Returns whether a sample is available to be read. * Returns whether a sample is available to be read.
*/ */
public synchronized boolean hasNextSample() { public synchronized boolean hasNextSample() {
return length != 0; return readPosition != length;
} }
/** /**
...@@ -185,6 +187,13 @@ import com.google.android.exoplayer2.util.Util; ...@@ -185,6 +187,13 @@ import com.google.android.exoplayer2.util.Util;
} }
/** /**
* Rewinds the read position to the first sample retained in the queue.
*/
public synchronized void rewind() {
readPosition = 0;
}
/**
* Attempts to read from the queue. * Attempts to read from the queue.
* *
* @param formatHolder A {@link FormatHolder} to populate in the case of reading a format. * @param formatHolder A {@link FormatHolder} to populate in the case of reading a format.
...@@ -222,8 +231,9 @@ import com.google.android.exoplayer2.util.Util; ...@@ -222,8 +231,9 @@ import com.google.android.exoplayer2.util.Util;
} }
} }
if (formatRequired || formats[relativeStartIndex] != downstreamFormat) { int relativeReadIndex = (relativeStartIndex + readPosition) % capacity;
formatHolder.format = formats[relativeStartIndex]; if (formatRequired || formats[relativeReadIndex] != downstreamFormat) {
formatHolder.format = formats[relativeReadIndex];
return C.RESULT_FORMAT_READ; return C.RESULT_FORMAT_READ;
} }
...@@ -231,62 +241,37 @@ import com.google.android.exoplayer2.util.Util; ...@@ -231,62 +241,37 @@ import com.google.android.exoplayer2.util.Util;
return C.RESULT_NOTHING_READ; return C.RESULT_NOTHING_READ;
} }
buffer.timeUs = timesUs[relativeStartIndex]; buffer.timeUs = timesUs[relativeReadIndex];
buffer.setFlags(flags[relativeStartIndex]); buffer.setFlags(flags[relativeReadIndex]);
extrasHolder.size = sizes[relativeStartIndex]; extrasHolder.size = sizes[relativeReadIndex];
extrasHolder.offset = offsets[relativeStartIndex]; extrasHolder.offset = offsets[relativeReadIndex];
extrasHolder.cryptoData = cryptoDatas[relativeStartIndex]; extrasHolder.cryptoData = cryptoDatas[relativeReadIndex];
largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs); largestDequeuedTimestampUs = Math.max(largestDequeuedTimestampUs, buffer.timeUs);
length--; readPosition++;
relativeStartIndex++; nextOffset = extrasHolder.offset + extrasHolder.size;
absoluteStartIndex++;
if (relativeStartIndex == capacity) {
// Wrap around.
relativeStartIndex = 0;
}
extrasHolder.nextOffset = length > 0 ? offsets[relativeStartIndex]
: extrasHolder.offset + extrasHolder.size;
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
} }
/** /**
* Skips all samples in the buffer. * Attempts to advance the read position to the keyframe before or at the specified time. If
*
* @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no
* dropping of data is required.
*/
public synchronized long skipAll() {
if (!hasNextSample()) {
return C.POSITION_UNSET;
}
int lastSampleIndex = (relativeStartIndex + length - 1) % capacity;
relativeStartIndex = (relativeStartIndex + length) % capacity;
absoluteStartIndex += length;
length = 0;
return offsets[lastSampleIndex] + sizes[lastSampleIndex];
}
/**
* Attempts to locate the keyframe before or at the specified time. If
* {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs} * {@code allowTimeBeyondBuffer} is {@code false} then it is also required that {@code timeUs}
* falls within the buffer. * falls within the buffer.
* *
* @param timeUs The seek time. * @param timeUs The seek time.
* @param allowTimeBeyondBuffer Whether the skip can succeed if {@code timeUs} is beyond the end * @param allowTimeBeyondBuffer Whether the skip can succeed if {@code timeUs} is beyond the end
* of the buffer. * of the buffer.
* @return The offset of the keyframe's data if the keyframe was present. * @return Whether the read position was advanced to the keyframe before or at the specified time.
* {@link C#POSITION_UNSET} otherwise.
*/ */
public synchronized long skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { public synchronized boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) {
if (!hasNextSample() || timeUs < timesUs[relativeStartIndex]) { int relativeReadIndex = (relativeStartIndex + readPosition) % capacity;
return C.POSITION_UNSET; if (!hasNextSample() || timeUs < timesUs[relativeReadIndex]) {
return false;
} }
if (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer) { if (timeUs > largestQueuedTimestampUs && !allowTimeBeyondBuffer) {
return C.POSITION_UNSET; return false;
} }
// This could be optimized to use a binary search, however in practice callers to this method // This could be optimized to use a binary search, however in practice callers to this method
...@@ -294,7 +279,8 @@ import com.google.android.exoplayer2.util.Util; ...@@ -294,7 +279,8 @@ import com.google.android.exoplayer2.util.Util;
// a binary search would yield any real benefit. // a binary search would yield any real benefit.
int sampleCount = 0; int sampleCount = 0;
int sampleCountToKeyframe = -1; int sampleCountToKeyframe = -1;
int searchIndex = relativeStartIndex; int searchIndex = relativeReadIndex;
int relativeEndIndex = (relativeStartIndex + length) % capacity;
while (searchIndex != relativeEndIndex) { while (searchIndex != relativeEndIndex) {
if (timesUs[searchIndex] > timeUs) { if (timesUs[searchIndex] > timeUs) {
// We've gone too far. // We've gone too far.
...@@ -308,13 +294,44 @@ import com.google.android.exoplayer2.util.Util; ...@@ -308,13 +294,44 @@ import com.google.android.exoplayer2.util.Util;
} }
if (sampleCountToKeyframe == -1) { if (sampleCountToKeyframe == -1) {
return C.POSITION_UNSET; return false;
}
readPosition += sampleCountToKeyframe;
nextOffset = offsets[(relativeStartIndex + readPosition) % capacity];
return true;
}
/**
* Skips all samples in the buffer.
*/
public synchronized void skipAll() {
if (!hasNextSample()) {
return;
} }
readPosition = length;
int relativeLastSampleIndex = (relativeStartIndex + readPosition - 1) % capacity;
nextOffset = offsets[relativeLastSampleIndex] + sizes[relativeLastSampleIndex];
}
relativeStartIndex = (relativeStartIndex + sampleCountToKeyframe) % capacity; /**
absoluteStartIndex += sampleCountToKeyframe; * Discards all samples in the buffer prior to the read position.
length -= sampleCountToKeyframe; *
return offsets[relativeStartIndex]; * @return The offset up to which data should be dropped, or {@link C#POSITION_UNSET} if no
* dropping of data is required.
*/
public synchronized long discardToRead() {
if (readPosition == 0) {
return C.POSITION_UNSET;
}
length -= readPosition;
absoluteStartIndex += readPosition;
relativeStartIndex += readPosition;
if (relativeStartIndex >= capacity) {
relativeStartIndex -= capacity;
}
readPosition = 0;
return length == 0 ? nextOffset : offsets[relativeStartIndex];
} }
// Called by the loading thread. // Called by the loading thread.
...@@ -344,6 +361,8 @@ import com.google.android.exoplayer2.util.Util; ...@@ -344,6 +361,8 @@ import com.google.android.exoplayer2.util.Util;
} }
Assertions.checkState(!upstreamFormatRequired); Assertions.checkState(!upstreamFormatRequired);
commitSampleTimestamp(timeUs); commitSampleTimestamp(timeUs);
int relativeEndIndex = (relativeStartIndex + length) % capacity;
timesUs[relativeEndIndex] = timeUs; timesUs[relativeEndIndex] = timeUs;
offsets[relativeEndIndex] = offset; offsets[relativeEndIndex] = offset;
sizes[relativeEndIndex] = size; sizes[relativeEndIndex] = size;
...@@ -351,7 +370,7 @@ import com.google.android.exoplayer2.util.Util; ...@@ -351,7 +370,7 @@ import com.google.android.exoplayer2.util.Util;
cryptoDatas[relativeEndIndex] = cryptoData; cryptoDatas[relativeEndIndex] = cryptoData;
formats[relativeEndIndex] = upstreamFormat; formats[relativeEndIndex] = upstreamFormat;
sourceIds[relativeEndIndex] = upstreamSourceId; sourceIds[relativeEndIndex] = upstreamSourceId;
// Increment the write index.
length++; length++;
if (length == capacity) { if (length == capacity) {
// Increase the capacity. // Increase the capacity.
...@@ -387,15 +406,8 @@ import com.google.android.exoplayer2.util.Util; ...@@ -387,15 +406,8 @@ import com.google.android.exoplayer2.util.Util;
formats = newFormats; formats = newFormats;
sourceIds = newSourceIds; sourceIds = newSourceIds;
relativeStartIndex = 0; relativeStartIndex = 0;
relativeEndIndex = capacity;
length = capacity; length = capacity;
capacity = newCapacity; capacity = newCapacity;
} else {
relativeEndIndex++;
if (relativeEndIndex == capacity) {
// Wrap around.
relativeEndIndex = 0;
}
} }
} }
...@@ -415,7 +427,7 @@ import com.google.android.exoplayer2.util.Util; ...@@ -415,7 +427,7 @@ import com.google.android.exoplayer2.util.Util;
return false; return false;
} }
int retainCount = length; int retainCount = length;
while (retainCount > 0 while (retainCount > readPosition
&& timesUs[(relativeStartIndex + retainCount - 1) % capacity] >= timeUs) { && timesUs[(relativeStartIndex + retainCount - 1) % capacity] >= timeUs) {
retainCount--; retainCount--;
} }
......
...@@ -227,7 +227,8 @@ public final class SampleQueue implements TrackOutput { ...@@ -227,7 +227,8 @@ public final class SampleQueue implements TrackOutput {
* Skips all samples currently in the buffer. * Skips all samples currently in the buffer.
*/ */
public void skipAll() { public void skipAll() {
long nextOffset = metadataQueue.skipAll(); metadataQueue.skipAll();
long nextOffset = metadataQueue.discardToRead();
if (nextOffset != C.POSITION_UNSET) { if (nextOffset != C.POSITION_UNSET) {
dropDownstreamTo(nextOffset); dropDownstreamTo(nextOffset);
} }
...@@ -245,12 +246,16 @@ public final class SampleQueue implements TrackOutput { ...@@ -245,12 +246,16 @@ public final class SampleQueue implements TrackOutput {
* @return Whether the skip was successful. * @return Whether the skip was successful.
*/ */
public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) { public boolean skipToKeyframeBefore(long timeUs, boolean allowTimeBeyondBuffer) {
long nextOffset = metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer); boolean success = metadataQueue.skipToKeyframeBefore(timeUs, allowTimeBeyondBuffer);
if (nextOffset == C.POSITION_UNSET) { if (success) {
long nextOffset = metadataQueue.discardToRead();
if (nextOffset != C.POSITION_UNSET) {
dropDownstreamTo(nextOffset);
}
return true;
} else {
return false; return false;
} }
dropDownstreamTo(nextOffset);
return true;
} }
/** /**
...@@ -290,7 +295,10 @@ public final class SampleQueue implements TrackOutput { ...@@ -290,7 +295,10 @@ public final class SampleQueue implements TrackOutput {
buffer.ensureSpaceForWrite(extrasHolder.size); buffer.ensureSpaceForWrite(extrasHolder.size);
readData(extrasHolder.offset, buffer.data, extrasHolder.size); readData(extrasHolder.offset, buffer.data, extrasHolder.size);
// Advance the read head. // Advance the read head.
dropDownstreamTo(extrasHolder.nextOffset); long nextOffset = metadataQueue.discardToRead();
if (nextOffset != C.POSITION_UNSET) {
dropDownstreamTo(nextOffset);
}
} }
return C.RESULT_BUFFER_READ; return C.RESULT_BUFFER_READ;
case C.RESULT_NOTHING_READ: case C.RESULT_NOTHING_READ:
......
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