Commit 64cc380f by Oliver Woodman

Avoid loading first chunk when preparing HLS for non-zero position.

This also fixes a technical mistake where HlsChunkSource is fed
seekPositionUs=-1 when obtaining the first chunk. This is wrong,
but the usage of this variable within HlsChunkSource enforces that
the seek must stay within bounds, so we get away with it.

Issue: #385
parent 116a1884
......@@ -57,7 +57,7 @@ import android.widget.TextView;
}
@Override
protected int doPrepare() throws ExoPlaybackException {
protected int doPrepare(long positionUs) throws ExoPlaybackException {
maybeFail();
return STATE_PREPARED;
}
......
......@@ -18,14 +18,14 @@ package com.google.android.exoplayer;
/**
* A {@link TrackRenderer} that does nothing.
* <p>
* This renderer returns {@link TrackRenderer#STATE_IGNORE} from {@link #doPrepare()} in order to
* request that it should be ignored. {@link IllegalStateException} is thrown from all methods that
* are documented to indicate that they should not be invoked unless the renderer is prepared.
* This renderer returns {@link TrackRenderer#STATE_IGNORE} from {@link #doPrepare(long)} in order
* to request that it should be ignored. {@link IllegalStateException} is thrown from all methods
* that are documented to indicate that they should not be invoked unless the renderer is prepared.
*/
public class DummyTrackRenderer extends TrackRenderer {
@Override
protected int doPrepare() throws ExoPlaybackException {
protected int doPrepare(long positionUs) throws ExoPlaybackException {
return STATE_IGNORE;
}
......
......@@ -264,7 +264,7 @@ import java.util.List;
boolean prepared = true;
for (int i = 0; i < renderers.length; i++) {
if (renderers[i].getState() == TrackRenderer.STATE_UNPREPARED) {
int state = renderers[i].prepare();
int state = renderers[i].prepare(positionUs);
if (state == TrackRenderer.STATE_UNPREPARED) {
prepared = false;
}
......
......@@ -128,7 +128,7 @@ public final class FrameworkSampleSource implements SampleSource {
}
@Override
public boolean prepare() throws IOException {
public boolean prepare(long positionUs) throws IOException {
if (!prepared) {
extractor = new MediaExtractor();
if (context != null) {
......
......@@ -243,9 +243,9 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
}
@Override
protected int doPrepare() throws ExoPlaybackException {
protected int doPrepare(long positionUs) throws ExoPlaybackException {
try {
boolean sourcePrepared = source.prepare();
boolean sourcePrepared = source.prepare(positionUs);
if (!sourcePrepared) {
return TrackRenderer.STATE_UNPREPARED;
}
......
......@@ -57,10 +57,11 @@ public interface SampleSource {
* and formats). If insufficient data is available then the call will return {@code false} rather
* than block. The method can be called repeatedly until the return value indicates success.
*
* @param positionUs The player's current playback position.
* @return True if the source was prepared successfully, false otherwise.
* @throws IOException If an error occurred preparing the source.
*/
public boolean prepare() throws IOException;
public boolean prepare(long positionUs) throws IOException;
/**
* Returns the number of tracks exposed by the source.
......
......@@ -108,11 +108,12 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
* Prepares the renderer. This method is non-blocking, and hence it may be necessary to call it
* more than once in order to transition the renderer into the prepared state.
*
* @param positionUs The player's current playback position.
* @return The current state (one of the STATE_* constants), for convenience.
*/
/* package */ final int prepare() throws ExoPlaybackException {
/* package */ final int prepare(long positionUs) throws ExoPlaybackException {
Assertions.checkState(state == TrackRenderer.STATE_UNPREPARED);
state = doPrepare();
state = doPrepare(positionUs);
Assertions.checkState(state == TrackRenderer.STATE_UNPREPARED ||
state == TrackRenderer.STATE_PREPARED ||
state == TrackRenderer.STATE_IGNORE);
......@@ -127,11 +128,12 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
* This method should return quickly, and should not block if the renderer is currently unable to
* make any useful progress.
*
* @param positionUs The player's current playback position.
* @return The new state of the renderer. One of {@link #STATE_UNPREPARED},
* {@link #STATE_PREPARED} and {@link #STATE_IGNORE}.
* @throws ExoPlaybackException If an error occurs.
*/
protected abstract int doPrepare() throws ExoPlaybackException;
protected abstract int doPrepare(long positionUs) throws ExoPlaybackException;
/**
* Enable the renderer.
......
......@@ -121,7 +121,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
}
@Override
public boolean prepare() {
public boolean prepare(long positionUs) {
Assertions.checkState(state == STATE_UNPREPARED);
loader = new Loader("Loader:" + chunkSource.getTrackInfo().mimeType);
state = STATE_PREPARED;
......
......@@ -138,7 +138,7 @@ public class ExtractorSampleSource implements SampleSource, ExtractorOutput, Loa
}
@Override
public boolean prepare() throws IOException {
public boolean prepare(long positionUs) throws IOException {
if (prepared) {
return true;
}
......
......@@ -125,15 +125,12 @@ public class HlsSampleSource implements SampleSource, Loader.Callback {
}
@Override
public boolean prepare() throws IOException {
public boolean prepare(long positionUs) throws IOException {
if (prepared) {
return true;
}
if (loader == null) {
loader = new Loader("Loader:HLS");
}
continueBufferingInternal();
if (!extractors.isEmpty()) {
// We're not prepared, but we might have loaded what we need.
HlsExtractorWrapper extractor = extractors.getFirst();
if (extractor.isPrepared()) {
trackCount = extractor.getTrackCount();
......@@ -146,12 +143,23 @@ public class HlsSampleSource implements SampleSource, Loader.Callback {
trackInfos[i] = new TrackInfo(format.mimeType, chunkSource.getDurationUs());
}
prepared = true;
return true;
}
}
if (!prepared) {
maybeThrowLoadableException();
// We're not prepared and we haven't loaded what we need.
if (loader == null) {
loader = new Loader("Loader:HLS");
}
if (!loader.isLoading()) {
// We're going to have to start loading a chunk to get what we need for preparation. We should
// attempt to load the chunk at positionUs, so that we'll already be loading the correct chunk
// in the common case where the renderer is subsequently enabled at this position.
pendingResetPositionUs = positionUs;
downstreamPositionUs = positionUs;
}
return prepared;
maybeStartLoading();
maybeThrowLoadableException();
return false;
}
@Override
......
......@@ -90,9 +90,9 @@ public class MetadataTrackRenderer<T> extends TrackRenderer implements Callback
}
@Override
protected int doPrepare() throws ExoPlaybackException {
protected int doPrepare(long positionUs) throws ExoPlaybackException {
try {
boolean sourcePrepared = source.prepare();
boolean sourcePrepared = source.prepare(positionUs);
if (!sourcePrepared) {
return TrackRenderer.STATE_UNPREPARED;
}
......
......@@ -80,9 +80,9 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
}
@Override
protected int doPrepare() throws ExoPlaybackException {
protected int doPrepare(long positionUs) throws ExoPlaybackException {
try {
boolean sourcePrepared = source.prepare();
boolean sourcePrepared = source.prepare(positionUs);
if (!sourcePrepared) {
return TrackRenderer.STATE_UNPREPARED;
}
......
......@@ -90,9 +90,9 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
}
@Override
protected int doPrepare() throws ExoPlaybackException {
protected int doPrepare(long positionUs) throws ExoPlaybackException {
try {
boolean sourcePrepared = source.prepare();
boolean sourcePrepared = source.prepare(positionUs);
if (!sourcePrepared) {
return TrackRenderer.STATE_UNPREPARED;
}
......
......@@ -579,7 +579,7 @@ public class Mp4ExtractorTest extends TestCase {
try {
switch (message.what) {
case MSG_PREPARE:
if (!source.prepare()) {
if (!source.prepare(0)) {
sendEmptyMessage(MSG_PREPARE);
} else {
// Select the video track and get its metadata.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment