mirror of
https://github.com/samsonjs/media.git
synced 2026-04-15 12:55:46 +00:00
Improve error propagation
This commit is contained in:
parent
5df6854fea
commit
a2f10399e7
20 changed files with 345 additions and 299 deletions
|
|
@ -126,24 +126,19 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
try {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
|
||||
for (int i = 0; i < source.getTrackCount(); i++) {
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.AUDIO_OPUS)
|
||||
|| source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.AUDIO_WEBM)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
}
|
||||
|
||||
|
|
@ -152,42 +147,49 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
|||
if (outputStreamEnded) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sourceIsReady = source.continueBuffering(trackIndex, positionUs);
|
||||
checkForDiscontinuity();
|
||||
if (format == null) {
|
||||
readFormat();
|
||||
} else {
|
||||
// Create the decoder.
|
||||
if (decoder == null) {
|
||||
// For opus, the format can contain upto 3 entries in initializationData in the following
|
||||
// exact order:
|
||||
// 1) Opus Header Information (required)
|
||||
// 2) Codec Delay in nanoseconds (required if Seek Preroll is present)
|
||||
// 3) Seek Preroll in nanoseconds (required if Codec Delay is present)
|
||||
List<byte[]> initializationData = format.initializationData;
|
||||
if (initializationData.size() < 1) {
|
||||
throw new ExoPlaybackException("Missing initialization data");
|
||||
}
|
||||
long codecDelayNs = -1;
|
||||
long seekPreRollNs = -1;
|
||||
if (initializationData.size() == 3) {
|
||||
if (initializationData.get(1).length != Long.SIZE
|
||||
|| initializationData.get(2).length != Long.SIZE) {
|
||||
throw new ExoPlaybackException("Invalid Codec Delay or Seek Preroll");
|
||||
}
|
||||
codecDelayNs = ByteBuffer.wrap(initializationData.get(1)).getLong();
|
||||
seekPreRollNs = ByteBuffer.wrap(initializationData.get(2)).getLong();
|
||||
}
|
||||
decoder =
|
||||
new OpusDecoderWrapper(initializationData.get(0), codecDelayNs, seekPreRollNs);
|
||||
decoder.start();
|
||||
}
|
||||
renderBuffer();
|
||||
sourceIsReady = source.continueBuffering(trackIndex, positionUs);
|
||||
checkForDiscontinuity();
|
||||
|
||||
// Queue input buffers.
|
||||
while (feedInputBuffer()) {}
|
||||
// Try and read a format if we don't have one already.
|
||||
if (format == null && !readFormat(positionUs)) {
|
||||
// We can't make progress without one.
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't have a decoder yet, we need to instantiate one.
|
||||
if (decoder == null) {
|
||||
// For opus, the format can contain upto 3 entries in initializationData in the following
|
||||
// exact order:
|
||||
// 1) Opus Header Information (required)
|
||||
// 2) Codec Delay in nanoseconds (required if Seek Preroll is present)
|
||||
// 3) Seek Preroll in nanoseconds (required if Codec Delay is present)
|
||||
List<byte[]> initializationData = format.initializationData;
|
||||
if (initializationData.size() < 1) {
|
||||
throw new ExoPlaybackException("Missing initialization data");
|
||||
}
|
||||
long codecDelayNs = -1;
|
||||
long seekPreRollNs = -1;
|
||||
if (initializationData.size() == 3) {
|
||||
if (initializationData.get(1).length != Long.SIZE
|
||||
|| initializationData.get(2).length != Long.SIZE) {
|
||||
throw new ExoPlaybackException("Invalid Codec Delay or Seek Preroll");
|
||||
}
|
||||
codecDelayNs = ByteBuffer.wrap(initializationData.get(1)).getLong();
|
||||
seekPreRollNs = ByteBuffer.wrap(initializationData.get(2)).getLong();
|
||||
}
|
||||
try {
|
||||
decoder = new OpusDecoderWrapper(initializationData.get(0), codecDelayNs, seekPreRollNs);
|
||||
} catch (OpusDecoderException e) {
|
||||
notifyDecoderError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
decoder.start();
|
||||
}
|
||||
|
||||
// Rendering loop.
|
||||
try {
|
||||
renderBuffer();
|
||||
while (feedInputBuffer()) {}
|
||||
} catch (AudioTrack.InitializationException e) {
|
||||
notifyAudioTrackInitializationError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
|
|
@ -197,8 +199,6 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
|||
} catch (OpusDecoderException e) {
|
||||
notifyDecoderError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +249,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
|||
}
|
||||
}
|
||||
|
||||
private boolean feedInputBuffer() throws IOException, OpusDecoderException {
|
||||
private boolean feedInputBuffer() throws OpusDecoderException {
|
||||
if (inputStreamEnded) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -291,7 +291,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
|||
return true;
|
||||
}
|
||||
|
||||
private void checkForDiscontinuity() throws IOException {
|
||||
private void checkForDiscontinuity() {
|
||||
if (decoder == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -394,12 +394,23 @@ public class LibopusAudioTrackRenderer extends TrackRenderer implements MediaClo
|
|||
}
|
||||
}
|
||||
|
||||
private void readFormat() throws IOException {
|
||||
int result = source.readData(trackIndex, currentPositionUs, formatHolder, null, false);
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readFormat(long positionUs) {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, null, false);
|
||||
if (result == SampleSource.FORMAT_READ) {
|
||||
format = formatHolder.format;
|
||||
audioTrack.reconfigure(format.getFrameworkMediaFormatV16());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -153,23 +153,18 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
|||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
try {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
|
||||
for (int i = 0; i < source.getTrackCount(); i++) {
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.VIDEO_VP9)
|
||||
|| source.getTrackInfo(i).mimeType.equalsIgnoreCase(MimeTypes.VIDEO_WEBM)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
}
|
||||
|
||||
|
|
@ -178,28 +173,29 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
|||
if (outputStreamEnded) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sourceIsReady = source.continueBuffering(trackIndex, positionUs);
|
||||
checkForDiscontinuity(positionUs);
|
||||
if (format == null) {
|
||||
readFormat(positionUs);
|
||||
} else {
|
||||
// TODO: Add support for dynamic switching between one type of surface to another.
|
||||
// Create the decoder.
|
||||
if (decoder == null) {
|
||||
decoder = new VpxDecoderWrapper(outputRgb);
|
||||
decoder.start();
|
||||
}
|
||||
processOutputBuffer(positionUs, elapsedRealtimeUs);
|
||||
sourceIsReady = source.continueBuffering(trackIndex, positionUs);
|
||||
checkForDiscontinuity(positionUs);
|
||||
|
||||
// Queue input buffers.
|
||||
while (feedInputBuffer(positionUs)) {}
|
||||
}
|
||||
// Try and read a format if we don't have one already.
|
||||
if (format == null && !readFormat(positionUs)) {
|
||||
// We can't make progress without one.
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't have a decoder yet, we need to instantiate one.
|
||||
// TODO: Add support for dynamic switching between one type of surface to another.
|
||||
if (decoder == null) {
|
||||
decoder = new VpxDecoderWrapper(outputRgb);
|
||||
decoder.start();
|
||||
}
|
||||
|
||||
// Rendering loop.
|
||||
try {
|
||||
processOutputBuffer(positionUs, elapsedRealtimeUs);
|
||||
while (feedInputBuffer(positionUs)) {}
|
||||
} catch (VpxDecoderException e) {
|
||||
notifyDecoderError(e);
|
||||
throw new ExoPlaybackException(e);
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +290,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
|||
surface.unlockCanvasAndPost(canvas);
|
||||
}
|
||||
|
||||
private boolean feedInputBuffer(long positionUs) throws IOException, VpxDecoderException {
|
||||
private boolean feedInputBuffer(long positionUs) throws VpxDecoderException {
|
||||
if (inputStreamEnded) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -334,7 +330,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void checkForDiscontinuity(long positionUs) throws IOException {
|
||||
private void checkForDiscontinuity(long positionUs) {
|
||||
if (decoder == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -417,11 +413,22 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
|||
source.disable(trackIndex);
|
||||
}
|
||||
|
||||
private void readFormat(long positionUs) throws IOException {
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean readFormat(long positionUs) {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, null, false);
|
||||
if (result == SampleSource.FORMAT_READ) {
|
||||
format = formatHolder.format;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ package com.google.android.exoplayer;
|
|||
public class DummyTrackRenderer extends TrackRenderer {
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
protected int doPrepare(long positionUs) {
|
||||
return STATE_IGNORE;
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +49,11 @@ public class DummyTrackRenderer extends TrackRenderer {
|
|||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
throw new IllegalStateException();
|
||||
|
|
|
|||
|
|
@ -266,10 +266,12 @@ import java.util.List;
|
|||
private void incrementalPrepareInternal() throws ExoPlaybackException {
|
||||
long operationStartTimeMs = SystemClock.elapsedRealtime();
|
||||
boolean prepared = true;
|
||||
for (int i = 0; i < renderers.length; i++) {
|
||||
if (renderers[i].getState() == TrackRenderer.STATE_UNPREPARED) {
|
||||
int state = renderers[i].prepare(positionUs);
|
||||
for (int rendererIndex = 0; rendererIndex < renderers.length; rendererIndex++) {
|
||||
TrackRenderer renderer = renderers[rendererIndex];
|
||||
if (renderer.getState() == TrackRenderer.STATE_UNPREPARED) {
|
||||
int state = renderer.prepare(positionUs);
|
||||
if (state == TrackRenderer.STATE_UNPREPARED) {
|
||||
renderer.maybeThrowError();
|
||||
prepared = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -414,7 +416,14 @@ import java.util.List;
|
|||
// invocation of this method.
|
||||
renderer.doSomeWork(positionUs, elapsedRealtimeUs);
|
||||
allRenderersEnded = allRenderersEnded && renderer.isEnded();
|
||||
allRenderersReadyOrEnded = allRenderersReadyOrEnded && rendererReadyOrEnded(renderer);
|
||||
|
||||
// Determine whether the renderer is ready (or ended). If it's not, throw an error that's
|
||||
// preventing the renderer from making progress, if such an error exists.
|
||||
boolean rendererReadyOrEnded = rendererReadyOrEnded(renderer);
|
||||
if (!rendererReadyOrEnded) {
|
||||
renderer.maybeThrowError();
|
||||
}
|
||||
allRenderersReadyOrEnded = allRenderersReadyOrEnded && rendererReadyOrEnded;
|
||||
|
||||
if (bufferedPositionUs == TrackRenderer.UNKNOWN_TIME_US) {
|
||||
// We've already encountered a track for which the buffered position is unknown. Hence the
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||
private final long fileDescriptorOffset;
|
||||
private final long fileDescriptorLength;
|
||||
|
||||
private IOException preparationError;
|
||||
private MediaExtractor extractor;
|
||||
private TrackInfo[] trackInfos;
|
||||
private boolean prepared;
|
||||
|
|
@ -128,13 +129,22 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(long positionUs) throws IOException {
|
||||
public boolean prepare(long positionUs) {
|
||||
if (!prepared) {
|
||||
if (preparationError != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extractor = new MediaExtractor();
|
||||
if (context != null) {
|
||||
extractor.setDataSource(context, uri, headers);
|
||||
} else {
|
||||
extractor.setDataSource(fileDescriptor, fileDescriptorOffset, fileDescriptorLength);
|
||||
try {
|
||||
if (context != null) {
|
||||
extractor.setDataSource(context, uri, headers);
|
||||
} else {
|
||||
extractor.setDataSource(fileDescriptor, fileDescriptorOffset, fileDescriptorLength);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
preparationError = e;
|
||||
return false;
|
||||
}
|
||||
|
||||
trackStates = new int[extractor.getTrackCount()];
|
||||
|
|
@ -232,6 +242,13 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||
trackStates[track] = TRACK_STATE_DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeThrowError() throws IOException {
|
||||
if (preparationError != null) {
|
||||
throw preparationError;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToUs(long positionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
|
|
|
|||
|
|
@ -245,17 +245,13 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
try {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
|
||||
for (int i = 0; i < source.getTrackCount(); i++) {
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
// TODO: Right now this is getting the mime types of the container format
|
||||
// (e.g. audio/mp4 and video/mp4 for fragmented mp4). It needs to be getting the mime types
|
||||
// of the actual samples (e.g. audio/mp4a-latm and video/avc).
|
||||
|
|
@ -264,7 +260,6 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
return TrackRenderer.STATE_PREPARED;
|
||||
}
|
||||
}
|
||||
|
||||
return TrackRenderer.STATE_IGNORE;
|
||||
}
|
||||
|
||||
|
|
@ -489,39 +484,35 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
try {
|
||||
sourceState = source.continueBuffering(trackIndex, positionUs)
|
||||
? (sourceState == SOURCE_STATE_NOT_READY ? SOURCE_STATE_READY : sourceState)
|
||||
: SOURCE_STATE_NOT_READY;
|
||||
checkForDiscontinuity(positionUs);
|
||||
if (format == null) {
|
||||
readFormat(positionUs);
|
||||
}
|
||||
if (codec == null && shouldInitCodec()) {
|
||||
maybeInitCodec();
|
||||
}
|
||||
if (codec != null) {
|
||||
TraceUtil.beginSection("drainAndFeed");
|
||||
while (drainOutputBuffer(positionUs, elapsedRealtimeUs)) {}
|
||||
if (feedInputBuffer(positionUs, true)) {
|
||||
while (feedInputBuffer(positionUs, false)) {}
|
||||
}
|
||||
TraceUtil.endSection();
|
||||
}
|
||||
codecCounters.ensureUpdated();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
sourceState = source.continueBuffering(trackIndex, positionUs)
|
||||
? (sourceState == SOURCE_STATE_NOT_READY ? SOURCE_STATE_READY : sourceState)
|
||||
: SOURCE_STATE_NOT_READY;
|
||||
checkForDiscontinuity(positionUs);
|
||||
if (format == null) {
|
||||
readFormat(positionUs);
|
||||
}
|
||||
if (codec == null && shouldInitCodec()) {
|
||||
maybeInitCodec();
|
||||
}
|
||||
if (codec != null) {
|
||||
TraceUtil.beginSection("drainAndFeed");
|
||||
while (drainOutputBuffer(positionUs, elapsedRealtimeUs)) {}
|
||||
if (feedInputBuffer(positionUs, true)) {
|
||||
while (feedInputBuffer(positionUs, false)) {}
|
||||
}
|
||||
TraceUtil.endSection();
|
||||
}
|
||||
codecCounters.ensureUpdated();
|
||||
}
|
||||
|
||||
private void readFormat(long positionUs) throws IOException, ExoPlaybackException {
|
||||
private void readFormat(long positionUs) throws ExoPlaybackException {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.FORMAT_READ) {
|
||||
onInputFormatChanged(formatHolder);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForDiscontinuity(long positionUs) throws IOException, ExoPlaybackException {
|
||||
private void checkForDiscontinuity(long positionUs) throws ExoPlaybackException {
|
||||
if (codec == null) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -560,11 +551,9 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
* @param firstFeed True if this is the first call to this method from the current invocation of
|
||||
* {@link #doSomeWork(long, long)}. False otherwise.
|
||||
* @return True if it may be possible to feed more input data. False otherwise.
|
||||
* @throws IOException If an error occurs reading data from the upstream source.
|
||||
* @throws ExoPlaybackException If an error occurs feeding the input buffer.
|
||||
*/
|
||||
private boolean feedInputBuffer(long positionUs, boolean firstFeed)
|
||||
throws IOException, ExoPlaybackException {
|
||||
private boolean feedInputBuffer(long positionUs, boolean firstFeed) throws ExoPlaybackException {
|
||||
if (inputStreamEnded
|
||||
|| codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) {
|
||||
// The input stream has ended, or we need to re-initialize the codec but are still waiting
|
||||
|
|
@ -785,6 +774,15 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnded() {
|
||||
return outputStreamEnded;
|
||||
|
|
|
|||
|
|
@ -76,9 +76,8 @@ public interface SampleSource {
|
|||
*
|
||||
* @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(long positionUs) throws IOException;
|
||||
public boolean prepare(long positionUs);
|
||||
|
||||
/**
|
||||
* Returns the number of tracks exposed by the source.
|
||||
|
|
@ -116,6 +115,14 @@ public interface SampleSource {
|
|||
*/
|
||||
public void disable(int track);
|
||||
|
||||
/**
|
||||
* If the source is currently having difficulty preparing or loading samples, then this method
|
||||
* throws the underlying error. Otherwise does nothing.
|
||||
*
|
||||
* @throws IOException The underlying error.
|
||||
*/
|
||||
public void maybeThrowError() throws IOException;
|
||||
|
||||
/**
|
||||
* Indicates to the source that it should still be buffering data for the specified track.
|
||||
*
|
||||
|
|
@ -123,9 +130,8 @@ public interface SampleSource {
|
|||
* @param positionUs The current playback position.
|
||||
* @return True if the track has available samples, or if the end of the stream has been
|
||||
* reached. False if more data needs to be buffered for samples to become available.
|
||||
* @throws IOException If an error occurred reading from the source.
|
||||
*/
|
||||
public boolean continueBuffering(int track, long positionUs) throws IOException;
|
||||
public boolean continueBuffering(int track, long positionUs);
|
||||
|
||||
/**
|
||||
* Attempts to read either a sample, a new format or or a discontinuity from the source.
|
||||
|
|
@ -147,10 +153,9 @@ public interface SampleSource {
|
|||
* {@link #DISCONTINUITY_READ} or {@link #NOTHING_READ} can be returned.
|
||||
* @return The result, which can be {@link #SAMPLE_READ}, {@link #FORMAT_READ},
|
||||
* {@link #DISCONTINUITY_READ}, {@link #NOTHING_READ} or {@link #END_OF_STREAM}.
|
||||
* @throws IOException If an error occurred reading from the source.
|
||||
*/
|
||||
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) throws IOException;
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity);
|
||||
|
||||
/**
|
||||
* Seeks to the specified time in microseconds.
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||
*
|
||||
* @param positionUs The player's current playback position.
|
||||
* @return The current state (one of the STATE_* constants), for convenience.
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final int prepare(long positionUs) throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_UNPREPARED);
|
||||
|
|
@ -139,6 +140,7 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||
* @param joining Whether this renderer is being enabled to join an ongoing playback. If true
|
||||
* then {@link #start} must be called immediately after this method returns (unless a
|
||||
* {@link ExoPlaybackException} is thrown).
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void enable(long positionUs, boolean joining) throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_PREPARED);
|
||||
|
|
@ -164,6 +166,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||
/**
|
||||
* Starts the renderer, meaning that calls to {@link #doSomeWork(long, long)} will cause the
|
||||
* track to be rendered.
|
||||
*
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void start() throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_ENABLED);
|
||||
|
|
@ -184,6 +188,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||
|
||||
/**
|
||||
* Stops the renderer.
|
||||
*
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void stop() throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_STARTED);
|
||||
|
|
@ -204,6 +210,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||
|
||||
/**
|
||||
* Disable the renderer.
|
||||
*
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void disable() throws ExoPlaybackException {
|
||||
Assertions.checkState(state == TrackRenderer.STATE_ENABLED);
|
||||
|
|
@ -224,6 +232,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||
|
||||
/**
|
||||
* Releases the renderer.
|
||||
*
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
/* package */ final void release() throws ExoPlaybackException {
|
||||
Assertions.checkState(state != TrackRenderer.STATE_ENABLED
|
||||
|
|
@ -297,6 +307,15 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
|
|||
protected abstract void doSomeWork(long positionUs, long elapsedRealtimeUs)
|
||||
throws ExoPlaybackException;
|
||||
|
||||
/**
|
||||
* Throws an error that's preventing the renderer from making progress or buffering more data at
|
||||
* this point in time.
|
||||
*
|
||||
* @throws ExoPlaybackException An error that's preventing the renderer from making progress or
|
||||
* buffering more data.
|
||||
*/
|
||||
protected abstract void maybeThrowError() throws ExoPlaybackException;
|
||||
|
||||
/**
|
||||
* Returns the duration of the media being rendered.
|
||||
* <p>
|
||||
|
|
|
|||
|
|
@ -188,23 +188,18 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean continueBuffering(int track, long positionUs) throws IOException {
|
||||
public boolean continueBuffering(int track, long positionUs) {
|
||||
Assertions.checkState(state == STATE_ENABLED);
|
||||
Assertions.checkState(track == 0);
|
||||
downstreamPositionUs = positionUs;
|
||||
chunkSource.continueBuffering(positionUs);
|
||||
updateLoadControl();
|
||||
|
||||
boolean haveSamples = !sampleQueue.isEmpty();
|
||||
if (!haveSamples) {
|
||||
maybeThrowLoadableException();
|
||||
}
|
||||
return loadingFinished || haveSamples;
|
||||
return loadingFinished || !sampleQueue.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) throws IOException {
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
||||
Assertions.checkState(state == STATE_ENABLED);
|
||||
Assertions.checkState(track == 0);
|
||||
downstreamPositionUs = positionUs;
|
||||
|
|
@ -219,7 +214,6 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
|||
}
|
||||
|
||||
if (isPendingReset()) {
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +246,6 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
|||
if (loadingFinished) {
|
||||
return END_OF_STREAM;
|
||||
}
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +256,6 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
|||
return SAMPLE_READ;
|
||||
}
|
||||
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
|
|
@ -295,15 +287,12 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
|||
pendingDiscontinuity = true;
|
||||
}
|
||||
|
||||
private void maybeThrowLoadableException() throws IOException {
|
||||
@Override
|
||||
public void maybeThrowError() throws IOException {
|
||||
if (currentLoadableException != null && currentLoadableExceptionCount > minLoadableRetryCount) {
|
||||
throw currentLoadableException;
|
||||
}
|
||||
if (sampleQueue.isEmpty() && currentLoadableHolder.chunk == null) {
|
||||
IOException chunkSourceException = chunkSource.getError();
|
||||
if (chunkSourceException != null) {
|
||||
throw chunkSourceException;
|
||||
}
|
||||
} else if (currentLoadableHolder.chunk == null) {
|
||||
chunkSource.maybeThrowError();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,13 +94,12 @@ public interface ChunkSource {
|
|||
long playbackPositionUs, ChunkOperationHolder out);
|
||||
|
||||
/**
|
||||
* If the {@link ChunkSource} is currently unable to provide chunks through
|
||||
* {@link ChunkSource#getChunkOperation}, then this method returns the underlying cause. Returns
|
||||
* null otherwise.
|
||||
* If the source is currently having difficulty providing chunks, then this method throws the
|
||||
* underlying error. Otherwise does nothing.
|
||||
*
|
||||
* @return An {@link IOException}, or null.
|
||||
* @throws IOException The underlying error.
|
||||
*/
|
||||
IOException getError();
|
||||
void maybeThrowError() throws IOException;
|
||||
|
||||
/**
|
||||
* Invoked when the {@link ChunkSampleSource} has finished loading a chunk obtained from this
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ public class MultiTrackChunkSource implements ChunkSource, ExoPlayerComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IOException getError() {
|
||||
return null;
|
||||
public void maybeThrowError() throws IOException {
|
||||
selectedSource.maybeThrowError();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import com.google.android.exoplayer.TrackInfo;
|
|||
import com.google.android.exoplayer.upstream.DataSource;
|
||||
import com.google.android.exoplayer.upstream.DataSpec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -94,8 +93,8 @@ public class SingleSampleChunkSource implements ChunkSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IOException getError() {
|
||||
return null;
|
||||
public void maybeThrowError() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -514,9 +514,12 @@ public class DashChunkSource implements ChunkSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IOException getError() {
|
||||
return fatalError != null ? fatalError
|
||||
: (manifestFetcher != null ? manifestFetcher.getError() : null);
|
||||
public void maybeThrowError() throws IOException {
|
||||
if (fatalError != null) {
|
||||
throw fatalError;
|
||||
} else if (manifestFetcher != null) {
|
||||
manifestFetcher.maybeThrowError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ public class ExtractorSampleSource implements SampleSource, SampleSourceReader,
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(long positionUs) throws IOException {
|
||||
public boolean prepare(long positionUs) {
|
||||
if (prepared) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -198,10 +198,9 @@ public class ExtractorSampleSource implements SampleSource, SampleSourceReader,
|
|||
}
|
||||
prepared = true;
|
||||
return true;
|
||||
} else {
|
||||
maybeThrowLoadableException();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -246,7 +245,7 @@ public class ExtractorSampleSource implements SampleSource, SampleSourceReader,
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean continueBuffering(int track, long playbackPositionUs) throws IOException {
|
||||
public boolean continueBuffering(int track, long playbackPositionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
Assertions.checkState(trackEnabledStates[track]);
|
||||
downstreamPositionUs = playbackPositionUs;
|
||||
|
|
@ -258,16 +257,12 @@ public class ExtractorSampleSource implements SampleSource, SampleSourceReader,
|
|||
if (isPendingReset()) {
|
||||
return false;
|
||||
}
|
||||
if (sampleQueues.valueAt(track).isEmpty()) {
|
||||
maybeThrowLoadableException();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return !sampleQueues.valueAt(track).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) throws IOException {
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
||||
downstreamPositionUs = playbackPositionUs;
|
||||
|
||||
if (pendingDiscontinuities[track]) {
|
||||
|
|
@ -276,7 +271,6 @@ public class ExtractorSampleSource implements SampleSource, SampleSourceReader,
|
|||
}
|
||||
|
||||
if (onlyReadDiscontinuity || isPendingReset()) {
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
|
|
@ -304,10 +298,27 @@ public class ExtractorSampleSource implements SampleSource, SampleSourceReader,
|
|||
return END_OF_STREAM;
|
||||
}
|
||||
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeThrowError() throws IOException {
|
||||
if (currentLoadableException == null) {
|
||||
return;
|
||||
}
|
||||
int minLoadableRetryCountForMedia;
|
||||
if (minLoadableRetryCount != MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA) {
|
||||
minLoadableRetryCountForMedia = minLoadableRetryCount;
|
||||
} else {
|
||||
minLoadableRetryCountForMedia = seekMap != null && !seekMap.isSeekable()
|
||||
? DEFAULT_MIN_LOADABLE_RETRY_COUNT_LIVE
|
||||
: DEFAULT_MIN_LOADABLE_RETRY_COUNT_ON_DEMAND;
|
||||
}
|
||||
if (currentLoadableExceptionCount > minLoadableRetryCountForMedia) {
|
||||
throw currentLoadableException;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToUs(long positionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
|
|
@ -496,23 +507,6 @@ public class ExtractorSampleSource implements SampleSource, SampleSourceReader,
|
|||
loader.startLoading(loadable, this);
|
||||
}
|
||||
|
||||
private void maybeThrowLoadableException() throws IOException {
|
||||
if (currentLoadableException == null) {
|
||||
return;
|
||||
}
|
||||
int minLoadableRetryCountForMedia;
|
||||
if (minLoadableRetryCount != MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA) {
|
||||
minLoadableRetryCountForMedia = minLoadableRetryCount;
|
||||
} else {
|
||||
minLoadableRetryCountForMedia = seekMap != null && !seekMap.isSeekable()
|
||||
? DEFAULT_MIN_LOADABLE_RETRY_COUNT_LIVE
|
||||
: DEFAULT_MIN_LOADABLE_RETRY_COUNT_ON_DEMAND;
|
||||
}
|
||||
if (currentLoadableExceptionCount > minLoadableRetryCountForMedia) {
|
||||
throw currentLoadableException;
|
||||
}
|
||||
}
|
||||
|
||||
private ExtractingLoadable createLoadableFromStart() {
|
||||
return new ExtractingLoadable(uri, dataSource, extractor, allocator, requestedBufferSize, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(long positionUs) throws IOException {
|
||||
public boolean prepare(long positionUs) {
|
||||
if (prepared) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -162,7 +162,6 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
downstreamPositionUs = positionUs;
|
||||
}
|
||||
maybeStartLoading();
|
||||
maybeThrowLoadableException();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -218,7 +217,7 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean continueBuffering(int track, long playbackPositionUs) throws IOException {
|
||||
public boolean continueBuffering(int track, long playbackPositionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
Assertions.checkState(trackEnabledStates[track]);
|
||||
downstreamPositionUs = playbackPositionUs;
|
||||
|
|
@ -232,7 +231,6 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
if (isPendingReset() || extractors.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int extractorIndex = 0; extractorIndex < extractors.size(); extractorIndex++) {
|
||||
HlsExtractorWrapper extractor = extractors.get(extractorIndex);
|
||||
if (!extractor.isPrepared()) {
|
||||
|
|
@ -242,13 +240,12 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
return true;
|
||||
}
|
||||
}
|
||||
maybeThrowLoadableException();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readData(int track, long playbackPositionUs, MediaFormatHolder formatHolder,
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) throws IOException {
|
||||
SampleHolder sampleHolder, boolean onlyReadDiscontinuity) {
|
||||
Assertions.checkState(prepared);
|
||||
downstreamPositionUs = playbackPositionUs;
|
||||
|
||||
|
|
@ -262,13 +259,11 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
}
|
||||
|
||||
if (isPendingReset()) {
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
HlsExtractorWrapper extractor = getCurrentExtractor();
|
||||
if (!extractor.isPrepared()) {
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +285,6 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
// next one for the current read.
|
||||
extractor = extractors.get(++extractorIndex);
|
||||
if (!extractor.isPrepared()) {
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
}
|
||||
|
|
@ -313,10 +307,16 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
return END_OF_STREAM;
|
||||
}
|
||||
|
||||
maybeThrowLoadableException();
|
||||
return NOTHING_READ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void maybeThrowError() throws IOException {
|
||||
if (currentLoadableException != null && currentLoadableExceptionCount > minLoadableRetryCount) {
|
||||
throw currentLoadableException;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seekToUs(long positionUs) {
|
||||
Assertions.checkState(prepared);
|
||||
|
|
@ -361,6 +361,8 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
}
|
||||
}
|
||||
|
||||
// Loader.Callback implementation.
|
||||
|
||||
@Override
|
||||
public void onLoadCompleted(Loadable loadable) {
|
||||
Assertions.checkState(loadable == currentLoadable);
|
||||
|
|
@ -412,6 +414,8 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
maybeStartLoading();
|
||||
}
|
||||
|
||||
// Internal stuff.
|
||||
|
||||
/**
|
||||
* Gets the current extractor from which samples should be read.
|
||||
* <p>
|
||||
|
|
@ -455,12 +459,6 @@ public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader
|
|||
return false;
|
||||
}
|
||||
|
||||
private void maybeThrowLoadableException() throws IOException {
|
||||
if (currentLoadableException != null && currentLoadableExceptionCount > minLoadableRetryCount) {
|
||||
throw currentLoadableException;
|
||||
}
|
||||
}
|
||||
|
||||
private void restartFrom(long positionUs) {
|
||||
pendingResetPositionUs = positionUs;
|
||||
loadingFinished = false;
|
||||
|
|
|
|||
|
|
@ -90,16 +90,13 @@ public class MetadataTrackRenderer<T> extends TrackRenderer implements Callback
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
try {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
for (int i = 0; i < source.getTrackCount(); i++) {
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (metadataParser.canParse(source.getTrackInfo(i).mimeType)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
|
|
@ -128,29 +125,21 @@ public class MetadataTrackRenderer<T> extends TrackRenderer implements Callback
|
|||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs)
|
||||
throws ExoPlaybackException {
|
||||
try {
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
} catch (IOException e) {
|
||||
// TODO: This should be propagated, but in the current design propagation may occur too
|
||||
// early. See [Internal b/22291244].
|
||||
// throw new ExoPlaybackException(e);
|
||||
}
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
|
||||
if (!inputStreamEnded && pendingMetadata == null) {
|
||||
try {
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
pendingMetadataTimestamp = sampleHolder.timeUs;
|
||||
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
||||
try {
|
||||
pendingMetadata = metadataParser.parse(sampleHolder.data.array(), sampleHolder.size);
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
sampleHolder.data.clear();
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: This should be propagated, but in the current design propagation may occur too
|
||||
// early. See [Internal b/22291244].
|
||||
// throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingMetadata != null && pendingMetadataTimestamp <= positionUs) {
|
||||
|
|
@ -159,6 +148,15 @@ public class MetadataTrackRenderer<T> extends TrackRenderer implements Callback
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDisabled() {
|
||||
pendingMetadata = null;
|
||||
|
|
|
|||
|
|
@ -324,9 +324,12 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IOException getError() {
|
||||
return fatalError != null ? fatalError
|
||||
: (manifestFetcher != null ? manifestFetcher.getError() : null);
|
||||
public void maybeThrowError() throws IOException {
|
||||
if (fatalError != null) {
|
||||
throw fatalError;
|
||||
} else {
|
||||
manifestFetcher.maybeThrowError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -151,17 +151,14 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
try {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < subtitleParsers.length; i++) {
|
||||
for (int j = 0; j < source.getTrackCount(); j++) {
|
||||
for (int j = 0; j < trackCount; j++) {
|
||||
if (subtitleParsers[i].canParse(source.getTrackInfo(j).mimeType)) {
|
||||
parserIndex = i;
|
||||
trackIndex = j;
|
||||
|
|
@ -197,11 +194,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
|||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
try {
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
|
||||
if (nextSubtitle == null) {
|
||||
try {
|
||||
|
|
@ -240,17 +233,13 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
|||
|
||||
if (!inputStreamEnded && nextSubtitle == null && !parserHelper.isParsing()) {
|
||||
// Try and read the next subtitle from the source.
|
||||
try {
|
||||
SampleHolder sampleHolder = parserHelper.getSampleHolder();
|
||||
sampleHolder.clearData();
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
parserHelper.startParseOperation();
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
SampleHolder sampleHolder = parserHelper.getSampleHolder();
|
||||
sampleHolder.clearData();
|
||||
int result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
parserHelper.startParseOperation();
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -271,6 +260,15 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
|||
source.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
|
|
|
|||
|
|
@ -92,16 +92,13 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int doPrepare(long positionUs) throws ExoPlaybackException {
|
||||
try {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
protected int doPrepare(long positionUs) {
|
||||
boolean sourcePrepared = source.prepare(positionUs);
|
||||
if (!sourcePrepared) {
|
||||
return TrackRenderer.STATE_UNPREPARED;
|
||||
}
|
||||
for (int i = 0; i < source.getTrackCount(); i++) {
|
||||
int trackCount = source.getTrackCount();
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
if (eia608Parser.canParse(source.getTrackInfo(i).mimeType)) {
|
||||
trackIndex = i;
|
||||
return TrackRenderer.STATE_PREPARED;
|
||||
|
|
@ -133,13 +130,7 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
|
|||
|
||||
@Override
|
||||
protected void doSomeWork(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
|
||||
try {
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
} catch (IOException e) {
|
||||
// TODO: This should be propagated, but in the current design propagation may occur too
|
||||
// early. See [Internal b/22291244].
|
||||
// throw new ExoPlaybackException(e);
|
||||
}
|
||||
source.continueBuffering(trackIndex, positionUs);
|
||||
|
||||
if (isSamplePending()) {
|
||||
maybeParsePendingSample(positionUs);
|
||||
|
|
@ -147,17 +138,11 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
|
|||
|
||||
int result = inputStreamEnded ? SampleSource.END_OF_STREAM : SampleSource.SAMPLE_READ;
|
||||
while (!isSamplePending() && result == SampleSource.SAMPLE_READ) {
|
||||
try {
|
||||
result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
maybeParsePendingSample(positionUs);
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// TODO: This should be propagated, but in the current design propagation may occur too
|
||||
// early. See [Internal b/22291244].
|
||||
// throw new ExoPlaybackException(e);
|
||||
result = source.readData(trackIndex, positionUs, formatHolder, sampleHolder, false);
|
||||
if (result == SampleSource.SAMPLE_READ) {
|
||||
maybeParsePendingSample(positionUs);
|
||||
} else if (result == SampleSource.END_OF_STREAM) {
|
||||
inputStreamEnded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -181,6 +166,15 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
|
|||
source.disable(trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void maybeThrowError() throws ExoPlaybackException {
|
||||
try {
|
||||
source.maybeThrowError();
|
||||
} catch (IOException e) {
|
||||
throw new ExoPlaybackException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getDurationUs() {
|
||||
return source.getTrackInfo(trackIndex).durationUs;
|
||||
|
|
|
|||
|
|
@ -186,17 +186,17 @@ public class ManifestFetcher<T> implements Loader.Callback {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the error that affected the most recent attempt to load the manifest, or null if the
|
||||
* most recent attempt was successful.
|
||||
* Throws the error that affected the most recent attempt to load the manifest. Does nothing if
|
||||
* the most recent attempt was successful.
|
||||
*
|
||||
* @return The error, or null if the most recent attempt was successful.
|
||||
* @throws IOException The error that affected the most recent attempt to load the manifest.
|
||||
*/
|
||||
public IOException getError() {
|
||||
if (loadExceptionCount <= 1) {
|
||||
// Don't report an exception until at least 1 retry attempt has been made.
|
||||
return null;
|
||||
public void maybeThrowError() throws IOException {
|
||||
// Don't throw an exception until at least 1 retry attempt has been made.
|
||||
if (loadException == null || loadExceptionCount <= 1) {
|
||||
return;
|
||||
}
|
||||
return loadException;
|
||||
throw loadException;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue