mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Remove requirement to specify downstream renderer count.
This makes it so that it's no longer necessary to specify the number of downstream renderers to HlsSampleSource, FrameworkSampleSource and ExtractorSampleSource, by forcing the downstream renderers to register with the SampleSource instances in their constructors. This eliminates a common source of subtle client bugs where the passed value is incorrect.
This commit is contained in:
parent
15dc87b037
commit
a70c1f1a4b
16 changed files with 205 additions and 161 deletions
|
|
@ -57,7 +57,7 @@ public class ExtractorRendererBuilder implements RendererBuilder {
|
|||
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(player.getMainHandler(),
|
||||
null);
|
||||
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
|
||||
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, extractor, 2,
|
||||
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, extractor,
|
||||
BUFFER_SIZE);
|
||||
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
|
||||
null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, null, player.getMainHandler(),
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
|
|||
HlsChunkSource chunkSource = new HlsChunkSource(dataSource, url, manifest, bandwidthMeter,
|
||||
variantIndices, HlsChunkSource.ADAPTIVE_MODE_SPLICE, audioCapabilities);
|
||||
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl,
|
||||
BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, 3, mainHandler, player, DemoPlayer.TYPE_VIDEO);
|
||||
BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, mainHandler, player, DemoPlayer.TYPE_VIDEO);
|
||||
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
|
||||
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, mainHandler, player, 50);
|
||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ public class VideoPlayer extends Activity implements OnClickListener,
|
|||
ExtractorSampleSource sampleSource = new ExtractorSampleSource(
|
||||
Uri.fromFile(new File(filename)),
|
||||
new DefaultUriDataSource(this, Util.getUserAgent(this, "ExoPlayerExtWebMDemo")),
|
||||
new WebmExtractor(), 2, EXTRACTOR_BUFFER_SIZE);
|
||||
new WebmExtractor(), EXTRACTOR_BUFFER_SIZE);
|
||||
TrackRenderer videoRenderer =
|
||||
new LibvpxVideoTrackRenderer(sampleSource, true, handler, this, 50);
|
||||
if (useOpenGL) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.ExoPlayer;
|
|||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.audio.AudioTrack;
|
||||
import com.google.android.exoplayer.ext.opus.OpusDecoderWrapper.InputBuffer;
|
||||
|
|
@ -74,7 +75,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer {
|
|||
*/
|
||||
public static final int MSG_SET_VOLUME = 1;
|
||||
|
||||
private final SampleSource source;
|
||||
private final SampleSourceReader source;
|
||||
private final Handler eventHandler;
|
||||
private final EventListener eventListener;
|
||||
private final MediaFormatHolder formatHolder;
|
||||
|
|
@ -109,7 +110,7 @@ public class LibopusAudioTrackRenderer extends TrackRenderer {
|
|||
*/
|
||||
public LibopusAudioTrackRenderer(SampleSource source, Handler eventHandler,
|
||||
EventListener eventListener) {
|
||||
this.source = source;
|
||||
this.source = source.register();
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.ExoPlayer;
|
|||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.InputBuffer;
|
||||
import com.google.android.exoplayer.ext.vp9.VpxDecoderWrapper.OutputBuffer;
|
||||
|
|
@ -90,7 +91,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
|||
public static final int MSG_SET_SURFACE = 1;
|
||||
public static final int MSG_SET_VPX_SURFACE_VIEW = 2;
|
||||
|
||||
private final SampleSource source;
|
||||
private final SampleSourceReader source;
|
||||
private final boolean scaleToFit;
|
||||
private final Handler eventHandler;
|
||||
private final EventListener eventListener;
|
||||
|
|
@ -141,7 +142,7 @@ public class LibvpxVideoTrackRenderer extends TrackRenderer {
|
|||
*/
|
||||
public LibvpxVideoTrackRenderer(SampleSource source, boolean scaleToFit,
|
||||
Handler eventHandler, EventListener eventListener, int maxDroppedFrameCountToNotify) {
|
||||
this.source = source;
|
||||
this.source = source.register();
|
||||
this.scaleToFit = scaleToFit;
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.extractor.ExtractorSampleSource;
|
||||
import com.google.android.exoplayer.extractor.mp4.Mp4Extractor;
|
||||
|
|
@ -48,6 +49,7 @@ import java.util.UUID;
|
|||
* <li>Playing media whose container format is unknown and so needs to be inferred automatically.
|
||||
* </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Over time we hope to enhance {@link ExtractorSampleSource} to support these use cases, and hence
|
||||
* make use of this class unnecessary.
|
||||
*/
|
||||
|
|
@ -55,7 +57,7 @@ import java.util.UUID;
|
|||
// through use of a background thread, or through changes to the framework's MediaExtractor API).
|
||||
@Deprecated
|
||||
@TargetApi(16)
|
||||
public final class FrameworkSampleSource implements SampleSource {
|
||||
public final class FrameworkSampleSource implements SampleSource, SampleSourceReader {
|
||||
|
||||
private static final int ALLOWED_FLAGS_MASK = C.SAMPLE_FLAG_SYNC | C.SAMPLE_FLAG_ENCRYPTED;
|
||||
|
||||
|
|
@ -88,17 +90,12 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||
* @param context Context for resolving {@code uri}.
|
||||
* @param uri The content URI from which to extract data.
|
||||
* @param headers Headers to send with requests for data.
|
||||
* @param downstreamRendererCount Number of track renderers dependent on this sample source.
|
||||
*/
|
||||
public FrameworkSampleSource(Context context, Uri uri, Map<String, String> headers,
|
||||
int downstreamRendererCount) {
|
||||
public FrameworkSampleSource(Context context, Uri uri, Map<String, String> headers) {
|
||||
Assertions.checkState(Util.SDK_INT >= 16);
|
||||
this.remainingReleaseCount = downstreamRendererCount;
|
||||
|
||||
this.context = Assertions.checkNotNull(context);
|
||||
this.uri = Assertions.checkNotNull(uri);
|
||||
this.headers = headers;
|
||||
|
||||
fileDescriptor = null;
|
||||
fileDescriptorOffset = 0;
|
||||
fileDescriptorLength = 0;
|
||||
|
|
@ -109,22 +106,24 @@ public final class FrameworkSampleSource implements SampleSource {
|
|||
* The caller is responsible for releasing the file descriptor.
|
||||
*
|
||||
* @param fileDescriptor File descriptor from which to read.
|
||||
* @param offset The offset in bytes into the file where the data to be extracted starts.
|
||||
* @param length The length in bytes of the data to be extracted.
|
||||
* @param downstreamRendererCount Number of track renderers dependent on this sample source.
|
||||
* @param fileDescriptorOffset The offset in bytes where the data to be extracted starts.
|
||||
* @param fileDescriptorLength The length in bytes of the data to be extracted.
|
||||
*/
|
||||
public FrameworkSampleSource(FileDescriptor fileDescriptor, long offset, long length,
|
||||
int downstreamRendererCount) {
|
||||
public FrameworkSampleSource(FileDescriptor fileDescriptor, long fileDescriptorOffset,
|
||||
long fileDescriptorLength) {
|
||||
Assertions.checkState(Util.SDK_INT >= 16);
|
||||
this.remainingReleaseCount = downstreamRendererCount;
|
||||
|
||||
this.fileDescriptor = Assertions.checkNotNull(fileDescriptor);
|
||||
this.fileDescriptorOffset = fileDescriptorOffset;
|
||||
this.fileDescriptorLength = fileDescriptorLength;
|
||||
context = null;
|
||||
uri = null;
|
||||
headers = null;
|
||||
}
|
||||
|
||||
this.fileDescriptor = Assertions.checkNotNull(fileDescriptor);
|
||||
fileDescriptorOffset = offset;
|
||||
fileDescriptorLength = length;
|
||||
@Override
|
||||
public SampleSourceReader register() {
|
||||
remainingReleaseCount++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.google.android.exoplayer;
|
||||
|
||||
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
import com.google.android.exoplayer.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
|
@ -182,7 +183,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final boolean playClearSamplesWithoutKeys;
|
||||
private final SampleSource source;
|
||||
private final SampleSourceReader source;
|
||||
private final SampleHolder sampleHolder;
|
||||
private final MediaFormatHolder formatHolder;
|
||||
private final List<Long> decodeOnlyPresentationTimestamps;
|
||||
|
|
@ -229,7 +230,7 @@ public abstract class MediaCodecTrackRenderer extends TrackRenderer {
|
|||
public MediaCodecTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener) {
|
||||
Assertions.checkState(Util.SDK_INT >= 16);
|
||||
this.source = source;
|
||||
this.source = source.register();
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
|
||||
this.eventHandler = eventHandler;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ import java.io.IOException;
|
|||
* A source of media samples.
|
||||
* <p>
|
||||
* A {@link SampleSource} may expose one or multiple tracks. The number of tracks and information
|
||||
* about each can be queried using {@link #getTrackCount()} and {@link #getTrackInfo(int)}
|
||||
* respectively.
|
||||
* about each can be queried using {@link SampleSourceReader#getTrackCount()} and
|
||||
* {@link SampleSourceReader#getTrackInfo(int)} respectively.
|
||||
*/
|
||||
public interface SampleSource {
|
||||
|
||||
|
|
@ -51,111 +51,133 @@ public interface SampleSource {
|
|||
public static final int DISCONTINUITY_READ = -5;
|
||||
|
||||
/**
|
||||
* Prepares the source.
|
||||
* A consumer of samples should call this method to register themselves and gain access to the
|
||||
* source through the returned {@link SampleSourceReader}.
|
||||
* <p>
|
||||
* Preparation may require reading from the data source (e.g. to determine the available tracks
|
||||
* 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.
|
||||
* {@link SampleSourceReader#release()} should be called on the returned object when access is no
|
||||
* longer required.
|
||||
*
|
||||
* @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.
|
||||
* @return A {@link SampleSourceReader} that provides access to the source.
|
||||
*/
|
||||
public boolean prepare(long positionUs) throws IOException;
|
||||
public SampleSourceReader register();
|
||||
|
||||
/**
|
||||
* Returns the number of tracks exposed by the source.
|
||||
*
|
||||
* @return The number of tracks.
|
||||
* An interface providing read access to a {@link SampleSource}.
|
||||
*/
|
||||
public int getTrackCount();
|
||||
public interface SampleSourceReader {
|
||||
|
||||
/**
|
||||
* Returns information about the specified track.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @return Information about the specified track.
|
||||
*/
|
||||
public TrackInfo getTrackInfo(int track);
|
||||
/**
|
||||
* Prepares the source.
|
||||
* <p>
|
||||
* Preparation may require reading from the data source (e.g. to determine the available tracks
|
||||
* 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(long positionUs) throws IOException;
|
||||
|
||||
/**
|
||||
* Enable the specified track. This allows the track's format and samples to be read from
|
||||
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @param track The track to enable.
|
||||
* @param positionUs The player's current playback position.
|
||||
*/
|
||||
public void enable(int track, long positionUs);
|
||||
/**
|
||||
* Returns the number of tracks exposed by the source.
|
||||
*
|
||||
* @return The number of tracks.
|
||||
*/
|
||||
public int getTrackCount();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* Returns information about the specified track.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @return Information about the specified track.
|
||||
*/
|
||||
public TrackInfo getTrackInfo(int track);
|
||||
|
||||
/**
|
||||
* Indicates to the source that it should still be buffering data.
|
||||
*
|
||||
* @param positionUs The current playback position.
|
||||
* @return True if the source 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(long positionUs) throws IOException;
|
||||
/**
|
||||
* Enable the specified track. This allows the track's format and samples to be read from
|
||||
* {@link #readData(int, long, MediaFormatHolder, SampleHolder, boolean)}.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @param track The track to enable.
|
||||
* @param positionUs The player's current playback position.
|
||||
*/
|
||||
public void enable(int track, long positionUs);
|
||||
|
||||
/**
|
||||
* Attempts to read either a sample, a new format or or a discontinuity from the source.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
* <p>
|
||||
* 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
|
||||
* than the one for which data was requested.
|
||||
*
|
||||
* @param track The track from which to read.
|
||||
* @param positionUs The current playback position.
|
||||
* @param formatHolder A {@link MediaFormatHolder} object to populate in the case of a new format.
|
||||
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample. If
|
||||
* the caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
||||
* references a valid output buffer.
|
||||
* @param onlyReadDiscontinuity Whether to only read a discontinuity. If true, only
|
||||
* {@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;
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Seeks to the specified time in microseconds.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @param positionUs The seek position in microseconds.
|
||||
*/
|
||||
public void seekToUs(long positionUs);
|
||||
/**
|
||||
* Indicates to the source that it should still be buffering data.
|
||||
*
|
||||
* @param positionUs The current playback position.
|
||||
* @return True if the source 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(long positionUs) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns an estimate of the position up to which data is buffered.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @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#UNKNOWN_TIME_US} if no estimate is available.
|
||||
*/
|
||||
public long getBufferedPositionUs();
|
||||
/**
|
||||
* Attempts to read either a sample, a new format or or a discontinuity from the source.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
* <p>
|
||||
* 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
|
||||
* than the one for which data was requested.
|
||||
*
|
||||
* @param track The track from which to read.
|
||||
* @param positionUs The current playback position.
|
||||
* @param formatHolder A {@link MediaFormatHolder} object to populate in the case of a new
|
||||
* format.
|
||||
* @param sampleHolder A {@link SampleHolder} object to populate in the case of a new sample.
|
||||
* If the caller requires the sample data then it must ensure that {@link SampleHolder#data}
|
||||
* references a valid output buffer.
|
||||
* @param onlyReadDiscontinuity Whether to only read a discontinuity. If true, only
|
||||
* {@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;
|
||||
|
||||
/**
|
||||
* Releases the {@link SampleSource}.
|
||||
*/
|
||||
public void release();
|
||||
/**
|
||||
* Seeks to the specified time in microseconds.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @param positionUs The seek position in microseconds.
|
||||
*/
|
||||
public void seekToUs(long positionUs);
|
||||
|
||||
/**
|
||||
* Returns an estimate of the position up to which data is buffered.
|
||||
* <p>
|
||||
* This method should not be called until after the source has been successfully prepared.
|
||||
*
|
||||
* @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#UNKNOWN_TIME_US} if no estimate is available.
|
||||
*/
|
||||
public long getBufferedPositionUs();
|
||||
|
||||
/**
|
||||
* Releases the {@link SampleSourceReader}.
|
||||
* <p>
|
||||
* This method should be called when access to the {@link SampleSource} is no longer required.
|
||||
*/
|
||||
public void release();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package com.google.android.exoplayer.chunk;
|
|||
|
||||
import com.google.android.exoplayer.C;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
|
@ -90,7 +91,7 @@ public interface BaseChunkSampleSourceEventListener {
|
|||
|
||||
/**
|
||||
* Invoked when the downstream format changes (i.e. when the format being supplied to the
|
||||
* caller of {@link SampleSource#readData} changes).
|
||||
* caller of {@link SampleSourceReader#readData} changes).
|
||||
*
|
||||
* @param sourceId The id of the reporting {@link SampleSource}.
|
||||
* @param format The format.
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.google.android.exoplayer.MediaFormat;
|
|||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.extractor.DefaultTrackOutput;
|
||||
|
|
@ -40,7 +41,7 @@ import java.util.List;
|
|||
* A {@link SampleSource} that loads media in {@link Chunk}s, which are themselves obtained from a
|
||||
* {@link ChunkSource}.
|
||||
*/
|
||||
public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
||||
public class ChunkSampleSource implements SampleSource, SampleSourceReader, Loader.Callback {
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be notified of {@link ChunkSampleSource} events.
|
||||
|
|
@ -52,9 +53,10 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
|||
*/
|
||||
public static final int DEFAULT_MIN_LOADABLE_RETRY_COUNT = 3;
|
||||
|
||||
private static final int STATE_UNPREPARED = 0;
|
||||
private static final int STATE_PREPARED = 1;
|
||||
private static final int STATE_ENABLED = 2;
|
||||
private static final int STATE_IDLE = 0;
|
||||
private static final int STATE_INITIALIZED = 1;
|
||||
private static final int STATE_PREPARED = 2;
|
||||
private static final int STATE_ENABLED = 3;
|
||||
|
||||
private static final int NO_RESET_PENDING = -1;
|
||||
|
||||
|
|
@ -116,13 +118,23 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
|||
mediaChunks = new LinkedList<>();
|
||||
readOnlyMediaChunks = Collections.unmodifiableList(mediaChunks);
|
||||
sampleQueue = new DefaultTrackOutput(loadControl.getAllocator());
|
||||
state = STATE_UNPREPARED;
|
||||
state = STATE_IDLE;
|
||||
pendingResetPositionUs = NO_RESET_PENDING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleSourceReader register() {
|
||||
Assertions.checkState(state == STATE_IDLE);
|
||||
state = STATE_INITIALIZED;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(long positionUs) {
|
||||
Assertions.checkState(state == STATE_UNPREPARED);
|
||||
Assertions.checkState(state == STATE_INITIALIZED || state == STATE_PREPARED);
|
||||
if (state == STATE_PREPARED) {
|
||||
return true;
|
||||
}
|
||||
loader = new Loader("Loader:" + chunkSource.getTrackInfo().mimeType);
|
||||
state = STATE_PREPARED;
|
||||
return true;
|
||||
|
|
@ -130,13 +142,13 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
|||
|
||||
@Override
|
||||
public int getTrackCount() {
|
||||
Assertions.checkState(state != STATE_UNPREPARED);
|
||||
Assertions.checkState(state == STATE_PREPARED || state == STATE_ENABLED);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackInfo getTrackInfo(int track) {
|
||||
Assertions.checkState(state != STATE_UNPREPARED);
|
||||
Assertions.checkState(state == STATE_PREPARED || state == STATE_ENABLED);
|
||||
Assertions.checkState(track == 0);
|
||||
return chunkSource.getTrackInfo();
|
||||
}
|
||||
|
|
@ -315,7 +327,7 @@ public class ChunkSampleSource implements SampleSource, Loader.Callback {
|
|||
loader.release();
|
||||
loader = null;
|
||||
}
|
||||
state = STATE_UNPREPARED;
|
||||
state = STATE_IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.MediaFormat;
|
|||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.drm.DrmInitData;
|
||||
|
|
@ -40,7 +41,8 @@ import java.io.IOException;
|
|||
/**
|
||||
* A {@link SampleSource} that extracts sample data using an {@link Extractor}
|
||||
*/
|
||||
public class ExtractorSampleSource implements SampleSource, ExtractorOutput, Loader.Callback {
|
||||
public class ExtractorSampleSource implements SampleSource, SampleSourceReader, ExtractorOutput,
|
||||
Loader.Callback {
|
||||
|
||||
/**
|
||||
* The default minimum number of times to retry loading prior to failing for on-demand streams.
|
||||
|
|
@ -102,32 +104,28 @@ public class ExtractorSampleSource implements SampleSource, ExtractorOutput, Loa
|
|||
* @param uri The {@link Uri} of the media stream.
|
||||
* @param dataSource A data source to read the media stream.
|
||||
* @param extractor An {@link Extractor} to extract the media stream.
|
||||
* @param downstreamRendererCount Number of track renderers dependent on this sample source.
|
||||
* @param requestedBufferSize The requested total buffer size for storing sample data, in bytes.
|
||||
* The actual allocated size may exceed the value passed in if the implementation requires it.
|
||||
*/
|
||||
public ExtractorSampleSource(Uri uri, DataSource dataSource, Extractor extractor,
|
||||
int downstreamRendererCount, int requestedBufferSize) {
|
||||
this(uri, dataSource, extractor, downstreamRendererCount, requestedBufferSize,
|
||||
MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA);
|
||||
int requestedBufferSize) {
|
||||
this(uri, dataSource, extractor, requestedBufferSize, MIN_RETRY_COUNT_DEFAULT_FOR_MEDIA);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The {@link Uri} of the media stream.
|
||||
* @param dataSource A data source to read the media stream.
|
||||
* @param extractor An {@link Extractor} to extract the media stream.
|
||||
* @param downstreamRendererCount Number of track renderers dependent on this sample source.
|
||||
* @param requestedBufferSize The requested total buffer size for storing sample data, in bytes.
|
||||
* The actual allocated size may exceed the value passed in if the implementation requires it.
|
||||
* @param minLoadableRetryCount The minimum number of times that the sample source will retry
|
||||
* if a loading error occurs.
|
||||
*/
|
||||
public ExtractorSampleSource(Uri uri, DataSource dataSource, Extractor extractor,
|
||||
int downstreamRendererCount, int requestedBufferSize, int minLoadableRetryCount) {
|
||||
int requestedBufferSize, int minLoadableRetryCount) {
|
||||
this.uri = uri;
|
||||
this.dataSource = dataSource;
|
||||
this.extractor = extractor;
|
||||
this.remainingReleaseCount = downstreamRendererCount;
|
||||
this.requestedBufferSize = requestedBufferSize;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
sampleQueues = new SparseArray<>();
|
||||
|
|
@ -137,6 +135,12 @@ public class ExtractorSampleSource implements SampleSource, ExtractorOutput, Loa
|
|||
extractor.init(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleSourceReader register() {
|
||||
remainingReleaseCount++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(long positionUs) throws IOException {
|
||||
if (prepared) {
|
||||
|
|
@ -148,9 +152,6 @@ public class ExtractorSampleSource implements SampleSource, ExtractorOutput, Loa
|
|||
|
||||
continueBufferingInternal();
|
||||
|
||||
// TODO: Support non-seekable content? Or at least avoid getting stuck here if a seekMap doesn't
|
||||
// arrive (we may end up filling the sample buffers whilst we're still not prepared, and then
|
||||
// getting stuck).
|
||||
if (seekMap != null && tracksBuilt && haveFormatsForAllTracks()) {
|
||||
int trackCount = sampleQueues.size();
|
||||
trackEnabledStates = new boolean[trackCount];
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.google.android.exoplayer.MediaFormat;
|
|||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackInfo;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.chunk.BaseChunkSampleSourceEventListener;
|
||||
|
|
@ -39,7 +40,7 @@ import java.util.LinkedList;
|
|||
/**
|
||||
* A {@link SampleSource} for HLS streams.
|
||||
*/
|
||||
public class HlsSampleSource implements SampleSource, Loader.Callback {
|
||||
public class HlsSampleSource implements SampleSource, SampleSourceReader, Loader.Callback {
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be notified of {@link HlsSampleSource} events.
|
||||
|
|
@ -91,28 +92,24 @@ public class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||
private long currentLoadStartTimeMs;
|
||||
|
||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||
int bufferSizeContribution, boolean frameAccurateSeeking, int downstreamRendererCount) {
|
||||
this(chunkSource, loadControl, bufferSizeContribution, frameAccurateSeeking,
|
||||
downstreamRendererCount, null, null, 0);
|
||||
int bufferSizeContribution, boolean frameAccurateSeeking) {
|
||||
this(chunkSource, loadControl, bufferSizeContribution, frameAccurateSeeking, null, null, 0);
|
||||
}
|
||||
|
||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||
int bufferSizeContribution, boolean frameAccurateSeeking, int downstreamRendererCount,
|
||||
Handler eventHandler, EventListener eventListener, int eventSourceId) {
|
||||
this(chunkSource, loadControl, bufferSizeContribution, frameAccurateSeeking,
|
||||
downstreamRendererCount, eventHandler, eventListener, eventSourceId,
|
||||
DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
||||
int bufferSizeContribution, boolean frameAccurateSeeking, Handler eventHandler,
|
||||
EventListener eventListener, int eventSourceId) {
|
||||
this(chunkSource, loadControl, bufferSizeContribution, frameAccurateSeeking, eventHandler,
|
||||
eventListener, eventSourceId, DEFAULT_MIN_LOADABLE_RETRY_COUNT);
|
||||
}
|
||||
|
||||
public HlsSampleSource(HlsChunkSource chunkSource, LoadControl loadControl,
|
||||
int bufferSizeContribution, boolean frameAccurateSeeking, int downstreamRendererCount,
|
||||
Handler eventHandler, EventListener eventListener, int eventSourceId,
|
||||
int minLoadableRetryCount) {
|
||||
int bufferSizeContribution, boolean frameAccurateSeeking, Handler eventHandler,
|
||||
EventListener eventListener, int eventSourceId, int minLoadableRetryCount) {
|
||||
this.chunkSource = chunkSource;
|
||||
this.loadControl = loadControl;
|
||||
this.bufferSizeContribution = bufferSizeContribution;
|
||||
this.frameAccurateSeeking = frameAccurateSeeking;
|
||||
this.remainingReleaseCount = downstreamRendererCount;
|
||||
this.minLoadableRetryCount = minLoadableRetryCount;
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
|
|
@ -121,6 +118,12 @@ public class HlsSampleSource implements SampleSource, Loader.Callback {
|
|||
extractors = new LinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleSourceReader register() {
|
||||
remainingReleaseCount++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean prepare(long positionUs) throws IOException {
|
||||
if (prepared) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
|||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
|
|
@ -54,7 +55,7 @@ public class MetadataTrackRenderer<T> extends TrackRenderer implements Callback
|
|||
|
||||
private static final int MSG_INVOKE_RENDERER = 0;
|
||||
|
||||
private final SampleSource source;
|
||||
private final SampleSourceReader source;
|
||||
private final MetadataParser<T> metadataParser;
|
||||
private final MetadataRenderer<T> metadataRenderer;
|
||||
private final Handler metadataHandler;
|
||||
|
|
@ -80,7 +81,7 @@ public class MetadataTrackRenderer<T> extends TrackRenderer implements Callback
|
|||
*/
|
||||
public MetadataTrackRenderer(SampleSource source, MetadataParser<T> metadataParser,
|
||||
MetadataRenderer<T> metadataRenderer, Looper metadataRendererLooper) {
|
||||
this.source = Assertions.checkNotNull(source);
|
||||
this.source = source.register();
|
||||
this.metadataParser = Assertions.checkNotNull(metadataParser);
|
||||
this.metadataRenderer = Assertions.checkNotNull(metadataRenderer);
|
||||
this.metadataHandler = metadataRendererLooper == null ? null
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
|||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
|
|
@ -44,7 +45,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
|||
|
||||
private final Handler textRendererHandler;
|
||||
private final TextRenderer textRenderer;
|
||||
private final SampleSource source;
|
||||
private final SampleSourceReader source;
|
||||
private final MediaFormatHolder formatHolder;
|
||||
private final SubtitleParser[] subtitleParsers;
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ public class TextTrackRenderer extends TrackRenderer implements Callback {
|
|||
*/
|
||||
public TextTrackRenderer(SampleSource source, TextRenderer textRenderer,
|
||||
Looper textRendererLooper, SubtitleParser... subtitleParsers) {
|
||||
this.source = Assertions.checkNotNull(source);
|
||||
this.source = source.register();
|
||||
this.textRenderer = Assertions.checkNotNull(textRenderer);
|
||||
this.textRendererHandler = textRendererLooper == null ? null
|
||||
: new Handler(textRendererLooper, this);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer.ExoPlaybackException;
|
|||
import com.google.android.exoplayer.MediaFormatHolder;
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
import com.google.android.exoplayer.SampleSource;
|
||||
import com.google.android.exoplayer.SampleSource.SampleSourceReader;
|
||||
import com.google.android.exoplayer.TrackRenderer;
|
||||
import com.google.android.exoplayer.text.Cue;
|
||||
import com.google.android.exoplayer.text.TextRenderer;
|
||||
|
|
@ -52,7 +53,7 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
|
|||
// The maximum duration that captions are parsed ahead of the current position.
|
||||
private static final int MAX_SAMPLE_READAHEAD_US = 5000000;
|
||||
|
||||
private final SampleSource source;
|
||||
private final SampleSourceReader source;
|
||||
private final Eia608Parser eia608Parser;
|
||||
private final TextRenderer textRenderer;
|
||||
private final Handler textRendererHandler;
|
||||
|
|
@ -81,7 +82,7 @@ public class Eia608TrackRenderer extends TrackRenderer implements Callback {
|
|||
*/
|
||||
public Eia608TrackRenderer(SampleSource source, TextRenderer textRenderer,
|
||||
Looper textRendererLooper) {
|
||||
this.source = Assertions.checkNotNull(source);
|
||||
this.source = source.register();
|
||||
this.textRenderer = Assertions.checkNotNull(textRenderer);
|
||||
textRendererHandler = textRendererLooper == null ? null : new Handler(textRendererLooper, this);
|
||||
eia608Parser = new Eia608Parser();
|
||||
|
|
|
|||
|
|
@ -570,7 +570,7 @@ public class Mp4ExtractorTest extends TestCase {
|
|||
@Override
|
||||
public void run() {
|
||||
final ExtractorSampleSource source = new ExtractorSampleSource(FAKE_URI, dataSource,
|
||||
new Mp4Extractor(), 1, 2 * 1024 * 1024);
|
||||
new Mp4Extractor(), 2 * 1024 * 1024);
|
||||
Looper.prepare();
|
||||
handler = new Handler() {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue