Allow playback to continue even after SingleSampleMediaPeriod load errors
This prevents users from having to check sideloaded subtitles URLs before preparing a SingleSampleMediaSource with it. Issue:#3140 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=174475274
This commit is contained in:
parent
ecaaed9674
commit
54a2a69b05
@ -27,7 +27,6 @@ import com.google.android.exoplayer2.upstream.DataSource;
|
|||||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||||
import com.google.android.exoplayer2.upstream.Loader;
|
import com.google.android.exoplayer2.upstream.Loader;
|
||||||
import com.google.android.exoplayer2.upstream.Loader.Loadable;
|
import com.google.android.exoplayer2.upstream.Loader.Loadable;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -52,16 +51,20 @@ import java.util.Arrays;
|
|||||||
private final int eventSourceId;
|
private final int eventSourceId;
|
||||||
private final TrackGroupArray tracks;
|
private final TrackGroupArray tracks;
|
||||||
private final ArrayList<SampleStreamImpl> sampleStreams;
|
private final ArrayList<SampleStreamImpl> sampleStreams;
|
||||||
|
// Package private to avoid thunk methods.
|
||||||
/* package */ final Loader loader;
|
/* package */ final Loader loader;
|
||||||
/* package */ final Format format;
|
/* package */ final Format format;
|
||||||
|
/* package */ final boolean treatLoadErrorsAsEndOfStream;
|
||||||
|
|
||||||
/* package */ boolean loadingFinished;
|
/* package */ boolean loadingFinished;
|
||||||
|
/* package */ boolean loadingSucceeded;
|
||||||
/* package */ byte[] sampleData;
|
/* package */ byte[] sampleData;
|
||||||
/* package */ int sampleSize;
|
/* package */ int sampleSize;
|
||||||
|
private int errorCount;
|
||||||
|
|
||||||
public SingleSampleMediaPeriod(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
public SingleSampleMediaPeriod(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
||||||
int minLoadableRetryCount, Handler eventHandler, EventListener eventListener,
|
int minLoadableRetryCount, Handler eventHandler, EventListener eventListener,
|
||||||
int eventSourceId) {
|
int eventSourceId, boolean treatLoadErrorsAsEndOfStream) {
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
@ -69,6 +72,7 @@ import java.util.Arrays;
|
|||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
this.eventSourceId = eventSourceId;
|
this.eventSourceId = eventSourceId;
|
||||||
|
this.treatLoadErrorsAsEndOfStream = treatLoadErrorsAsEndOfStream;
|
||||||
tracks = new TrackGroupArray(new TrackGroup(format));
|
tracks = new TrackGroupArray(new TrackGroup(format));
|
||||||
sampleStreams = new ArrayList<>();
|
sampleStreams = new ArrayList<>();
|
||||||
loader = new Loader("Loader:SingleSampleMediaPeriod");
|
loader = new Loader("Loader:SingleSampleMediaPeriod");
|
||||||
@ -85,7 +89,7 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void maybeThrowPrepareError() throws IOException {
|
public void maybeThrowPrepareError() throws IOException {
|
||||||
loader.maybeThrowError();
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -157,6 +161,7 @@ import java.util.Arrays;
|
|||||||
sampleSize = loadable.sampleSize;
|
sampleSize = loadable.sampleSize;
|
||||||
sampleData = loadable.sampleData;
|
sampleData = loadable.sampleData;
|
||||||
loadingFinished = true;
|
loadingFinished = true;
|
||||||
|
loadingSucceeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -169,6 +174,11 @@ import java.util.Arrays;
|
|||||||
public int onLoadError(SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs,
|
public int onLoadError(SourceLoadable loadable, long elapsedRealtimeMs, long loadDurationMs,
|
||||||
IOException error) {
|
IOException error) {
|
||||||
notifyLoadError(error);
|
notifyLoadError(error);
|
||||||
|
errorCount++;
|
||||||
|
if (treatLoadErrorsAsEndOfStream && errorCount >= minLoadableRetryCount) {
|
||||||
|
loadingFinished = true;
|
||||||
|
return Loader.DONT_RETRY;
|
||||||
|
}
|
||||||
return Loader.RETRY;
|
return Loader.RETRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +216,9 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void maybeThrowError() throws IOException {
|
public void maybeThrowError() throws IOException {
|
||||||
loader.maybeThrowError();
|
if (!treatLoadErrorsAsEndOfStream) {
|
||||||
|
loader.maybeThrowError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -219,19 +231,19 @@ import java.util.Arrays;
|
|||||||
formatHolder.format = format;
|
formatHolder.format = format;
|
||||||
streamState = STREAM_STATE_SEND_SAMPLE;
|
streamState = STREAM_STATE_SEND_SAMPLE;
|
||||||
return C.RESULT_FORMAT_READ;
|
return C.RESULT_FORMAT_READ;
|
||||||
}
|
} else if (loadingFinished) {
|
||||||
|
if (loadingSucceeded) {
|
||||||
Assertions.checkState(streamState == STREAM_STATE_SEND_SAMPLE);
|
buffer.timeUs = 0;
|
||||||
if (!loadingFinished) {
|
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||||
return C.RESULT_NOTHING_READ;
|
buffer.ensureSpaceForWrite(sampleSize);
|
||||||
} else {
|
buffer.data.put(sampleData, 0, sampleSize);
|
||||||
buffer.timeUs = 0;
|
} else {
|
||||||
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||||
buffer.ensureSpaceForWrite(sampleSize);
|
}
|
||||||
buffer.data.put(sampleData, 0, sampleSize);
|
|
||||||
streamState = STREAM_STATE_END_OF_STREAM;
|
streamState = STREAM_STATE_END_OF_STREAM;
|
||||||
return C.RESULT_BUFFER_READ;
|
return C.RESULT_BUFFER_READ;
|
||||||
}
|
}
|
||||||
|
return C.RESULT_NOTHING_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,21 +57,51 @@ public final class SingleSampleMediaSource implements MediaSource {
|
|||||||
private final Handler eventHandler;
|
private final Handler eventHandler;
|
||||||
private final EventListener eventListener;
|
private final EventListener eventListener;
|
||||||
private final int eventSourceId;
|
private final int eventSourceId;
|
||||||
|
private final boolean treatLoadErrorsAsEndOfStream;
|
||||||
private final Timeline timeline;
|
private final Timeline timeline;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The {@link Uri} of the media stream.
|
||||||
|
* @param dataSourceFactory The factory from which the {@link DataSource} to read the media will
|
||||||
|
* be obtained.
|
||||||
|
* @param format The {@link Format} associated with the output track.
|
||||||
|
* @param durationUs The duration of the media stream in microseconds.
|
||||||
|
*/
|
||||||
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
||||||
long durationUs) {
|
long durationUs) {
|
||||||
this(uri, dataSourceFactory, format, durationUs, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
this(uri, dataSourceFactory, format, durationUs, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The {@link Uri} of the media stream.
|
||||||
|
* @param dataSourceFactory The factory from which the {@link DataSource} to read the media will
|
||||||
|
* be obtained.
|
||||||
|
* @param format The {@link Format} associated with the output track.
|
||||||
|
* @param durationUs The duration of the media stream in microseconds.
|
||||||
|
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||||
|
*/
|
||||||
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
||||||
long durationUs, int minLoadableRetryCount) {
|
long durationUs, int minLoadableRetryCount) {
|
||||||
this(uri, dataSourceFactory, format, durationUs, minLoadableRetryCount, null, null, 0);
|
this(uri, dataSourceFactory, format, durationUs, minLoadableRetryCount, null, null, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The {@link Uri} of the media stream.
|
||||||
|
* @param dataSourceFactory The factory from which the {@link DataSource} to read the media will
|
||||||
|
* be obtained.
|
||||||
|
* @param format The {@link Format} associated with the output track.
|
||||||
|
* @param durationUs The duration of the media stream in microseconds.
|
||||||
|
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
|
||||||
|
* @param eventHandler A handler for events. May be null if delivery of events is not required.
|
||||||
|
* @param eventListener A listener of events. May be null if delivery of events is not required.
|
||||||
|
* @param eventSourceId An identifier that gets passed to {@code eventListener} methods.
|
||||||
|
* @param treatLoadErrorsAsEndOfStream If true, load errors will not be propagated by sample
|
||||||
|
* streams, treating them as ended instead. If false, load errors will be propagated normally
|
||||||
|
* by {@link SampleStream#maybeThrowError()}.
|
||||||
|
*/
|
||||||
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
public SingleSampleMediaSource(Uri uri, DataSource.Factory dataSourceFactory, Format format,
|
||||||
long durationUs, int minLoadableRetryCount, Handler eventHandler, EventListener eventListener,
|
long durationUs, int minLoadableRetryCount, Handler eventHandler, EventListener eventListener,
|
||||||
int eventSourceId) {
|
int eventSourceId, boolean treatLoadErrorsAsEndOfStream) {
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
this.format = format;
|
this.format = format;
|
||||||
@ -79,6 +109,7 @@ public final class SingleSampleMediaSource implements MediaSource {
|
|||||||
this.eventHandler = eventHandler;
|
this.eventHandler = eventHandler;
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
this.eventSourceId = eventSourceId;
|
this.eventSourceId = eventSourceId;
|
||||||
|
this.treatLoadErrorsAsEndOfStream = treatLoadErrorsAsEndOfStream;
|
||||||
timeline = new SinglePeriodTimeline(durationUs, true);
|
timeline = new SinglePeriodTimeline(durationUs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +129,7 @@ public final class SingleSampleMediaSource implements MediaSource {
|
|||||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||||
Assertions.checkArgument(id.periodIndex == 0);
|
Assertions.checkArgument(id.periodIndex == 0);
|
||||||
return new SingleSampleMediaPeriod(uri, dataSourceFactory, format, minLoadableRetryCount,
|
return new SingleSampleMediaPeriod(uri, dataSourceFactory, format, minLoadableRetryCount,
|
||||||
eventHandler, eventListener, eventSourceId);
|
eventHandler, eventListener, eventSourceId, treatLoadErrorsAsEndOfStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user