Clean up downstream format notification for ChunkSampleStream

- Fixes the referenced issue.
- Provides more consistent behavior for the edge case of empty
  chunks (i.e. chunks containing now samples). Format changes
  will now always be reported for such chunks, unless the empty
  chunk is discarded from upstream before there's a chance to
  do so.

Issue: #4533

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=212443043
This commit is contained in:
olly 2018-09-11 06:43:32 -07:00 committed by Oliver Woodman
parent 21c5b0bf67
commit b31438b670

View file

@ -79,6 +79,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
private @Nullable ReleaseCallback<T> releaseCallback;
private long pendingResetPositionUs;
private long lastSeekPositionUs;
private int nextNotifyPrimaryFormatMediaChunkIndex;
/* package */ long decodeOnlyUntilPositionUs;
/* package */ boolean loadingFinished;
@ -191,16 +193,16 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
if (isPendingReset()) {
return;
}
int oldFirstIndex = primarySampleQueue.getFirstIndex();
int oldFirstSampleIndex = primarySampleQueue.getFirstIndex();
primarySampleQueue.discardTo(positionUs, toKeyframe, true);
int newFirstIndex = primarySampleQueue.getFirstIndex();
if (newFirstIndex > oldFirstIndex) {
int newFirstSampleIndex = primarySampleQueue.getFirstIndex();
if (newFirstSampleIndex > oldFirstSampleIndex) {
long discardToUs = primarySampleQueue.getFirstTimestampUs();
for (int i = 0; i < embeddedSampleQueues.length; i++) {
embeddedSampleQueues[i].discardTo(discardToUs, toKeyframe, embeddedTracksSelected[i]);
}
discardDownstreamMediaChunks(newFirstIndex);
}
discardDownstreamMediaChunks(newFirstSampleIndex);
}
/**
@ -318,7 +320,11 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
}
if (seekInsideBuffer) {
// We can seek inside the buffer. Advance the embedded sample queues to the seek position.
// We can seek inside the buffer.
nextNotifyPrimaryFormatMediaChunkIndex =
primarySampleIndexToMediaChunkIndex(
primarySampleQueue.getReadIndex(), /* minChunkIndex= */ 0);
// Advance the embedded sample queues to the seek position.
for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) {
embeddedSampleQueue.rewind();
embeddedSampleQueue.advanceTo(positionUs, true, false);
@ -328,6 +334,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
pendingResetPositionUs = positionUs;
loadingFinished = false;
mediaChunks.clear();
nextNotifyPrimaryFormatMediaChunkIndex = 0;
if (loader.isLoading()) {
loader.cancelLoading();
} else {
@ -400,13 +407,9 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
if (isPendingReset()) {
return C.RESULT_NOTHING_READ;
}
int result =
primarySampleQueue.read(
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilPositionUs);
if (result == C.RESULT_BUFFER_READ) {
maybeNotifyPrimaryTrackFormatChanged(primarySampleQueue.getReadIndex(), 1);
}
return result;
maybeNotifyPrimaryTrackFormatChanged();
return primarySampleQueue.read(
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilPositionUs);
}
@Override
@ -423,9 +426,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
skipCount = 0;
}
}
if (skipCount > 0) {
maybeNotifyPrimaryTrackFormatChanged(primarySampleQueue.getReadIndex(), skipCount);
}
maybeNotifyPrimaryTrackFormatChanged();
return skipCount;
}
@ -669,22 +670,25 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
return pendingResetPositionUs != C.TIME_UNSET;
}
private void discardDownstreamMediaChunks(int discardToPrimaryStreamIndex) {
private void discardDownstreamMediaChunks(int discardToSampleIndex) {
int discardToMediaChunkIndex =
primaryStreamIndexToMediaChunkIndex(discardToPrimaryStreamIndex, /* minChunkIndex= */ 0);
primarySampleIndexToMediaChunkIndex(discardToSampleIndex, /* minChunkIndex= */ 0);
// Don't discard any chunks that we haven't reported the primary format change for yet.
discardToMediaChunkIndex =
Math.min(discardToMediaChunkIndex, nextNotifyPrimaryFormatMediaChunkIndex);
if (discardToMediaChunkIndex > 0) {
Util.removeRange(mediaChunks, /* fromIndex= */ 0, /* toIndex= */ discardToMediaChunkIndex);
nextNotifyPrimaryFormatMediaChunkIndex -= discardToMediaChunkIndex;
}
}
private void maybeNotifyPrimaryTrackFormatChanged(int toPrimaryStreamReadIndex, int readCount) {
int fromMediaChunkIndex = primaryStreamIndexToMediaChunkIndex(
toPrimaryStreamReadIndex - readCount, /* minChunkIndex= */ 0);
int toMediaChunkIndexInclusive = readCount == 1 ? fromMediaChunkIndex
: primaryStreamIndexToMediaChunkIndex(toPrimaryStreamReadIndex - 1,
/* minChunkIndex= */ fromMediaChunkIndex);
for (int i = fromMediaChunkIndex; i <= toMediaChunkIndexInclusive; i++) {
maybeNotifyPrimaryTrackFormatChanged(i);
private void maybeNotifyPrimaryTrackFormatChanged() {
int readSampleIndex = primarySampleQueue.getReadIndex();
int notifyToMediaChunkIndex =
primarySampleIndexToMediaChunkIndex(
readSampleIndex, /* minChunkIndex= */ nextNotifyPrimaryFormatMediaChunkIndex - 1);
while (nextNotifyPrimaryFormatMediaChunkIndex <= notifyToMediaChunkIndex) {
maybeNotifyPrimaryTrackFormatChanged(nextNotifyPrimaryFormatMediaChunkIndex++);
}
}
@ -700,12 +704,20 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
}
/**
* Returns media chunk index for primary stream sample index. May be -1 if the list of media
* chunks is empty or the requested index is less than the first index in the first media chunk.
* Returns the media chunk index corresponding to a given primary sample index.
*
* @param primarySampleIndex The primary sample index for which the corresponding media chunk
* index is required.
* @param minChunkIndex A minimum chunk index from which to start searching, or -1 if no hint can
* be provided.
* @return The index of the media chunk corresponding to the sample index, or -1 if the list of
* media chunks is empty, or {@code minChunkIndex} if the sample precedes the first chunk in
* the search (i.e. the chunk at {@code minChunkIndex}, or at index 0 if {@code minChunkIndex}
* is -1.
*/
private int primaryStreamIndexToMediaChunkIndex(int primaryStreamIndex, int minChunkIndex) {
private int primarySampleIndexToMediaChunkIndex(int primarySampleIndex, int minChunkIndex) {
for (int i = minChunkIndex + 1; i < mediaChunks.size(); i++) {
if (mediaChunks.get(i).getFirstSampleIndex(0) > primaryStreamIndex) {
if (mediaChunks.get(i).getFirstSampleIndex(0) > primarySampleIndex) {
return i - 1;
}
}
@ -726,6 +738,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
private BaseMediaChunk discardUpstreamMediaChunksFromIndex(int chunkIndex) {
BaseMediaChunk firstRemovedChunk = mediaChunks.get(chunkIndex);
Util.removeRange(mediaChunks, /* fromIndex= */ chunkIndex, /* toIndex= */ mediaChunks.size());
nextNotifyPrimaryFormatMediaChunkIndex =
Math.max(nextNotifyPrimaryFormatMediaChunkIndex, mediaChunks.size());
primarySampleQueue.discardUpstreamSamples(firstRemovedChunk.getFirstSampleIndex(0));
for (int i = 0; i < embeddedSampleQueues.length; i++) {
embeddedSampleQueues[i].discardUpstreamSamples(firstRemovedChunk.getFirstSampleIndex(i + 1));