Calculate ExtractorSampleSource duration if unknown (playlists #4).
When buffering playlist items after the currently-playing one, continueBuffering should take a position that is negative because the playback position is before the start of the source being buffered. This change makes sure that ExtractorSampleSources always have a known duration when they are fully buffered, which means that the correct (negative) source-relative position can be calculated. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=124949409
This commit is contained in:
parent
e6267cd253
commit
66a5c96c5a
@ -364,7 +364,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
long operationStartTimeMs = SystemClock.elapsedRealtime();
|
long operationStartTimeMs = SystemClock.elapsedRealtime();
|
||||||
if (sampleSource == null) {
|
if (sampleSource == null) {
|
||||||
timeline.updateSources();
|
timeline.updateSources();
|
||||||
sampleSource = timeline.getSampleSource(internalPositionUs);
|
sampleSource = timeline.getSampleSource();
|
||||||
if (sampleSource != null) {
|
if (sampleSource != null) {
|
||||||
resumeInternal();
|
resumeInternal();
|
||||||
} else {
|
} else {
|
||||||
@ -380,7 +380,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
// Process reset if there is one, else update the position.
|
// Process reset if there is one, else update the position.
|
||||||
if (!checkForSourceResetInternal()) {
|
if (!checkForSourceResetInternal()) {
|
||||||
updatePositionUs();
|
updatePositionUs();
|
||||||
sampleSource = timeline.getSampleSource(internalPositionUs);
|
sampleSource = timeline.getSampleSource();
|
||||||
}
|
}
|
||||||
updateBufferedPositionUs();
|
updateBufferedPositionUs();
|
||||||
timeline.updateSources();
|
timeline.updateSources();
|
||||||
@ -405,17 +405,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
allRenderersReadyOrEnded = allRenderersReadyOrEnded && rendererReadyOrEnded;
|
allRenderersReadyOrEnded = allRenderersReadyOrEnded && rendererReadyOrEnded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean timelineIsReady = timeline.isReady();
|
||||||
if (allRenderersEnded && (durationUs == C.UNSET_TIME_US || durationUs <= positionUs)) {
|
if (allRenderersEnded && (durationUs == C.UNSET_TIME_US || durationUs <= positionUs)) {
|
||||||
setState(ExoPlayer.STATE_ENDED);
|
setState(ExoPlayer.STATE_ENDED);
|
||||||
stopRenderers();
|
stopRenderers();
|
||||||
} else if (state == ExoPlayer.STATE_BUFFERING && allRenderersReadyOrEnded
|
} else if (state == ExoPlayer.STATE_BUFFERING && allRenderersReadyOrEnded
|
||||||
&& haveSufficientBuffer() && timeline.isReady(internalPositionUs)) {
|
&& haveSufficientBuffer() && timelineIsReady) {
|
||||||
setState(ExoPlayer.STATE_READY);
|
setState(ExoPlayer.STATE_READY);
|
||||||
if (playWhenReady) {
|
if (playWhenReady) {
|
||||||
startRenderers();
|
startRenderers();
|
||||||
}
|
}
|
||||||
} else if (state == ExoPlayer.STATE_READY && (!allRenderersReadyOrEnded
|
} else if (state == ExoPlayer.STATE_READY && (!allRenderersReadyOrEnded || !timelineIsReady)) {
|
||||||
|| !timeline.isReady(internalPositionUs))) {
|
|
||||||
rebuffering = playWhenReady;
|
rebuffering = playWhenReady;
|
||||||
setState(ExoPlayer.STATE_BUFFERING);
|
setState(ExoPlayer.STATE_BUFFERING);
|
||||||
stopRenderers();
|
stopRenderers();
|
||||||
@ -485,9 +485,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
if (allRenderersEnded && (durationUs == C.UNSET_TIME_US || durationUs <= positionUs)) {
|
if (allRenderersEnded && (durationUs == C.UNSET_TIME_US || durationUs <= positionUs)) {
|
||||||
setState(ExoPlayer.STATE_ENDED);
|
setState(ExoPlayer.STATE_ENDED);
|
||||||
} else {
|
} else {
|
||||||
setState(allRenderersReadyOrEnded && haveSufficientBuffer()
|
setState(allRenderersReadyOrEnded && haveSufficientBuffer() && timeline.isReady()
|
||||||
&& timeline.isReady(internalPositionUs) ? ExoPlayer.STATE_READY
|
? ExoPlayer.STATE_READY : ExoPlayer.STATE_BUFFERING);
|
||||||
: ExoPlayer.STATE_BUFFERING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the renderers if ready, and schedule the first piece of work.
|
// Start the renderers if ready, and schedule the first piece of work.
|
||||||
@ -596,7 +595,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
private Source bufferingSource;
|
private Source bufferingSource;
|
||||||
|
|
||||||
private long playingSourceEndPositionUs;
|
private long playingSourceEndPositionUs;
|
||||||
private long nextSourceOffsetUs;
|
private long bufferingSourceOffsetUs;
|
||||||
|
|
||||||
public Timeline() {
|
public Timeline() {
|
||||||
rendererWasEnabledFlags = new boolean[renderers.length];
|
rendererWasEnabledFlags = new boolean[renderers.length];
|
||||||
@ -620,6 +619,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
Source newSource = new Source(sampleSource, index, renderers.length);
|
Source newSource = new Source(sampleSource, index, renderers.length);
|
||||||
if (bufferingSource != null) {
|
if (bufferingSource != null) {
|
||||||
bufferingSource.nextSource = newSource;
|
bufferingSource.nextSource = newSource;
|
||||||
|
bufferingSourceOffsetUs += bufferingSource.sampleSource.getDurationUs();
|
||||||
}
|
}
|
||||||
bufferingSource = newSource;
|
bufferingSource = newSource;
|
||||||
}
|
}
|
||||||
@ -637,23 +637,14 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
bufferingSource.selectTracks(result.first, result.second, startPositionUs);
|
bufferingSource.selectTracks(result.first, result.second, startPositionUs);
|
||||||
if (playingSource == null) {
|
if (playingSource == null) {
|
||||||
// This is the first prepared source, so start playing it.
|
// This is the first prepared source, so start playing it.
|
||||||
sourceOffsetUs = 0;
|
setPlayingSource(bufferingSource, 0);
|
||||||
setPlayingSource(bufferingSource);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferingSource.hasEnabledTracks) {
|
if (bufferingSource.hasEnabledTracks) {
|
||||||
long bufferingPositionUs;
|
long sourcePositionUs = internalPositionUs - bufferingSourceOffsetUs;
|
||||||
if (bufferingSource == playingSource) {
|
bufferingSource.sampleSource.continueBuffering(sourcePositionUs);
|
||||||
bufferingPositionUs = internalPositionUs - sourceOffsetUs;
|
|
||||||
} else if (bufferingSource == readingSource) {
|
|
||||||
// TODO[playlists]: Make sure continueBuffering supports a negative downstream position.
|
|
||||||
bufferingPositionUs = internalPositionUs - nextSourceOffsetUs;
|
|
||||||
} else {
|
|
||||||
bufferingPositionUs = 0;
|
|
||||||
}
|
|
||||||
bufferingSource.sampleSource.continueBuffering(bufferingPositionUs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,22 +660,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (playingSourceEndPositionUs == C.UNSET_TIME_US) {
|
if (playingSourceEndPositionUs == C.UNSET_TIME_US) {
|
||||||
// Calculate the next source's start position in the timeline.
|
playingSourceEndPositionUs = sourceOffsetUs + playingSource.sampleSource.getDurationUs();
|
||||||
long playingSourceDurationUs = playingSource.sampleSource.getDurationUs();
|
|
||||||
if (playingSourceDurationUs == C.UNSET_TIME_US) {
|
|
||||||
// The duration of the current source is unknown, so use the maximum rendered timestamp
|
|
||||||
// plus a small extra offset to make sure that renderers don't read two buffers with the
|
|
||||||
// same timestamp.
|
|
||||||
playingSourceEndPositionUs = 0;
|
|
||||||
for (TrackRenderer renderer : enabledRenderers) {
|
|
||||||
playingSourceEndPositionUs =
|
|
||||||
Math.max(playingSourceEndPositionUs, renderer.getMaximumTimeUs());
|
|
||||||
}
|
|
||||||
nextSourceOffsetUs = playingSourceEndPositionUs + 10000;
|
|
||||||
} else {
|
|
||||||
playingSourceEndPositionUs = sourceOffsetUs + playingSourceDurationUs;
|
|
||||||
nextSourceOffsetUs = playingSourceEndPositionUs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT
|
if (sourceCount != SampleSourceProvider.UNKNOWN_SOURCE_COUNT
|
||||||
&& readingSource.index == sourceCount - 1) {
|
&& readingSource.index == sourceCount - 1) {
|
||||||
@ -694,9 +670,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
}
|
}
|
||||||
readingSource = null;
|
readingSource = null;
|
||||||
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
||||||
return;
|
} else if (playingSource.nextSource != null && playingSource.nextSource.prepared) {
|
||||||
}
|
|
||||||
if (playingSource.nextSource != null && playingSource.nextSource.prepared) {
|
|
||||||
readingSource = playingSource.nextSource;
|
readingSource = playingSource.nextSource;
|
||||||
// Suppress reading a reset so that the transition can be seamless.
|
// Suppress reading a reset so that the transition can be seamless.
|
||||||
readingSource.sampleSource.readReset();
|
readingSource.sampleSource.readReset();
|
||||||
@ -713,27 +687,26 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
for (int j = 0; j < formats.length; j++) {
|
for (int j = 0; j < formats.length; j++) {
|
||||||
formats[j] = groups.get(selection.group).getFormat(selection.getTrack(j));
|
formats[j] = groups.get(selection.group).getFormat(selection.getTrack(j));
|
||||||
}
|
}
|
||||||
renderer.replaceTrackStream(formats, readingSource.trackStreams[i], nextSourceOffsetUs);
|
renderer.replaceTrackStream(formats, readingSource.trackStreams[i],
|
||||||
|
playingSourceEndPositionUs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isReady(long positionUs) {
|
public boolean isReady() {
|
||||||
return playingSourceEndPositionUs == C.UNSET_TIME_US
|
return playingSourceEndPositionUs == C.UNSET_TIME_US
|
||||||
|| positionUs < playingSourceEndPositionUs || playingSource.nextSource != null;
|
|| internalPositionUs < playingSourceEndPositionUs || playingSource.nextSource != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SampleSource getSampleSource(long positionUs) throws ExoPlaybackException {
|
public SampleSource getSampleSource() throws ExoPlaybackException {
|
||||||
if (playingSource == null) {
|
if (playingSource == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (readingSource != playingSource && playingSourceEndPositionUs != C.UNSET_TIME_US
|
if (readingSource != playingSource && playingSourceEndPositionUs != C.UNSET_TIME_US
|
||||||
&& positionUs >= playingSourceEndPositionUs) {
|
&& internalPositionUs >= playingSourceEndPositionUs) {
|
||||||
// Renderers are playing the next source, so update the timeline.
|
|
||||||
playingSource.release();
|
playingSource.release();
|
||||||
sourceOffsetUs = nextSourceOffsetUs;
|
setPlayingSource(readingSource, playingSourceEndPositionUs);
|
||||||
setPlayingSource(readingSource);
|
|
||||||
}
|
}
|
||||||
return playingSource.sampleSource;
|
return playingSource.sampleSource;
|
||||||
}
|
}
|
||||||
@ -753,8 +726,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
if (newPlayingSource != null) {
|
if (newPlayingSource != null) {
|
||||||
nextSourceIndex = sourceIndex + 1;
|
nextSourceIndex = sourceIndex + 1;
|
||||||
newPlayingSource.nextSource = null;
|
newPlayingSource.nextSource = null;
|
||||||
setPlayingSource(newPlayingSource);
|
setPlayingSource(newPlayingSource, sourceOffsetUs);
|
||||||
bufferingSource = playingSource;
|
bufferingSource = playingSource;
|
||||||
|
bufferingSourceOffsetUs = sourceOffsetUs;
|
||||||
if (playingSource.hasEnabledTracks) {
|
if (playingSource.hasEnabledTracks) {
|
||||||
sampleSource.seekToUs(sourcePositionUs);
|
sampleSource.seekToUs(sourcePositionUs);
|
||||||
}
|
}
|
||||||
@ -762,6 +736,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
playingSource = null;
|
playingSource = null;
|
||||||
readingSource = null;
|
readingSource = null;
|
||||||
bufferingSource = null;
|
bufferingSource = null;
|
||||||
|
bufferingSourceOffsetUs = 0;
|
||||||
durationUs = C.UNSET_TIME_US;
|
durationUs = C.UNSET_TIME_US;
|
||||||
sampleSource = null;
|
sampleSource = null;
|
||||||
// Set the next source index so that the required source is created in updateSources.
|
// Set the next source index so that the required source is created in updateSources.
|
||||||
@ -803,6 +778,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
bufferingSource = playingSource;
|
bufferingSource = playingSource;
|
||||||
nextSourceIndex = playingSource.index + 1;
|
nextSourceIndex = playingSource.index + 1;
|
||||||
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
||||||
|
bufferingSourceOffsetUs = sourceOffsetUs;
|
||||||
|
|
||||||
// Update the track selection for the playing source.
|
// Update the track selection for the playing source.
|
||||||
Pair<TrackSelectionArray, Object> result =
|
Pair<TrackSelectionArray, Object> result =
|
||||||
@ -842,10 +818,10 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
readingSource = null;
|
readingSource = null;
|
||||||
bufferingSource = null;
|
bufferingSource = null;
|
||||||
durationUs = C.UNSET_TIME_US;
|
durationUs = C.UNSET_TIME_US;
|
||||||
|
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
||||||
nextSourceIndex = 0;
|
nextSourceIndex = 0;
|
||||||
sourceOffsetUs = 0;
|
sourceOffsetUs = 0;
|
||||||
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
bufferingSourceOffsetUs = 0;
|
||||||
nextSourceOffsetUs = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -864,8 +840,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPlayingSource(Source source) throws ExoPlaybackException {
|
private void setPlayingSource(Source source, long offsetUs) throws ExoPlaybackException {
|
||||||
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
sourceOffsetUs = offsetUs;
|
||||||
durationUs = source.sampleSource.getDurationUs();
|
durationUs = source.sampleSource.getDurationUs();
|
||||||
|
|
||||||
// Disable/enable renderers for the new source.
|
// Disable/enable renderers for the new source.
|
||||||
@ -875,6 +851,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
}
|
}
|
||||||
readingSource = source;
|
readingSource = source;
|
||||||
playingSource = source;
|
playingSource = source;
|
||||||
|
playingSourceEndPositionUs = C.UNSET_TIME_US;
|
||||||
enableRenderers(source.trackSelections, enabledRendererCount);
|
enableRenderers(source.trackSelections, enabledRendererCount);
|
||||||
|
|
||||||
// Update the timeline position for the new source index.
|
// Update the timeline position for the new source index.
|
||||||
|
@ -37,7 +37,10 @@ public interface SampleSource {
|
|||||||
boolean prepare(long positionUs) throws IOException;
|
boolean prepare(long positionUs) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the duration of the source.
|
* Returns the duration of the source in microseconds, or {@link C#UNSET_TIME_US} if not known.
|
||||||
|
* <p>
|
||||||
|
* If {@link #getBufferedPositionUs()} returns {@link C#END_OF_SOURCE_US}, the duration is
|
||||||
|
* guaranteed to be known.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should only be called after the source has been prepared.
|
* This method should only be called after the source has been prepared.
|
||||||
*
|
*
|
||||||
|
@ -109,7 +109,6 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||||||
private int state;
|
private int state;
|
||||||
private TrackStream stream;
|
private TrackStream stream;
|
||||||
private long streamOffsetUs;
|
private long streamOffsetUs;
|
||||||
private long maximumTimeUs;
|
|
||||||
private boolean readEndOfStream;
|
private boolean readEndOfStream;
|
||||||
private boolean streamIsFinal;
|
private boolean streamIsFinal;
|
||||||
|
|
||||||
@ -235,7 +234,6 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||||||
*/
|
*/
|
||||||
/* package */ final void reset(long positionUs) throws ExoPlaybackException {
|
/* package */ final void reset(long positionUs) throws ExoPlaybackException {
|
||||||
streamIsFinal = false;
|
streamIsFinal = false;
|
||||||
maximumTimeUs = C.UNSET_TIME_US;
|
|
||||||
onReset(positionUs, false);
|
onReset(positionUs, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,14 +258,6 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||||||
return readEndOfStream;
|
return readEndOfStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum buffer timestamp read from the stream since the last reset, or
|
|
||||||
* {@link C#UNSET_TIME_US} if no buffers have been read.
|
|
||||||
*/
|
|
||||||
/* package */ final long getMaximumTimeUs() {
|
|
||||||
return maximumTimeUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals to the renderer that the current {@link TrackStream} will be the final one supplied
|
* Signals to the renderer that the current {@link TrackStream} will be the final one supplied
|
||||||
* before it is next disabled or reset.
|
* before it is next disabled or reset.
|
||||||
@ -372,9 +362,6 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||||||
return streamIsFinal ? TrackStream.BUFFER_READ : TrackStream.NOTHING_READ;
|
return streamIsFinal ? TrackStream.BUFFER_READ : TrackStream.NOTHING_READ;
|
||||||
}
|
}
|
||||||
buffer.timeUs += streamOffsetUs;
|
buffer.timeUs += streamOffsetUs;
|
||||||
if (buffer.timeUs > maximumTimeUs) {
|
|
||||||
maximumTimeUs = buffer.timeUs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,12 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
|
|
||||||
private static final int MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA = -1;
|
private static final int MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the source's duration is unknown, it is calculated by adding this value to the largest
|
||||||
|
* sample timestamp seen when buffering completes.
|
||||||
|
*/
|
||||||
|
private static final long DEFAULT_LAST_SAMPLE_DURATION_US = 10000;
|
||||||
|
|
||||||
// Lazily initialized default extractor classes in priority order.
|
// Lazily initialized default extractor classes in priority order.
|
||||||
private static List<Class<? extends Extractor>> defaultExtractorClasses;
|
private static List<Class<? extends Extractor>> defaultExtractorClasses;
|
||||||
|
|
||||||
@ -397,11 +403,7 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
} else if (isPendingReset()) {
|
} else if (isPendingReset()) {
|
||||||
return pendingResetPositionUs;
|
return pendingResetPositionUs;
|
||||||
} else {
|
} else {
|
||||||
long largestQueuedTimestampUs = Long.MIN_VALUE;
|
long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
|
||||||
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
|
||||||
largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs,
|
|
||||||
sampleQueue.getLargestQueuedTimestampUs());
|
|
||||||
}
|
|
||||||
return largestQueuedTimestampUs == Long.MIN_VALUE ? lastSeekPositionUs
|
return largestQueuedTimestampUs == Long.MIN_VALUE ? lastSeekPositionUs
|
||||||
: largestQueuedTimestampUs;
|
: largestQueuedTimestampUs;
|
||||||
}
|
}
|
||||||
@ -459,6 +461,11 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
long loadDurationMs) {
|
long loadDurationMs) {
|
||||||
copyLengthFromLoader(loadable);
|
copyLengthFromLoader(loadable);
|
||||||
loadingFinished = true;
|
loadingFinished = true;
|
||||||
|
if (durationUs == C.UNSET_TIME_US) {
|
||||||
|
long largestQueuedTimestampUs = getLargestQueuedTimestampUs();
|
||||||
|
durationUs = largestQueuedTimestampUs == Long.MIN_VALUE ? 0
|
||||||
|
: largestQueuedTimestampUs + DEFAULT_LAST_SAMPLE_DURATION_US;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -579,6 +586,15 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
return extractedSamplesCount;
|
return extractedSamplesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getLargestQueuedTimestampUs() {
|
||||||
|
long largestQueuedTimestampUs = Long.MIN_VALUE;
|
||||||
|
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
||||||
|
largestQueuedTimestampUs = Math.max(largestQueuedTimestampUs,
|
||||||
|
sampleQueue.getLargestQueuedTimestampUs());
|
||||||
|
}
|
||||||
|
return largestQueuedTimestampUs;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean haveFormatsForAllTracks() {
|
private boolean haveFormatsForAllTracks() {
|
||||||
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
for (DefaultTrackOutput sampleQueue : sampleQueues) {
|
||||||
if (sampleQueue.getUpstreamFormat() == null) {
|
if (sampleQueue.getUpstreamFormat() == null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user