Optimize in-queue seeking when non-AV tracks are present

Let's do it this way for now. Note there's an implicit
assumption in here that non-AV tracks consist of only
key-frames, but I think we'll not encounter any issues
in the real world as a result, we already make this
assumption in ChunkSampleStream, and actually tagging
every queue with this information explicitly is a very
painful amount of plumbing.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=161545383
This commit is contained in:
olly 2017-07-11 10:18:25 -07:00 committed by Oliver Woodman
parent 6b17e2cf3f
commit 3c5688de73

View File

@ -80,7 +80,7 @@ import java.util.Arrays;
private boolean prepared;
private boolean seenFirstTrackSelection;
private boolean notifyReset;
private boolean notifyDiscontinuity;
private int enabledTrackCount;
private TrackGroupArray tracks;
private long durationUs;
@ -229,7 +229,7 @@ import java.util.Arrays;
}
}
if (enabledTrackCount == 0) {
notifyReset = false;
notifyDiscontinuity = false;
if (loader.isLoading()) {
// Discard as much as we can synchronously.
for (SampleQueue sampleQueue : sampleQueues) {
@ -282,8 +282,8 @@ import java.util.Arrays;
@Override
public long readDiscontinuity() {
if (notifyReset) {
notifyReset = false;
if (notifyDiscontinuity) {
notifyDiscontinuity = false;
return lastSeekPositionUs;
}
return C.TIME_UNSET;
@ -319,18 +319,9 @@ import java.util.Arrays;
// Treat all seeks into non-seekable media as being to t=0.
positionUs = seekMap.isSeekable() ? positionUs : 0;
lastSeekPositionUs = positionUs;
notifyDiscontinuity = false;
// If we're not pending a reset, see if we can seek within the sample queues.
boolean seekInsideBuffer = !isPendingReset();
int trackCount = sampleQueues.length;
for (int i = 0; seekInsideBuffer && i < trackCount; i++) {
SampleQueue sampleQueue = sampleQueues[i];
sampleQueue.rewind();
// TODO: For sparse tracks (e.g. text, metadata) this may return false when an in-buffer
// seek should be allowed. If there are non-sparse tracks (e.g. video, audio) for which
// in-buffer seeking is successful, we should perform an in-buffer seek unconditionally.
seekInsideBuffer = sampleQueue.advanceTo(positionUs, true, false);
sampleQueue.discardToRead();
}
boolean seekInsideBuffer = !isPendingReset() && seekInsideBufferUs(positionUs);
// If we failed to seek within the sample queues, we need to restart.
if (!seekInsideBuffer) {
pendingResetPositionUs = positionUs;
@ -338,12 +329,11 @@ import java.util.Arrays;
if (loader.isLoading()) {
loader.cancelLoading();
} else {
for (int i = 0; i < trackCount; i++) {
sampleQueues[i].reset();
for (SampleQueue sampleQueue : sampleQueues) {
sampleQueue.reset();
}
}
}
notifyReset = false;
return positionUs;
}
@ -359,7 +349,7 @@ import java.util.Arrays;
/* package */ int readData(int track, FormatHolder formatHolder, DecoderInputBuffer buffer,
boolean formatRequired) {
if (notifyReset || isPendingReset()) {
if (notifyDiscontinuity || isPendingReset()) {
return C.RESULT_NOTHING_READ;
}
return sampleQueues[track].read(formatHolder, buffer, formatRequired, loadingFinished,
@ -536,7 +526,7 @@ import java.util.Arrays;
// previous load finished, so it's necessary to load from the start whenever commencing
// a new load.
lastSeekPositionUs = 0;
notifyReset = prepared;
notifyDiscontinuity = prepared;
for (SampleQueue sampleQueue : sampleQueues) {
sampleQueue.reset();
}
@ -544,6 +534,30 @@ import java.util.Arrays;
}
}
/**
* Attempts to seek to the specified position within the sample queues.
*
* @param positionUs The seek position in microseconds.
* @return Whether the in-buffer seek was successful.
*/
private boolean seekInsideBufferUs(long positionUs) {
int trackCount = sampleQueues.length;
for (int i = 0; i < trackCount; i++) {
SampleQueue sampleQueue = sampleQueues[i];
sampleQueue.rewind();
boolean seekInsideQueue = sampleQueue.advanceTo(positionUs, true, false);
// If we have AV tracks then an in-buffer seek is successful if the seek into every AV queue
// is successful. We ignore whether seeks within non-AV queues are successful in this case, as
// they may be sparse or poorly interleaved. If we only have non-AV tracks then a seek is
// successful only if the seek into every queue succeeds.
if (!seekInsideQueue && (trackIsAudioVideoFlags[i] || !haveAudioVideoTracks)) {
return false;
}
sampleQueue.discardToRead();
}
return true;
}
private int getExtractedSamplesCount() {
int extractedSamplesCount = 0;
for (SampleQueue sampleQueue : sampleQueues) {