mirror of
https://github.com/androidx/media.git
synced 2025-05-17 12:39:52 +08:00
Allow ChunkSource an opportunity to fail preparation.
When ChunkSource implementations implement multi-track for DASH and SS, format selection will move inside of ChunkSource. If we, for example, fail to query the decoder to determine which tracks are playable, we need an opportunity to fail (i.e. say we're not prepared, so that maybeThrowError is called, from which we can throw). This may go away in the future if we remove the distinct preparation step and treat tracks/formats as things that can change dynamically, but for now this is what we have. Issue #514.
This commit is contained in:
parent
d49d5a1765
commit
38f2413290
@ -66,6 +66,14 @@ public interface SampleSource {
|
|||||||
*/
|
*/
|
||||||
public interface SampleSourceReader {
|
public interface SampleSourceReader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the source.
|
* Prepares the source.
|
||||||
* <p>
|
* <p>
|
||||||
@ -75,12 +83,14 @@ public interface SampleSource {
|
|||||||
* success.
|
* success.
|
||||||
*
|
*
|
||||||
* @param positionUs The player's current playback position.
|
* @param positionUs The player's current playback position.
|
||||||
* @return True if the source was prepared successfully, false otherwise.
|
* @return True if the source was prepared, false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean prepare(long positionUs);
|
public boolean prepare(long positionUs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of tracks exposed by the source.
|
* Returns the number of tracks exposed by the source.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called after the source has been prepared.
|
||||||
*
|
*
|
||||||
* @return The number of tracks.
|
* @return The number of tracks.
|
||||||
*/
|
*/
|
||||||
@ -96,7 +106,7 @@ public interface SampleSource {
|
|||||||
* performed using the formats obtained when reading the media stream through calls to
|
* performed using the formats obtained when reading the media stream through calls to
|
||||||
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should not be called until after the source has been successfully prepared.
|
* This method should only be called after the source has been prepared.
|
||||||
*
|
*
|
||||||
* @param track The track index.
|
* @param track The track index.
|
||||||
* @return The format of the specified track.
|
* @return The format of the specified track.
|
||||||
@ -107,32 +117,18 @@ public interface SampleSource {
|
|||||||
* Enable the specified track. This allows the track's format and samples to be read from
|
* Enable the specified track. This allows the track's format and samples to be read from
|
||||||
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should not be called until after the source has been successfully prepared.
|
* This method should only be called after the source has been prepared, and when the specified
|
||||||
|
* track is disabled.
|
||||||
*
|
*
|
||||||
* @param track The track to enable.
|
* @param track The track to enable.
|
||||||
* @param positionUs The player's current playback position.
|
* @param positionUs The player's current playback position.
|
||||||
*/
|
*/
|
||||||
public void enable(int track, long positionUs);
|
public void enable(int track, long positionUs);
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable the specified track.
|
|
||||||
* <p>
|
|
||||||
* This method should not be called until after the source has been successfully prepared.
|
|
||||||
*
|
|
||||||
* @param track The track to disable.
|
|
||||||
*/
|
|
||||||
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.
|
* Indicates to the source that it should still be buffering data for the specified track.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the specified track is enabled.
|
||||||
*
|
*
|
||||||
* @param track The track to continue buffering.
|
* @param track The track to continue buffering.
|
||||||
* @param positionUs The current playback position.
|
* @param positionUs The current playback position.
|
||||||
@ -144,7 +140,7 @@ public interface SampleSource {
|
|||||||
/**
|
/**
|
||||||
* Attempts to read either a sample, a new format or or a discontinuity from the source.
|
* Attempts to read either a sample, a new format or or a discontinuity from the source.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should not be called until after the source has been successfully prepared.
|
* This method should only be called when the specified track is enabled.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that where multiple tracks are enabled, {@link #NOTHING_READ} may be returned if the
|
* Note that where multiple tracks are enabled, {@link #NOTHING_READ} may be returned if the
|
||||||
* next piece of data to be read from the {@link SampleSource} corresponds to a different track
|
* next piece of data to be read from the {@link SampleSource} corresponds to a different track
|
||||||
@ -168,7 +164,7 @@ public interface SampleSource {
|
|||||||
/**
|
/**
|
||||||
* Seeks to the specified time in microseconds.
|
* Seeks to the specified time in microseconds.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should not be called until after the source has been successfully prepared.
|
* This method should only be called when at least one track is enabled.
|
||||||
*
|
*
|
||||||
* @param positionUs The seek position in microseconds.
|
* @param positionUs The seek position in microseconds.
|
||||||
*/
|
*/
|
||||||
@ -177,7 +173,7 @@ public interface SampleSource {
|
|||||||
/**
|
/**
|
||||||
* Returns an estimate of the position up to which data is buffered.
|
* Returns an estimate of the position up to which data is buffered.
|
||||||
* <p>
|
* <p>
|
||||||
* This method should not be called until after the source has been successfully prepared.
|
* This method should only be called when at least one track is enabled.
|
||||||
*
|
*
|
||||||
* @return An estimate of the absolute position in microseconds up to which data is buffered,
|
* @return An estimate of the absolute position in microseconds up to which data is buffered,
|
||||||
* or {@link TrackRenderer#END_OF_TRACK_US} if data is buffered to the end of the stream,
|
* or {@link TrackRenderer#END_OF_TRACK_US} if data is buffered to the end of the stream,
|
||||||
@ -185,6 +181,15 @@ public interface SampleSource {
|
|||||||
*/
|
*/
|
||||||
public long getBufferedPositionUs();
|
public long getBufferedPositionUs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the specified track.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the specified track is enabled.
|
||||||
|
*
|
||||||
|
* @param track The track to disable.
|
||||||
|
*/
|
||||||
|
public void disable(int track);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases the {@link SampleSourceReader}.
|
* Releases the {@link SampleSourceReader}.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -131,6 +131,8 @@ public class ChunkSampleSource implements SampleSource, SampleSourceReader, Load
|
|||||||
Assertions.checkState(state == STATE_INITIALIZED || state == STATE_PREPARED);
|
Assertions.checkState(state == STATE_INITIALIZED || state == STATE_PREPARED);
|
||||||
if (state == STATE_PREPARED) {
|
if (state == STATE_PREPARED) {
|
||||||
return true;
|
return true;
|
||||||
|
} else if (!chunkSource.prepare()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
loader = new Loader("Loader:" + chunkSource.getFormat(0).mimeType);
|
loader = new Loader("Loader:" + chunkSource.getFormat(0).mimeType);
|
||||||
state = STATE_PREPARED;
|
state = STATE_PREPARED;
|
||||||
|
@ -30,8 +30,27 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface ChunkSource {
|
public interface ChunkSource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the source is currently having difficulty preparing or providing chunks, then this method
|
||||||
|
* throws the underlying error. Otherwise does nothing.
|
||||||
|
*
|
||||||
|
* @throws IOException The underlying error.
|
||||||
|
*/
|
||||||
|
void maybeThrowError() throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the source.
|
||||||
|
* <p>
|
||||||
|
* The method can be called repeatedly until the return value indicates success.
|
||||||
|
*
|
||||||
|
* @return True if the source was prepared, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean prepare();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of tracks exposed by the source.
|
* Returns the number of tracks exposed by the source.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called after the source has been prepared.
|
||||||
*
|
*
|
||||||
* @return The number of tracks.
|
* @return The number of tracks.
|
||||||
*/
|
*/
|
||||||
@ -40,7 +59,7 @@ public interface ChunkSource {
|
|||||||
/**
|
/**
|
||||||
* Gets the format of the specified track.
|
* Gets the format of the specified track.
|
||||||
* <p>
|
* <p>
|
||||||
* May be called when the source is disabled or enabled.
|
* This method should only be called after the source has been prepared.
|
||||||
*
|
*
|
||||||
* @param track The track index.
|
* @param track The track index.
|
||||||
* @return The format of the track.
|
* @return The format of the track.
|
||||||
@ -51,6 +70,8 @@ public interface ChunkSource {
|
|||||||
* Adaptive video {@link ChunkSource} implementations must return a copy of the provided
|
* Adaptive video {@link ChunkSource} implementations must return a copy of the provided
|
||||||
* {@link MediaFormat} with the maximum video dimensions set. Other implementations can return
|
* {@link MediaFormat} with the maximum video dimensions set. Other implementations can return
|
||||||
* the provided {@link MediaFormat} directly.
|
* the provided {@link MediaFormat} directly.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called after the source has been prepared.
|
||||||
*
|
*
|
||||||
* @param format The format to be copied or returned.
|
* @param format The format to be copied or returned.
|
||||||
* @return A copy of the provided {@link MediaFormat} with the maximum video dimensions set, or
|
* @return A copy of the provided {@link MediaFormat} with the maximum video dimensions set, or
|
||||||
@ -59,21 +80,19 @@ public interface ChunkSource {
|
|||||||
MediaFormat getWithMaxVideoDimensions(MediaFormat format);
|
MediaFormat getWithMaxVideoDimensions(MediaFormat format);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the source is enabled.
|
* Enable the source for the specified track.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called after the source has been prepared, and when the source is
|
||||||
|
* disabled.
|
||||||
*
|
*
|
||||||
* @param track The track index.
|
* @param track The track index.
|
||||||
*/
|
*/
|
||||||
void enable(int track);
|
void enable(int track);
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the source is disabled.
|
|
||||||
*
|
|
||||||
* @param queue A representation of the currently buffered {@link MediaChunk}s.
|
|
||||||
*/
|
|
||||||
void disable(List<? extends MediaChunk> queue);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates to the source that it should still be checking for updates to the stream.
|
* Indicates to the source that it should still be checking for updates to the stream.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the source is enabled.
|
||||||
*
|
*
|
||||||
* @param playbackPositionUs The current playback position.
|
* @param playbackPositionUs The current playback position.
|
||||||
*/
|
*/
|
||||||
@ -88,6 +107,8 @@ public interface ChunkSource {
|
|||||||
* with the next {@link Chunk} to load. The next chunk may be a {@link MediaChunk} to be added to
|
* with the next {@link Chunk} to load. The next chunk may be a {@link MediaChunk} to be added to
|
||||||
* the queue, or another {@link Chunk} type (e.g. to load initialization data), or null if the
|
* the queue, or another {@link Chunk} type (e.g. to load initialization data), or null if the
|
||||||
* source is not able to provide a chunk in its current state.
|
* source is not able to provide a chunk in its current state.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the source is enabled.
|
||||||
*
|
*
|
||||||
* @param queue A representation of the currently buffered {@link MediaChunk}s.
|
* @param queue A representation of the currently buffered {@link MediaChunk}s.
|
||||||
* @param seekPositionUs If the queue is empty, this parameter must specify the seek position. If
|
* @param seekPositionUs If the queue is empty, this parameter must specify the seek position. If
|
||||||
@ -103,17 +124,11 @@ public interface ChunkSource {
|
|||||||
void getChunkOperation(List<? extends MediaChunk> queue, long seekPositionUs,
|
void getChunkOperation(List<? extends MediaChunk> queue, long seekPositionUs,
|
||||||
long playbackPositionUs, ChunkOperationHolder out);
|
long playbackPositionUs, ChunkOperationHolder out);
|
||||||
|
|
||||||
/**
|
|
||||||
* If the source is currently having difficulty providing chunks, then this method throws the
|
|
||||||
* underlying error. Otherwise does nothing.
|
|
||||||
*
|
|
||||||
* @throws IOException The underlying error.
|
|
||||||
*/
|
|
||||||
void maybeThrowError() throws IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when the {@link ChunkSampleSource} has finished loading a chunk obtained from this
|
* Invoked when the {@link ChunkSampleSource} has finished loading a chunk obtained from this
|
||||||
* source.
|
* source.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the source is enabled.
|
||||||
*
|
*
|
||||||
* @param chunk The chunk whose load has been completed.
|
* @param chunk The chunk whose load has been completed.
|
||||||
*/
|
*/
|
||||||
@ -122,10 +137,21 @@ public interface ChunkSource {
|
|||||||
/**
|
/**
|
||||||
* Invoked when the {@link ChunkSampleSource} encounters an error loading a chunk obtained from
|
* Invoked when the {@link ChunkSampleSource} encounters an error loading a chunk obtained from
|
||||||
* this source.
|
* this source.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the source is enabled.
|
||||||
*
|
*
|
||||||
* @param chunk The chunk whose load encountered the error.
|
* @param chunk The chunk whose load encountered the error.
|
||||||
* @param e The error.
|
* @param e The error.
|
||||||
*/
|
*/
|
||||||
void onChunkLoadError(Chunk chunk, Exception e);
|
void onChunkLoadError(Chunk chunk, Exception e);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the source.
|
||||||
|
* <p>
|
||||||
|
* This method should only be called when the source is enabled.
|
||||||
|
*
|
||||||
|
* @param queue A representation of the currently buffered {@link MediaChunk}s.
|
||||||
|
*/
|
||||||
|
void disable(List<? extends MediaChunk> queue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,15 @@ public final class MultiTrackChunkSource implements ChunkSource, ExoPlayerCompon
|
|||||||
return allSources.length;
|
return allSources.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prepare() {
|
||||||
|
boolean prepared = true;
|
||||||
|
for (int i = 0; i < allSources.length; i++) {
|
||||||
|
prepared &= allSources[i].prepare();
|
||||||
|
}
|
||||||
|
return prepared;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTrackCount() {
|
public int getTrackCount() {
|
||||||
return selectedSource.getTrackCount();
|
return selectedSource.getTrackCount();
|
||||||
|
@ -54,6 +54,11 @@ public final class SingleSampleChunkSource implements ChunkSource {
|
|||||||
this.mediaFormat = mediaFormat;
|
this.mediaFormat = mediaFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prepare() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTrackCount() {
|
public int getTrackCount() {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -290,6 +290,11 @@ public class DashChunkSource implements ChunkSource {
|
|||||||
? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
|
? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prepare() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTrackCount() {
|
public int getTrackCount() {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -186,6 +186,11 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||||||
? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
|
? format.copyWithMaxVideoDimension(maxWidth, maxHeight) : format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prepare() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTrackCount() {
|
public int getTrackCount() {
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user