@Override public TrackOutput track(int id) { InternalTrackOutput sampleQueue = sampleQueues.get(id); if (sampleQueue == null) { sampleQueue = new InternalTrackOutput(allocator); sampleQueues.put(id, sampleQueue); } return sampleQueue; }
private void clearState() { for (int i = 0; i < sampleQueues.size(); i++) { sampleQueues.valueAt(i).clear(); } loadable = null; currentLoadableException = null; currentLoadableExceptionCount = 0; }
private void discardSamplesForDisabledTracks(long timeUs) { for (int i = 0; i < trackEnabledStates.length; i++) { if (!trackEnabledStates[i]) { sampleQueues.valueAt(i).discardUntil(timeUs); } } }
@Override public boolean prepare(long positionUs) { if (prepared) { return true; } if (loader == null) { loader = new Loader("Loader:ExtractorSampleSource"); } maybeStartLoading(); if (seekMap != null && tracksBuilt && haveFormatsForAllTracks()) { int trackCount = sampleQueues.size(); trackEnabledStates = new boolean[trackCount]; pendingDiscontinuities = new boolean[trackCount]; pendingMediaFormat = new boolean[trackCount]; mediaFormats = new MediaFormat[trackCount]; maxTrackDurationUs = C.UNKNOWN_TIME_US; for (int i = 0; i < trackCount; i++) { MediaFormat format = sampleQueues.valueAt(i).getFormat(); mediaFormats[i] = format; if (format.durationUs != C.UNKNOWN_TIME_US && format.durationUs > maxTrackDurationUs) { maxTrackDurationUs = format.durationUs; } } prepared = true; return true; } return false; }
@Override public void seekToUs(long positionUs) { Assertions.checkState(prepared); Assertions.checkState(enabledTrackCount > 0); // Treat all seeks into non-seekable media as being to t=0. positionUs = !seekMap.isSeekable() ? 0 : positionUs; long currentPositionUs = isPendingReset() ? pendingResetPositionUs : downstreamPositionUs; downstreamPositionUs = positionUs; lastSeekPositionUs = positionUs; if (currentPositionUs == positionUs) { return; } // If we're not pending a reset, see if we can seek within the sample queues. boolean seekInsideBuffer = !isPendingReset(); for (int i = 0; seekInsideBuffer && i < sampleQueues.size(); i++) { seekInsideBuffer &= sampleQueues.valueAt(i).skipToKeyframeBefore(positionUs); } // If we failed to seek within the sample queues, we need to restart. if (!seekInsideBuffer) { restartFrom(positionUs); } // Either way, we need to send discontinuities to the downstream components. for (int i = 0; i < pendingDiscontinuities.length; i++) { pendingDiscontinuities[i] = true; } }
@Override public long getBufferedPositionUs() { if (loadingFinished) { return TrackRenderer.END_OF_TRACK_US; } else if (isPendingReset()) { return pendingResetPositionUs; } else { long largestParsedTimestampUs = Long.MIN_VALUE; for (int i = 0; i < sampleQueues.size(); i++) { largestParsedTimestampUs = Math.max(largestParsedTimestampUs, sampleQueues.valueAt(i).getLargestParsedTimestampUs()); } return largestParsedTimestampUs == Long.MIN_VALUE ? downstreamPositionUs : largestParsedTimestampUs; } }
@Override public boolean continueBuffering(int track, long playbackPositionUs) { Assertions.checkState(prepared); Assertions.checkState(trackEnabledStates[track]); downstreamPositionUs = playbackPositionUs; discardSamplesForDisabledTracks(downstreamPositionUs); if (loadingFinished) { return true; } maybeStartLoading(); if (isPendingReset()) { return false; } return !sampleQueues.valueAt(track).isEmpty(); }
private boolean haveFormatsForAllTracks() { for (int i = 0; i < sampleQueues.size(); i++) { if (!sampleQueues.valueAt(i).hasFormat()) { return false; } } return true; }