Ensure SampleQueue seek only happens if needed

When selecting progressive and HLS tracks, we currently check if
we can either seek in the existing samples or are starting from the
beginning of the stream. In both cases, we don't need to reload the
stream and can continue reading.

Seeking to the beginning isn't side-effect free though because it
also sets the startTimeUs to zero. Whether a seek to the beginning
is successful also depends on whether we already loaded a sample or
not. This mean that the startTimeUs value is set (or not set) based
on the speed of the Loader thread even for the same input starting
from the beginning. This race condition means the actual samples
we write to the stream may differ if the stream has initial samples
with negative timestamps.

We can avoid this race condition by checking if the queue is empty
first, so that we only call seekTo if really needed.

PiperOrigin-RevId: 546010951
This commit is contained in:
tonihei 2023-07-06 17:27:41 +01:00 committed by Rohit Singh
parent 1ef7579f5c
commit a9be9caf40
2 changed files with 10 additions and 12 deletions

View File

@ -288,13 +288,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// If there's still a chance of avoiding a seek, try and seek within the sample queue.
if (!seekRequired) {
SampleQueue sampleQueue = sampleQueues[track];
// A seek can be avoided if we're able to seek to the current playback position in the
// sample queue, or if we haven't read anything from the queue since the previous seek
// (this case is common for sparse tracks such as metadata tracks). In all other cases a
// seek is required.
// A seek can be avoided if we haven't read any samples yet (e.g. for the first track
// selection) or we are able to seek to the current playback position in the sample queue.
// In all other cases a seek is required.
seekRequired =
!sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */ true)
&& sampleQueue.getReadIndex() != 0;
sampleQueue.getReadIndex() != 0
&& !sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */ true);
}
}
}

View File

@ -393,13 +393,12 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
// If there's still a chance of avoiding a seek, try and seek within the sample queue.
if (!seekRequired) {
SampleQueue sampleQueue = sampleQueues[trackGroupToSampleQueueIndex[trackGroupIndex]];
// A seek can be avoided if we're able to seek to the current playback position in
// the sample queue, or if we haven't read anything from the queue since the previous
// seek (this case is common for sparse tracks such as metadata tracks). In all other
// cases a seek is required.
// A seek can be avoided if we haven't read any samples yet (e.g. for the first track
// selection) or we are able to seek to the current playback position in the sample
// queue. In all other cases a seek is required.
seekRequired =
!sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */ true)
&& sampleQueue.getReadIndex() != 0;
sampleQueue.getReadIndex() != 0
&& !sampleQueue.seekTo(positionUs, /* allowTimeBeyondBuffer= */ true);
}
}
}