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:
olly 2016-04-01 06:47:45 -07:00 committed by Oliver Woodman
parent 292b2402e6
commit 9c2a971109
7 changed files with 268 additions and 236 deletions

View File

@ -119,6 +119,8 @@ public final class FrameworkSampleSource implements SampleSource {
headers = null;
}
// SampleSource implementation.
@Override
public boolean prepare(long positionUs) throws IOException {
if (prepared) {
@ -156,11 +158,6 @@ public final class FrameworkSampleSource implements SampleSource {
return tracks;
}
@Override
public void continueBuffering(long positionUs) {
// MediaExtractor takes care of buffering. Do nothing.
}
@Override
public TrackStream[] selectTracks(List<TrackStream> oldStreams,
List<TrackSelection> newSelections, long positionUs) {
@ -194,6 +191,44 @@ public final class FrameworkSampleSource implements SampleSource {
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) {
if (pendingResets[track]) {
pendingResets[track] = false;
@ -242,36 +277,7 @@ public final class FrameworkSampleSource implements SampleSource {
}
}
@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;
}
}
// Internal methods.
@TargetApi(18)
private DrmInitData getDrmInitDataV18() {

View File

@ -80,6 +80,11 @@ public final class MultiSampleSource implements SampleSource {
return true;
}
@Override
public long getDurationUs() {
return durationUs;
}
@Override
public TrackGroupArray getTrackGroups() {
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
public long getBufferedPositionUs() {
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;
}
@Override
public void seekToUs(long positionUs) {
for (SampleSource source : enabledSources) {
source.seekToUs(positionUs);
}
}
@Override
public void release() {
for (SampleSource source : sources) {
@ -153,6 +153,8 @@ public final class MultiSampleSource implements SampleSource {
}
}
// Internal methods.
private int selectTracks(SampleSource source, List<TrackStream> allOldStreams,
List<TrackSelection> allNewSelections, long positionUs, TrackStream[] allNewStreams) {
// Get the subset of the old streams for the source.

View File

@ -104,10 +104,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
sampleData = new byte[INITIAL_SAMPLE_SIZE];
}
@Override
public void maybeThrowError() throws IOException {
loader.maybeThrowError();
}
// SampleSource implementation.
@Override
public boolean prepare(long positionUs) {
@ -152,11 +149,37 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
// 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
public boolean isReady() {
return loadingFinished;
}
@Override
public void maybeThrowError() throws IOException {
loader.maybeThrowError();
}
@Override
public long readReset() {
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.
@Override
@ -259,7 +263,7 @@ public final class SingleSampleSource implements SampleSource, TrackStream, Load
}
}
// Private methods.
// Internal methods.
private void maybeStartLoading() {
if (loadingFinished || streamState == STREAM_STATE_END_OF_STREAM || loader.isLoading()) {

View File

@ -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.Loadable;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.Util;
import android.os.Handler;
import android.os.SystemClock;
@ -139,6 +140,8 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
pendingResetPositionUs = NO_RESET_PENDING;
}
// SampleSource implementation.
@Override
public boolean prepare(long positionUs) throws IOException {
if (prepared) {
@ -224,11 +227,62 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
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
public boolean isReady() {
return loadingFinished || !sampleQueue.isEmpty();
}
@Override
public void maybeThrowError() throws IOException {
loader.maybeThrowError();
if (currentLoadableHolder.chunk == null) {
chunkSource.maybeThrowError();
}
}
@Override
public long readReset() {
if (pendingReset) {
@ -287,55 +341,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
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.
@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
* the sample is returned.
@ -530,10 +537,6 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
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,
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
if (eventHandler != null && eventListener != null) {
@ -541,7 +544,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
@Override
public void run() {
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
public void run() {
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() {
@Override
public void run() {
eventListener.onUpstreamDiscarded(eventSourceId, usToMs(mediaStartTimeUs),
usToMs(mediaEndTimeUs));
eventListener.onUpstreamDiscarded(eventSourceId, Util.usToMs(mediaStartTimeUs),
Util.usToMs(mediaEndTimeUs));
}
});
}
@ -602,7 +606,7 @@ public class ChunkSampleSource implements SampleSource, TrackStream, Loader.Call
@Override
public void run() {
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
usToMs(positionUs));
Util.usToMs(positionUs));
}
});
}

View File

@ -329,6 +329,8 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
pendingResetPositionUs = NO_RESET_PENDING;
}
// SampleSource implementation.
@Override
public boolean prepare(long positionUs) throws IOException {
if (prepared) {
@ -418,12 +420,49 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
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) {
Assertions.checkState(trackEnabledStates[track]);
return !sampleQueues.valueAt(track).isEmpty();
}
/* package */ void maybeThrowError() throws IOException {
if (fatalException != null) {
throw fatalException;
}
loader.maybeThrowError();
}
/* package */ long readReset(int track) {
if (pendingResets[track]) {
pendingResets[track] = false;
@ -466,58 +505,6 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
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.
@Override
@ -575,7 +562,24 @@ public final class ExtractorSampleSource implements SampleSource, ExtractorOutpu
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) {
pendingResetPositionUs = positionUs;

View File

@ -32,6 +32,7 @@ import com.google.android.exoplayer.upstream.Loader;
import com.google.android.exoplayer.upstream.Loader.Loadable;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;
import android.os.Handler;
import android.os.SystemClock;
@ -128,6 +129,8 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
chunkOperationHolder = new ChunkOperationHolder();
}
// SampleSource implementation.
@Override
public boolean prepare(long positionUs) throws IOException {
if (prepared) {
@ -245,6 +248,47 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
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) {
Assertions.checkState(groupEnabledStates[group]);
if (loadingFinished) {
@ -265,6 +309,13 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
return false;
}
/* package */ void maybeThrowError() throws IOException {
loader.maybeThrowError();
if (currentLoadable == null) {
chunkSource.maybeThrowError();
}
}
/* package */ long readReset(int group) {
if (pendingResets[group]) {
pendingResets[group] = false;
@ -327,52 +378,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
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.
@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
@ -707,10 +712,6 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
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,
final Format format, final long mediaStartTimeUs, final long mediaEndTimeUs) {
if (eventHandler != null && eventListener != null) {
@ -718,7 +719,7 @@ public final class HlsSampleSource implements SampleSource, Loader.Callback {
@Override
public void run() {
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
public void run() {
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
public void run() {
eventListener.onDownstreamFormatChanged(eventSourceId, format, trigger,
usToMs(positionUs));
Util.usToMs(positionUs));
}
});
}

View File

@ -131,6 +131,16 @@ public final class Util {
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.
*