Simple method re-ordering of SampleSource implementations.
The only change that's not re-ordering is to add a Util method for usToMs to replace the ones in the HLS and Chunk sources. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=118775359
This commit is contained in:
parent
292b2402e6
commit
9c2a971109
@ -119,6 +119,8 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
headers = null;
|
headers = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SampleSource implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean prepare(long positionUs) throws IOException {
|
public boolean prepare(long positionUs) throws IOException {
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
@ -156,11 +158,6 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
return tracks;
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void continueBuffering(long positionUs) {
|
|
||||||
// MediaExtractor takes care of buffering. Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
|
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
|
||||||
List<TrackSelection> newSelections, long positionUs) {
|
List<TrackSelection> newSelections, long positionUs) {
|
||||||
@ -194,6 +191,44 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
return newStreams;
|
return newStreams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void continueBuffering(long positionUs) {
|
||||||
|
// MediaExtractor takes care of buffering. Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekToUs(long positionUs) {
|
||||||
|
if (enabledTrackCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seekToUsInternal(positionUs, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBufferedPositionUs() {
|
||||||
|
if (enabledTrackCount == 0) {
|
||||||
|
return C.END_OF_SOURCE_US;
|
||||||
|
}
|
||||||
|
|
||||||
|
long bufferedDurationUs = extractor.getCachedDuration();
|
||||||
|
if (bufferedDurationUs == -1) {
|
||||||
|
return C.UNKNOWN_TIME_US;
|
||||||
|
}
|
||||||
|
|
||||||
|
long sampleTime = extractor.getSampleTime();
|
||||||
|
return sampleTime == -1 ? C.END_OF_SOURCE_US : sampleTime + bufferedDurationUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
if (extractor != null) {
|
||||||
|
extractor.release();
|
||||||
|
extractor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackStream methods.
|
||||||
|
|
||||||
/* package */ long readReset(int track) {
|
/* package */ long readReset(int track) {
|
||||||
if (pendingResets[track]) {
|
if (pendingResets[track]) {
|
||||||
pendingResets[track] = false;
|
pendingResets[track] = false;
|
||||||
@ -242,36 +277,7 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// Internal methods.
|
||||||
public void seekToUs(long positionUs) {
|
|
||||||
if (enabledTrackCount == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seekToUsInternal(positionUs, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getBufferedPositionUs() {
|
|
||||||
if (enabledTrackCount == 0) {
|
|
||||||
return C.END_OF_SOURCE_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
long bufferedDurationUs = extractor.getCachedDuration();
|
|
||||||
if (bufferedDurationUs == -1) {
|
|
||||||
return C.UNKNOWN_TIME_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
long sampleTime = extractor.getSampleTime();
|
|
||||||
return sampleTime == -1 ? C.END_OF_SOURCE_US : sampleTime + bufferedDurationUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
if (extractor != null) {
|
|
||||||
extractor.release();
|
|
||||||
extractor = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(18)
|
@TargetApi(18)
|
||||||
private DrmInitData getDrmInitDataV18() {
|
private DrmInitData getDrmInitDataV18() {
|
||||||
|
@ -80,6 +80,11 @@ public final class MultiSampleSource implements SampleSource {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDurationUs() {
|
||||||
|
return durationUs;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TrackGroupArray getTrackGroups() {
|
public TrackGroupArray getTrackGroups() {
|
||||||
return trackGroups;
|
return trackGroups;
|
||||||
@ -118,18 +123,6 @@ public final class MultiSampleSource implements SampleSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekToUs(long positionUs) {
|
|
||||||
for (SampleSource source : enabledSources) {
|
|
||||||
source.seekToUs(positionUs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getDurationUs() {
|
|
||||||
return durationUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getBufferedPositionUs() {
|
public long getBufferedPositionUs() {
|
||||||
long bufferedPositionUs = durationUs != C.UNKNOWN_TIME_US ? durationUs : Long.MAX_VALUE;
|
long bufferedPositionUs = durationUs != C.UNKNOWN_TIME_US ? durationUs : Long.MAX_VALUE;
|
||||||
@ -146,6 +139,13 @@ public final class MultiSampleSource implements SampleSource {
|
|||||||
return bufferedPositionUs == Long.MAX_VALUE ? C.UNKNOWN_TIME_US : bufferedPositionUs;
|
return bufferedPositionUs == Long.MAX_VALUE ? C.UNKNOWN_TIME_US : bufferedPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekToUs(long positionUs) {
|
||||||
|
for (SampleSource source : enabledSources) {
|
||||||
|
source.seekToUs(positionUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
for (SampleSource source : sources) {
|
for (SampleSource source : sources) {
|
||||||
@ -153,6 +153,8 @@ public final class MultiSampleSource implements SampleSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal methods.
|
||||||
|
|
||||||
private int selectTracks(SampleSource source, List<TrackStream> allOldStreams,
|
private int selectTracks(SampleSource source, List<TrackStream> allOldStreams,
|
||||||
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
|
||||||
// Get the subset of the old streams for the source.
|
// Get the subset of the old streams for the source.
|
||||||
|
@ -104,10 +104,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
|||||||
sampleData = new byte[INITIAL_SAMPLE_SIZE];
|
sampleData = new byte[INITIAL_SAMPLE_SIZE];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// SampleSource implementation.
|
||||||
public void maybeThrowError() throws IOException {
|
|
||||||
loader.maybeThrowError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean prepare(long positionUs) {
|
public boolean prepare(long positionUs) {
|
||||||
@ -152,11 +149,37 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
|||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBufferedPositionUs() {
|
||||||
|
return loadingFinished ? C.END_OF_SOURCE_US : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekToUs(long positionUs) {
|
||||||
|
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
||||||
|
pendingResetPositionUs = positionUs;
|
||||||
|
streamState = STREAM_STATE_SEND_SAMPLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
streamState = STREAM_STATE_END_OF_STREAM;
|
||||||
|
loader.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackStream implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return loadingFinished;
|
return loadingFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void maybeThrowError() throws IOException {
|
||||||
|
loader.maybeThrowError();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long readReset() {
|
public long readReset() {
|
||||||
long resetPositionUs = pendingResetPositionUs;
|
long resetPositionUs = pendingResetPositionUs;
|
||||||
@ -189,25 +212,6 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekToUs(long positionUs) {
|
|
||||||
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
|
||||||
pendingResetPositionUs = positionUs;
|
|
||||||
streamState = STREAM_STATE_SEND_SAMPLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getBufferedPositionUs() {
|
|
||||||
return loadingFinished ? C.END_OF_SOURCE_US : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
streamState = STREAM_STATE_END_OF_STREAM;
|
|
||||||
loader.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loader.Callback implementation.
|
// Loader.Callback implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -259,7 +263,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private methods.
|
// Internal methods.
|
||||||
|
|
||||||
private void maybeStartLoading() {
|
private void maybeStartLoading() {
|
||||||
if (loadingFinished || streamState == STREAM_STATE_END_OF_STREAM || loader.isLoading()) {
|
if (loadingFinished || streamState == STREAM_STATE_END_OF_STREAM || loader.isLoading()) {
|
||||||
|
@ -29,6 +29,7 @@ import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
|||||||
import com.google.android.exoplayer.upstream.Loader;
|
import com.google.android.exoplayer.upstream.Loader;
|
||||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@ -139,6 +140,8 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
pendingResetPositionUs = NO_RESET_PENDING;
|
pendingResetPositionUs = NO_RESET_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SampleSource implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean prepare(long positionUs) throws IOException {
|
public boolean prepare(long positionUs) throws IOException {
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
@ -224,11 +227,62 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
maybeStartLoading();
|
maybeStartLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBufferedPositionUs() {
|
||||||
|
if (loadingFinished) {
|
||||||
|
return C.END_OF_SOURCE_US;
|
||||||
|
} else if (isPendingReset()) {
|
||||||
|
return pendingResetPositionUs;
|
||||||
|
} else {
|
||||||
|
long largestParsedTimestampUs = sampleQueue.getLargestParsedTimestampUs();
|
||||||
|
return largestParsedTimestampUs == Long.MIN_VALUE ? downstreamPositionUs
|
||||||
|
: largestParsedTimestampUs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekToUs(long positionUs) {
|
||||||
|
downstreamPositionUs = positionUs;
|
||||||
|
lastSeekPositionUs = positionUs;
|
||||||
|
// If we're not pending a reset, see if we can seek within the sample queue.
|
||||||
|
boolean seekInsideBuffer = !isPendingReset() && sampleQueue.skipToKeyframeBefore(positionUs);
|
||||||
|
if (seekInsideBuffer) {
|
||||||
|
// We succeeded. All we need to do is discard any chunks that we've moved past.
|
||||||
|
boolean haveSamples = !sampleQueue.isEmpty();
|
||||||
|
while (haveSamples && mediaChunks.size() > 1
|
||||||
|
&& mediaChunks.get(1).getFirstSampleIndex() <= sampleQueue.getReadIndex()) {
|
||||||
|
mediaChunks.removeFirst();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We failed, and need to restart.
|
||||||
|
restartFrom(positionUs);
|
||||||
|
}
|
||||||
|
// Either way, we need to send a discontinuity to the downstream components.
|
||||||
|
pendingReset = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
prepared = false;
|
||||||
|
trackEnabled = false;
|
||||||
|
loader.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackStream implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReady() {
|
public boolean isReady() {
|
||||||
return loadingFinished || !sampleQueue.isEmpty();
|
return loadingFinished || !sampleQueue.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void maybeThrowError() throws IOException {
|
||||||
|
loader.maybeThrowError();
|
||||||
|
if (currentLoadableHolder.chunk == null) {
|
||||||
|
chunkSource.maybeThrowError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long readReset() {
|
public long readReset() {
|
||||||
if (pendingReset) {
|
if (pendingReset) {
|
||||||
@ -287,55 +341,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
return NOTHING_READ;
|
return NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekToUs(long positionUs) {
|
|
||||||
downstreamPositionUs = positionUs;
|
|
||||||
lastSeekPositionUs = positionUs;
|
|
||||||
// If we're not pending a reset, see if we can seek within the sample queue.
|
|
||||||
boolean seekInsideBuffer = !isPendingReset() && sampleQueue.skipToKeyframeBefore(positionUs);
|
|
||||||
if (seekInsideBuffer) {
|
|
||||||
// We succeeded. All we need to do is discard any chunks that we've moved past.
|
|
||||||
boolean haveSamples = !sampleQueue.isEmpty();
|
|
||||||
while (haveSamples && mediaChunks.size() > 1
|
|
||||||
&& mediaChunks.get(1).getFirstSampleIndex() <= sampleQueue.getReadIndex()) {
|
|
||||||
mediaChunks.removeFirst();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We failed, and need to restart.
|
|
||||||
restartFrom(positionUs);
|
|
||||||
}
|
|
||||||
// Either way, we need to send a discontinuity to the downstream components.
|
|
||||||
pendingReset = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void maybeThrowError() throws IOException {
|
|
||||||
loader.maybeThrowError();
|
|
||||||
if (currentLoadableHolder.chunk == null) {
|
|
||||||
chunkSource.maybeThrowError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getBufferedPositionUs() {
|
|
||||||
if (loadingFinished) {
|
|
||||||
return C.END_OF_SOURCE_US;
|
|
||||||
} else if (isPendingReset()) {
|
|
||||||
return pendingResetPositionUs;
|
|
||||||
} else {
|
|
||||||
long largestParsedTimestampUs = sampleQueue.getLargestParsedTimestampUs();
|
|
||||||
return largestParsedTimestampUs == Long.MIN_VALUE ? downstreamPositionUs
|
|
||||||
: largestParsedTimestampUs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
prepared = false;
|
|
||||||
trackEnabled = false;
|
|
||||||
loader.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loadable.Callback implementation.
|
// Loadable.Callback implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -396,6 +401,8 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Internal methods.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a sample has been read. Can be used to perform any modifications necessary before
|
* Called when a sample has been read. Can be used to perform any modifications necessary before
|
||||||
* the sample is returned.
|
* the sample is returned.
|
||||||
@ -530,10 +537,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
return pendingResetPositionUs != NO_RESET_PENDING;
|
return pendingResetPositionUs != NO_RESET_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final long usToMs(long timeUs) {
|
|
||||||
return timeUs / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadStarted(final long length, final int type, final int trigger,
|
private void notifyLoadStarted(final long length, final int type, final int trigger,
|
||||||
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
||||||
if (eventHandler != null && eventListener != null) {
|
if (eventHandler != null && eventListener != null) {
|
||||||
@ -541,7 +544,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onLoadStarted(eventSourceId, length, type, trigger, format,
|
eventListener.onLoadStarted(eventSourceId, length, type, trigger, format,
|
||||||
usToMs(mediaStartTimeUs), usToMs(mediaEndTimeUs));
|
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -555,7 +558,8 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onLoadCompleted(eventSourceId, bytesLoaded, type, trigger, format,
|
eventListener.onLoadCompleted(eventSourceId, bytesLoaded, type, trigger, format,
|
||||||
usToMs(mediaStartTimeUs), usToMs(mediaEndTimeUs), elapsedRealtimeMs, loadDurationMs);
|
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs), elapsedRealtimeMs,
|
||||||
|
loadDurationMs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -588,8 +592,8 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
eventHandler.post(new Runnable() {
|
eventHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onUpstreamDiscarded(eventSourceId, usToMs(mediaStartTimeUs),
|
eventListener.onUpstreamDiscarded(eventSourceId, Util.usToMs(mediaStartTimeUs),
|
||||||
usToMs(mediaEndTimeUs));
|
Util.usToMs(mediaEndTimeUs));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -602,7 +606,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
|
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
|
||||||
usToMs(positionUs));
|
Util.usToMs(positionUs));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -329,6 +329,8 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
pendingResetPositionUs = NO_RESET_PENDING;
|
pendingResetPositionUs = NO_RESET_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SampleSource implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean prepare(long positionUs) throws IOException {
|
public boolean prepare(long positionUs) throws IOException {
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
@ -418,12 +420,49 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
maybeStartLoading();
|
maybeStartLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBufferedPositionUs() {
|
||||||
|
if (loadingFinished) {
|
||||||
|
return C.END_OF_SOURCE_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 void seekToUs(long positionUs) {
|
||||||
|
seekToInternal(positionUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
enabledTrackCount = 0;
|
||||||
|
loader.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackStream methods.
|
||||||
|
|
||||||
/* package */ boolean isReady(int track) {
|
/* package */ boolean isReady(int track) {
|
||||||
Assertions.checkState(trackEnabledStates[track]);
|
Assertions.checkState(trackEnabledStates[track]);
|
||||||
return !sampleQueues.valueAt(track).isEmpty();
|
return !sampleQueues.valueAt(track).isEmpty();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* package */ void maybeThrowError() throws IOException {
|
||||||
|
if (fatalException != null) {
|
||||||
|
throw fatalException;
|
||||||
|
}
|
||||||
|
loader.maybeThrowError();
|
||||||
|
}
|
||||||
|
|
||||||
/* package */ long readReset(int track) {
|
/* package */ long readReset(int track) {
|
||||||
if (pendingResets[track]) {
|
if (pendingResets[track]) {
|
||||||
pendingResets[track] = false;
|
pendingResets[track] = false;
|
||||||
@ -466,58 +505,6 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void maybeThrowError() throws IOException {
|
|
||||||
if (fatalException != null) {
|
|
||||||
throw fatalException;
|
|
||||||
}
|
|
||||||
loader.maybeThrowError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekToUs(long positionUs) {
|
|
||||||
seekToInternal(positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void seekToInternal(long positionUs) {
|
|
||||||
// Treat all seeks into non-seekable media as being to t=0.
|
|
||||||
positionUs = !seekMap.isSeekable() ? 0 : positionUs;
|
|
||||||
lastSeekPositionUs = positionUs;
|
|
||||||
downstreamPositionUs = positionUs;
|
|
||||||
Arrays.fill(pendingResets, true);
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getBufferedPositionUs() {
|
|
||||||
if (loadingFinished) {
|
|
||||||
return C.END_OF_SOURCE_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 void release() {
|
|
||||||
enabledTrackCount = 0;
|
|
||||||
loader.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loader.Callback implementation.
|
// Loader.Callback implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -575,7 +562,24 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
|
|||||||
this.drmInitData = drmInitData;
|
this.drmInitData = drmInitData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal stuff.
|
// Internal methods.
|
||||||
|
|
||||||
|
private void seekToInternal(long positionUs) {
|
||||||
|
// Treat all seeks into non-seekable media as being to t=0.
|
||||||
|
positionUs = !seekMap.isSeekable() ? 0 : positionUs;
|
||||||
|
lastSeekPositionUs = positionUs;
|
||||||
|
downstreamPositionUs = positionUs;
|
||||||
|
Arrays.fill(pendingResets, true);
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void restartFrom(long positionUs) {
|
private void restartFrom(long positionUs) {
|
||||||
pendingResetPositionUs = positionUs;
|
pendingResetPositionUs = positionUs;
|
||||||
|
@ -32,6 +32,7 @@ import com.google.android.exoplayer.upstream.Loader;
|
|||||||
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
import com.google.android.exoplayer.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer.util.Assertions;
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
import com.google.android.exoplayer.util.MimeTypes;
|
import com.google.android.exoplayer.util.MimeTypes;
|
||||||
|
import com.google.android.exoplayer.util.Util;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@ -128,6 +129,8 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
chunkOperationHolder = new ChunkOperationHolder();
|
chunkOperationHolder = new ChunkOperationHolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SampleSource implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean prepare(long positionUs) throws IOException {
|
public boolean prepare(long positionUs) throws IOException {
|
||||||
if (prepared) {
|
if (prepared) {
|
||||||
@ -245,6 +248,47 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
maybeStartLoading();
|
maybeStartLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getBufferedPositionUs() {
|
||||||
|
if (isPendingReset()) {
|
||||||
|
return pendingResetPositionUs;
|
||||||
|
} else if (loadingFinished) {
|
||||||
|
return C.END_OF_SOURCE_US;
|
||||||
|
} else {
|
||||||
|
long bufferedPositionUs = extractors.getLast().getLargestParsedTimestampUs();
|
||||||
|
if (extractors.size() > 1) {
|
||||||
|
// When adapting from one format to the next, the penultimate extractor may have the largest
|
||||||
|
// parsed timestamp (e.g. if the last extractor hasn't parsed any timestamps yet).
|
||||||
|
bufferedPositionUs = Math.max(bufferedPositionUs,
|
||||||
|
extractors.get(extractors.size() - 2).getLargestParsedTimestampUs());
|
||||||
|
}
|
||||||
|
if (previousTsLoadable != null) {
|
||||||
|
// Buffered position should be at least as large as the end time of the previously loaded
|
||||||
|
// chunk.
|
||||||
|
bufferedPositionUs = Math.max(previousTsLoadable.endTimeUs, bufferedPositionUs);
|
||||||
|
}
|
||||||
|
return bufferedPositionUs == Long.MIN_VALUE ? downstreamPositionUs
|
||||||
|
: bufferedPositionUs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekToUs(long positionUs) {
|
||||||
|
seekToInternal(positionUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
enabledTrackCount = 0;
|
||||||
|
if (loadControlRegistered) {
|
||||||
|
loadControl.unregister(this);
|
||||||
|
loadControlRegistered = false;
|
||||||
|
}
|
||||||
|
loader.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TrackStream methods.
|
||||||
|
|
||||||
/* package */ boolean isReady(int group) {
|
/* package */ boolean isReady(int group) {
|
||||||
Assertions.checkState(groupEnabledStates[group]);
|
Assertions.checkState(groupEnabledStates[group]);
|
||||||
if (loadingFinished) {
|
if (loadingFinished) {
|
||||||
@ -265,6 +309,13 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* package */ void maybeThrowError() throws IOException {
|
||||||
|
loader.maybeThrowError();
|
||||||
|
if (currentLoadable == null) {
|
||||||
|
chunkSource.maybeThrowError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* package */ long readReset(int group) {
|
/* package */ long readReset(int group) {
|
||||||
if (pendingResets[group]) {
|
if (pendingResets[group]) {
|
||||||
pendingResets[group] = false;
|
pendingResets[group] = false;
|
||||||
@ -327,52 +378,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
return TrackStream.NOTHING_READ;
|
return TrackStream.NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void maybeThrowError() throws IOException {
|
|
||||||
loader.maybeThrowError();
|
|
||||||
if (currentLoadable == null) {
|
|
||||||
chunkSource.maybeThrowError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seekToUs(long positionUs) {
|
|
||||||
seekToInternal(positionUs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getBufferedPositionUs() {
|
|
||||||
if (isPendingReset()) {
|
|
||||||
return pendingResetPositionUs;
|
|
||||||
} else if (loadingFinished) {
|
|
||||||
return C.END_OF_SOURCE_US;
|
|
||||||
} else {
|
|
||||||
long bufferedPositionUs = extractors.getLast().getLargestParsedTimestampUs();
|
|
||||||
if (extractors.size() > 1) {
|
|
||||||
// When adapting from one format to the next, the penultimate extractor may have the largest
|
|
||||||
// parsed timestamp (e.g. if the last extractor hasn't parsed any timestamps yet).
|
|
||||||
bufferedPositionUs = Math.max(bufferedPositionUs,
|
|
||||||
extractors.get(extractors.size() - 2).getLargestParsedTimestampUs());
|
|
||||||
}
|
|
||||||
if (previousTsLoadable != null) {
|
|
||||||
// Buffered position should be at least as large as the end time of the previously loaded
|
|
||||||
// chunk.
|
|
||||||
bufferedPositionUs = Math.max(previousTsLoadable.endTimeUs, bufferedPositionUs);
|
|
||||||
}
|
|
||||||
return bufferedPositionUs == Long.MIN_VALUE ? downstreamPositionUs
|
|
||||||
: bufferedPositionUs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void release() {
|
|
||||||
enabledTrackCount = 0;
|
|
||||||
if (loadControlRegistered) {
|
|
||||||
loadControl.unregister(this);
|
|
||||||
loadControlRegistered = false;
|
|
||||||
}
|
|
||||||
loader.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loader.Callback implementation.
|
// Loader.Callback implementation.
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -425,7 +430,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal stuff.
|
// Internal methods.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds tracks that are exposed by this {@link HlsSampleSource} instance, as well as internal
|
* Builds tracks that are exposed by this {@link HlsSampleSource} instance, as well as internal
|
||||||
@ -707,10 +712,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
return pendingResetPositionUs != NO_RESET_PENDING;
|
return pendingResetPositionUs != NO_RESET_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ long usToMs(long timeUs) {
|
|
||||||
return timeUs / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyLoadStarted(final long length, final int type, final int trigger,
|
private void notifyLoadStarted(final long length, final int type, final int trigger,
|
||||||
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
|
||||||
if (eventHandler != null && eventListener != null) {
|
if (eventHandler != null && eventListener != null) {
|
||||||
@ -718,7 +719,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onLoadStarted(eventSourceId, length, type, trigger, format,
|
eventListener.onLoadStarted(eventSourceId, length, type, trigger, format,
|
||||||
usToMs(mediaStartTimeUs), usToMs(mediaEndTimeUs));
|
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -732,7 +733,8 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onLoadCompleted(eventSourceId, bytesLoaded, type, trigger, format,
|
eventListener.onLoadCompleted(eventSourceId, bytesLoaded, type, trigger, format,
|
||||||
usToMs(mediaStartTimeUs), usToMs(mediaEndTimeUs), elapsedRealtimeMs, loadDurationMs);
|
Util.usToMs(mediaStartTimeUs), Util.usToMs(mediaEndTimeUs), elapsedRealtimeMs,
|
||||||
|
loadDurationMs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -767,7 +769,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
|
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
|
||||||
usToMs(positionUs));
|
Util.usToMs(positionUs));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,16 @@ public final class Util {
|
|||||||
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
|
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts microseconds to milliseconds (rounding down).
|
||||||
|
*
|
||||||
|
* @param timeUs A microsecond value.
|
||||||
|
* @return The value in milliseconds.
|
||||||
|
*/
|
||||||
|
public static long usToMs(long timeUs) {
|
||||||
|
return timeUs / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the entirety of an {@link InputStream} to a byte array.
|
* Converts the entirety of an {@link InputStream} to a byte array.
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user