ExoPlayer之SampleQueue
SampleQueue的作用
代码中关于SampleQueue的注释说明 - A queue of media samples.
SampleQueue对应于媒体文件数据采样的处理:
ProgressiveMediaPeriod在startLoading方法中会通过Loader对象在后台线程执行内部类ExtractingLoadable.load方法开始加载media data。 然后交由extractor.read()处理,最终由trackOutput(SampleQueue)真正开始从ExtractorInput中采样。采样的media data会保存到SampleDataQueue中,SampleDataQueue相当于是一个容器。
接口说明
com.google.android.exoplayer2.source.SampleQueue:
public class SampleQueue implements TrackOutput {
...
/**
* Creates a sample queue.
*
* @param allocator An {@link Allocator} from which allocations for sample data can be obtained.
* @param playbackLooper The looper associated with the media playback thread.
* @param drmSessionManager The {@link DrmSessionManager} to obtain {@link DrmSession DrmSessions}
* from. The created instance does not take ownership of this {@link DrmSessionManager}.
*/
public SampleQueue(Allocator allocator, Looper playbackLooper, DrmSessionManager<?> drmSessionManager) {
sampleDataQueue = new SampleDataQueue(allocator);
this.playbackLooper = playbackLooper;
this.drmSessionManager = drmSessionManager;
extrasHolder = new SampleExtrasHolder();
capacity = SAMPLE_CAPACITY_INCREMENT;
sourceIds = new int[capacity];
offsets = new long[capacity];
timesUs = new long[capacity];
flags = new int[capacity];
sizes = new int[capacity];
cryptoDatas = new CryptoData[capacity];
formats = new Format[capacity];
largestDiscardedTimestampUs = Long.MIN_VALUE;
largestQueuedTimestampUs = Long.MIN_VALUE;
upstreamFormatRequired = true;
upstreamKeyframeRequired = true;
}
...
/**
* Returns whether there is data available for reading.
*
* <p>Note: If the stream has ended then a buffer with the end of stream flag can always be read
* from {@link #read}. Hence an ended stream is always ready.
*
* @param loadingFinished Whether no more samples will be written to the sample queue. When true,
* this method returns true if the sample queue is empty, because an empty sample queue means
* the end of stream has been reached. When false, this method returns false if the sample
* queue is empty.
*/
@SuppressWarnings("ReferenceEquality") // See comments in setUpstreamFormat
@CallSuper
public synchronized boolean isReady(boolean loadingFinished) {
if (!hasNextSample()) {
return loadingFinished
|| isLastSampleQueued
|| (upstreamFormat != null && upstreamFormat != downstreamFormat);
}
int relativeReadIndex = getRelativeIndex(readPosition);
if (formats[relativeReadIndex] != downstreamFormat) {
// A format can be read.
return true;
}
return mayReadSample(relativeReadIndex);
}
/**
* Attempts to read from the queue.
*
* <p>{@link Format Formats} read from this method may be associated to a {@link DrmSession}
* through {@link FormatHolder#drmSession}, which is populated in two scenarios:
*
* <ul>
* <li>The {@link Format} has a non-null {@link Format#drmInitData}.
* <li>The {@link DrmSessionManager} provides placeholder sessions for this queue's track type.
* See {@link DrmSessionManager#acquirePlaceholderSession(Looper, int)}.
* </ul>
*
* @param formatHolder A {@link FormatHolder} to populate in the case of reading a format.
* @param buffer A {@link DecoderInputBuffer} to populate in the case of reading a sample or the
* end of the stream. If the end of the stream has been reached, the {@link
* C#BUFFER_FLAG_END_OF_STREAM} flag will be set on the buffer. If a {@link
* DecoderInputBuffer#isFlagsOnly() flags-only} buffer is passed, only the buffer flags may be
* populated by this method and the read position of the queue will not change.
* @param formatRequired Whether the caller requires that the format of the stream be read even if
* it's not changing. A sample will never be read if set to true, however it is still possible
* for the end of stream or nothing to be read.
* @param loadingFinished True if an empty queue should be considered the end of the stream.
* @param decodeOnlyUntilUs If a buffer is read, the {@link C#BUFFER_FLAG_DECODE_ONLY} flag will
* be set if the buffer's timestamp is less than this value.
* @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or
* {@link C#RESULT_BUFFER_READ}.
*/
@CallSuper
public int read(
FormatHolder formatHolder,
DecoderInputBuffer buffer,
boolean formatRequired,
boolean loadingFinished,
long decodeOnlyUntilUs) {
int result =
readSampleMetadata(
formatHolder, buffer, formatRequired, loadingFinished, decodeOnlyUntilUs, extrasHolder);
if (result == C.RESULT_BUFFER_READ && !buffer.isEndOfStream() && !buffer.isFlagsOnly()) {
sampleDataQueue.readToBuffer(buffer