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; 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() {

View File

@ -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.

View File

@ -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()) {

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;
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));
} }
}); });
} }

View File

@ -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;

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.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));
} }
}); });
} }

View File

@ -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.
* *