mirror of
https://github.com/samsonjs/media.git
synced 2026-04-03 10:55:48 +00:00
SampleStream/SampleQueue: Introduce read flags
- SampleQueue.peek is replaced with SampleQueue.read with FLAG_PEEK. This also exposes peek functionality through SampleStream. - Use of DecoderInputBuffer.isFlagsOnly is replaced with FLAG_OMIT_SAMPLE_DATA. This flag can be used with or without FLAG_PEEK, where-as previously the read position would never be advanced for an isFlagsOnly buffer. - formatRequired is replaced with FLAG_FORMAT_REQUIRED. PiperOrigin-RevId: 363460105
This commit is contained in:
parent
31f65f63ff
commit
2d9177b7c2
28 changed files with 293 additions and 224 deletions
|
|
@ -111,12 +111,8 @@ public class DecoderInputBuffer extends Buffer {
|
|||
@BufferReplacementMode private final int bufferReplacementMode;
|
||||
private final int paddingSize;
|
||||
|
||||
/**
|
||||
* Creates a new instance for which {@link #isFlagsOnly()} will return true.
|
||||
*
|
||||
* @return A new flags only input buffer.
|
||||
*/
|
||||
public static DecoderInputBuffer newFlagsOnlyInstance() {
|
||||
/** Returns a new instance that's not able to hold any data. */
|
||||
public static DecoderInputBuffer newNoDataInstance() {
|
||||
return new DecoderInputBuffer(BUFFER_REPLACEMENT_MODE_DISABLED);
|
||||
}
|
||||
|
||||
|
|
@ -200,14 +196,6 @@ public class DecoderInputBuffer extends Buffer {
|
|||
data = newData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the buffer is only able to hold flags, meaning {@link #data} is null and
|
||||
* its replacement mode is {@link #BUFFER_REPLACEMENT_MODE_DISABLED}.
|
||||
*/
|
||||
public final boolean isFlagsOnly() {
|
||||
return data == null && bufferReplacementMode == BUFFER_REPLACEMENT_MODE_DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the {@link C#BUFFER_FLAG_ENCRYPTED} flag is set.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import androidx.annotation.Nullable;
|
|||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer.InsufficientCapacityException;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadFlags;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
import java.io.IOException;
|
||||
|
|
@ -225,8 +227,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
* @param formats The enabled formats.
|
||||
* @param startPositionUs The start position of the new stream in renderer time (microseconds).
|
||||
* @param offsetUs The offset that will be added to the timestamps of buffers read via {@link
|
||||
* #readSource(FormatHolder, DecoderInputBuffer, boolean)} so that decoder input buffers have
|
||||
* monotonically increasing timestamps.
|
||||
* #readSource} so that decoder input buffers have monotonically increasing timestamps.
|
||||
* @throws ExoPlaybackException If an error occurs.
|
||||
*/
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
|
||||
|
|
@ -383,20 +384,17 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||
* @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.
|
||||
* @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.
|
||||
* @return The status of read, one of {@link SampleStream.ReadDataResult}.
|
||||
* @throws InsufficientCapacityException If the {@code buffer} is not a {@link
|
||||
* DecoderInputBuffer#isFlagsOnly() flags-only} buffer and has insufficient capacity to hold
|
||||
* @param readFlags Flags controlling the behavior of this read operation.
|
||||
* @return The {@link ReadDataResult result} of the read operation.
|
||||
* @throws InsufficientCapacityException If the {@code buffer} has insufficient capacity to hold
|
||||
* the data of a sample being read. The buffer {@link DecoderInputBuffer#timeUs timestamp} and
|
||||
* flags are populated if this exception is thrown, but the read position is not advanced.
|
||||
*/
|
||||
@SampleStream.ReadDataResult
|
||||
@ReadDataResult
|
||||
protected final int readSource(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) {
|
||||
@SampleStream.ReadDataResult
|
||||
int result = Assertions.checkNotNull(stream).readData(formatHolder, buffer, formatRequired);
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
@ReadDataResult
|
||||
int result = Assertions.checkNotNull(stream).readData(formatHolder, buffer, readFlags);
|
||||
if (result == C.RESULT_BUFFER_READ) {
|
||||
if (buffer.isEndOfStream()) {
|
||||
readingPositionUs = C.TIME_END_OF_SOURCE;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio;
|
|||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DISCARD_REASON_DRM_SESSION_CHANGED;
|
||||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DISCARD_REASON_REUSE_NOT_IMPLEMENTED;
|
||||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.REUSE_RESULT_NO;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import android.os.Handler;
|
||||
|
|
@ -45,7 +46,7 @@ import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
|||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MediaClock;
|
||||
|
|
@ -189,7 +190,7 @@ public abstract class DecoderAudioRenderer<
|
|||
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
||||
this.audioSink = audioSink;
|
||||
audioSink.setListener(new AudioSinkListener());
|
||||
flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
|
||||
flagsOnlyBuffer = DecoderInputBuffer.newNoDataInstance();
|
||||
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
|
||||
audioTrackNeedsConfigure = true;
|
||||
}
|
||||
|
|
@ -273,7 +274,7 @@ public abstract class DecoderAudioRenderer<
|
|||
// We don't have a format yet, so try and read one.
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
flagsOnlyBuffer.clear();
|
||||
@SampleStream.ReadDataResult int result = readSource(formatHolder, flagsOnlyBuffer, true);
|
||||
@ReadDataResult int result = readSource(formatHolder, flagsOnlyBuffer, FLAG_REQUIRE_FORMAT);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
onInputFormatChanged(formatHolder);
|
||||
} else if (result == C.RESULT_BUFFER_READ) {
|
||||
|
|
@ -438,7 +439,7 @@ public abstract class DecoderAudioRenderer<
|
|||
}
|
||||
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
switch (readSource(formatHolder, inputBuffer, /* formatRequired= */ false)) {
|
||||
switch (readSource(formatHolder, inputBuffer, /* readFlags= */ 0)) {
|
||||
case C.RESULT_NOTHING_READ:
|
||||
return false;
|
||||
case C.RESULT_FORMAT_READ:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.REUSE
|
|||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.REUSE_RESULT_YES_WITHOUT_RECONFIGURATION;
|
||||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.REUSE_RESULT_YES_WITH_FLUSH;
|
||||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.REUSE_RESULT_YES_WITH_RECONFIGURATION;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_OMIT_SAMPLE_DATA;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_PEEK;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||
import static java.lang.Math.max;
|
||||
|
|
@ -57,6 +60,8 @@ import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
|
|||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadFlags;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
|
|
@ -294,7 +299,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
private final MediaCodecSelector mediaCodecSelector;
|
||||
private final boolean enableDecoderFallback;
|
||||
private final float assumedMinimumCodecOperatingRate;
|
||||
private final DecoderInputBuffer flagsOnlyBuffer;
|
||||
private final DecoderInputBuffer noDataBuffer;
|
||||
private final DecoderInputBuffer buffer;
|
||||
private final DecoderInputBuffer bypassSampleBuffer;
|
||||
private final BatchBuffer bypassBatchBuffer;
|
||||
|
|
@ -388,7 +393,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
this.mediaCodecSelector = checkNotNull(mediaCodecSelector);
|
||||
this.enableDecoderFallback = enableDecoderFallback;
|
||||
this.assumedMinimumCodecOperatingRate = assumedMinimumCodecOperatingRate;
|
||||
flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
|
||||
noDataBuffer = DecoderInputBuffer.newNoDataInstance();
|
||||
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
||||
bypassSampleBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
|
||||
bypassBatchBuffer = new BatchBuffer();
|
||||
|
|
@ -816,7 +821,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
renderToEndOfStream();
|
||||
return;
|
||||
}
|
||||
if (inputFormat == null && !readToFlagsOnlyBuffer(/* requireFormat= */ true)) {
|
||||
if (inputFormat == null && !readSourceOmittingSampleData(FLAG_REQUIRE_FORMAT)) {
|
||||
// We still don't have a format and can't make progress without one.
|
||||
return;
|
||||
}
|
||||
|
|
@ -837,9 +842,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
decoderCounters.skippedInputBufferCount += skipSource(positionUs);
|
||||
// We need to read any format changes despite not having a codec so that drmSession can be
|
||||
// updated, and so that we have the most recent format should the codec be initialized. We
|
||||
// may also reach the end of the stream. Note that readSource will not read a sample into a
|
||||
// flags-only buffer.
|
||||
readToFlagsOnlyBuffer(/* requireFormat= */ false);
|
||||
// may also reach the end of the stream. FLAG_PEEK is used because we don't want to advance
|
||||
// the source further than skipSource has already done.
|
||||
readSourceOmittingSampleData(FLAG_PEEK);
|
||||
}
|
||||
decoderCounters.ensureUpdated();
|
||||
} catch (IllegalStateException e) {
|
||||
|
|
@ -972,16 +977,24 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
return new MediaCodecDecoderException(cause, codecInfo);
|
||||
}
|
||||
|
||||
/** Reads into {@link #flagsOnlyBuffer} and returns whether a {@link Format} was read. */
|
||||
private boolean readToFlagsOnlyBuffer(boolean requireFormat) throws ExoPlaybackException {
|
||||
/**
|
||||
* Reads from the source when sample data is not required. If a format or an end of stream buffer
|
||||
* is read, it will be handled before the call returns.
|
||||
*
|
||||
* @param readFlags Additional {@link ReadFlags}. {@link SampleStream#FLAG_OMIT_SAMPLE_DATA} is
|
||||
* added internally, and so does not need to be passed.
|
||||
* @return Whether a format was read and processed.
|
||||
*/
|
||||
private boolean readSourceOmittingSampleData(@SampleStream.ReadFlags int readFlags)
|
||||
throws ExoPlaybackException {
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
flagsOnlyBuffer.clear();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(formatHolder, flagsOnlyBuffer, requireFormat);
|
||||
noDataBuffer.clear();
|
||||
@ReadDataResult
|
||||
int result = readSource(formatHolder, noDataBuffer, readFlags | FLAG_OMIT_SAMPLE_DATA);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
onInputFormatChanged(formatHolder);
|
||||
return true;
|
||||
} else if (result == C.RESULT_BUFFER_READ && flagsOnlyBuffer.isEndOfStream()) {
|
||||
} else if (result == C.RESULT_BUFFER_READ && noDataBuffer.isEndOfStream()) {
|
||||
inputStreamEnded = true;
|
||||
processEndOfStream();
|
||||
}
|
||||
|
|
@ -1248,8 +1261,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
int adaptiveReconfigurationBytes = buffer.data.position();
|
||||
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(formatHolder, buffer, /* formatRequired= */ false);
|
||||
@ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */ 0);
|
||||
|
||||
if (hasReadStreamToEnd()) {
|
||||
// Notify output queue of the last buffer's timestamp.
|
||||
|
|
@ -2264,8 +2276,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||
bypassSampleBuffer.clear();
|
||||
while (true) {
|
||||
bypassSampleBuffer.clear();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(formatHolder, bypassSampleBuffer, /* formatRequired= */ false);
|
||||
@ReadDataResult int result = readSource(formatHolder, bypassSampleBuffer, /* readFlags= */ 0);
|
||||
switch (result) {
|
||||
case C.RESULT_FORMAT_READ:
|
||||
onInputFormatChanged(formatHolder);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -125,7 +125,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
|
|||
if (!inputStreamEnded && pendingMetadataCount < MAX_PENDING_METADATA_COUNT) {
|
||||
buffer.clear();
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
@SampleStream.ReadDataResult int result = readSource(formatHolder, buffer, false);
|
||||
@ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */ 0);
|
||||
if (result == C.RESULT_BUFFER_READ) {
|
||||
if (buffer.isEndOfStream()) {
|
||||
inputStreamEnded = true;
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||
|
||||
@Override
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) {
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
if (isPendingInitialDiscontinuity()) {
|
||||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
|
|
@ -307,7 +307,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
|
|||
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
@ReadDataResult int result = childStream.readData(formatHolder, buffer, requireFormat);
|
||||
@ReadDataResult int result = childStream.readData(formatHolder, buffer, readFlags);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
Format format = Assertions.checkNotNull(formatHolder.format);
|
||||
if (format.encoderDelay != 0 || format.encoderPadding != 0) {
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ public final class EmptySampleStream implements SampleStream {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||
boolean formatRequired) {
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -440,8 +440,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
|
||||
@Override
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) {
|
||||
int readResult = sampleStream.readData(formatHolder, buffer, formatRequired);
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
int readResult = sampleStream.readData(formatHolder, buffer, readFlags);
|
||||
if (readResult == C.RESULT_BUFFER_READ) {
|
||||
buffer.timeUs = max(0, buffer.timeUs + timeOffsetUs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import com.google.android.exoplayer2.extractor.TrackOutput;
|
|||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.icy.IcyHeaders;
|
||||
import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadFlags;
|
||||
import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
|
|
@ -478,13 +479,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
int sampleQueueIndex,
|
||||
FormatHolder formatHolder,
|
||||
DecoderInputBuffer buffer,
|
||||
boolean formatRequired) {
|
||||
@ReadFlags int readFlags) {
|
||||
if (suppressRead()) {
|
||||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
maybeNotifyDownstreamFormat(sampleQueueIndex);
|
||||
int result =
|
||||
sampleQueues[sampleQueueIndex].read(formatHolder, buffer, formatRequired, loadingFinished);
|
||||
sampleQueues[sampleQueueIndex].read(formatHolder, buffer, readFlags, loadingFinished);
|
||||
if (result == C.RESULT_NOTHING_READ) {
|
||||
maybeStartDeferredRetry(sampleQueueIndex);
|
||||
}
|
||||
|
|
@ -947,9 +948,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
}
|
||||
|
||||
@Override
|
||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||
boolean formatRequired) {
|
||||
return ProgressiveMediaPeriod.this.readData(track, formatHolder, buffer, formatRequired);
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
return ProgressiveMediaPeriod.this.readData(track, formatHolder, buffer, readFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.source;
|
||||
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_OMIT_SAMPLE_DATA;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_PEEK;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static java.lang.Math.max;
|
||||
|
|
@ -36,6 +39,7 @@ import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
|||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager.DrmSessionReference;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadFlags;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DataReader;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
|
|
@ -380,20 +384,6 @@ public class SampleQueue implements TrackOutput {
|
|||
return mayReadSample(getRelativeIndex(readPosition));
|
||||
}
|
||||
|
||||
/** Equivalent to {@link #read}, except it never advances the read position. */
|
||||
public final int peek(
|
||||
FormatHolder formatHolder,
|
||||
DecoderInputBuffer buffer,
|
||||
boolean formatRequired,
|
||||
boolean loadingFinished) {
|
||||
int result =
|
||||
peekSampleMetadata(formatHolder, buffer, formatRequired, loadingFinished, extrasHolder);
|
||||
if (result == C.RESULT_BUFFER_READ && !buffer.isEndOfStream() && !buffer.isFlagsOnly()) {
|
||||
sampleDataQueue.peekToBuffer(buffer, extrasHolder);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to read from the queue.
|
||||
*
|
||||
|
|
@ -403,18 +393,12 @@ public class SampleQueue implements TrackOutput {
|
|||
* @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 and a sample is read, then
|
||||
* only the buffer {@link DecoderInputBuffer#timeUs timestamp} and flags will be populated,
|
||||
* and the read position will not be advanced.
|
||||
* @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.
|
||||
* C#BUFFER_FLAG_END_OF_STREAM} flag will be set on the buffer.
|
||||
* @param readFlags Flags controlling the behavior of this read operation.
|
||||
* @param loadingFinished True if an empty queue should be considered the end of the stream.
|
||||
* @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or
|
||||
* {@link C#RESULT_BUFFER_READ}.
|
||||
* @throws InsufficientCapacityException If the {@code buffer} is not a {@link
|
||||
* DecoderInputBuffer#isFlagsOnly() flags-only} buffer and has insufficient capacity to hold
|
||||
* @throws InsufficientCapacityException If the {@code buffer} has insufficient capacity to hold
|
||||
* the data of a sample being read. The buffer {@link DecoderInputBuffer#timeUs timestamp} and
|
||||
* flags are populated if this exception is thrown, but the read position is not advanced.
|
||||
*/
|
||||
|
|
@ -422,13 +406,27 @@ public class SampleQueue implements TrackOutput {
|
|||
public int read(
|
||||
FormatHolder formatHolder,
|
||||
DecoderInputBuffer buffer,
|
||||
boolean formatRequired,
|
||||
@ReadFlags int readFlags,
|
||||
boolean loadingFinished) {
|
||||
int result =
|
||||
peekSampleMetadata(formatHolder, buffer, formatRequired, loadingFinished, extrasHolder);
|
||||
if (result == C.RESULT_BUFFER_READ && !buffer.isEndOfStream() && !buffer.isFlagsOnly()) {
|
||||
sampleDataQueue.readToBuffer(buffer, extrasHolder);
|
||||
readPosition++;
|
||||
peekSampleMetadata(
|
||||
formatHolder,
|
||||
buffer,
|
||||
/* formatRequired= */ (readFlags & FLAG_REQUIRE_FORMAT) != 0,
|
||||
loadingFinished,
|
||||
extrasHolder);
|
||||
if (result == C.RESULT_BUFFER_READ && !buffer.isEndOfStream()) {
|
||||
boolean peek = (readFlags & FLAG_PEEK) != 0;
|
||||
if ((readFlags & FLAG_OMIT_SAMPLE_DATA) == 0) {
|
||||
if (peek) {
|
||||
sampleDataQueue.peekToBuffer(buffer, extrasHolder);
|
||||
} else {
|
||||
sampleDataQueue.readToBuffer(buffer, extrasHolder);
|
||||
}
|
||||
}
|
||||
if (!peek) {
|
||||
readPosition++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,43 @@ import java.lang.annotation.RetentionPolicy;
|
|||
*/
|
||||
public interface SampleStream {
|
||||
|
||||
/** Return values of {@link #readData(FormatHolder, DecoderInputBuffer, boolean)}. */
|
||||
/**
|
||||
* Flags that can be specified when calling {@link #readData}. Possible flag values are {@link
|
||||
* #FLAG_PEEK}, {@link #FLAG_REQUIRE_FORMAT} and {@link #FLAG_OMIT_SAMPLE_DATA}.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(
|
||||
flag = true,
|
||||
value = {FLAG_PEEK, FLAG_REQUIRE_FORMAT, FLAG_OMIT_SAMPLE_DATA})
|
||||
@interface ReadFlags {}
|
||||
/** Specifies that the read position should not be advanced if a sample buffer is read. */
|
||||
int FLAG_PEEK = 1;
|
||||
/**
|
||||
* Specifies that if a sample buffer would normally be read next, the format of the stream should
|
||||
* be read instead. In detail, the effect of this flag is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If a sample buffer would be read were the flag not set, then the stream format will be
|
||||
* read instead.
|
||||
* <li>If nothing would be read were the flag not set, then the stream format will be read if
|
||||
* it's known. If the stream format is not known then behavior is unchanged.
|
||||
* <li>If an end of stream buffer would be read were the flag not set, then behavior is
|
||||
* unchanged.
|
||||
* </ul>
|
||||
*/
|
||||
int FLAG_REQUIRE_FORMAT = 1 << 1;
|
||||
/**
|
||||
* Specifies that {@link DecoderInputBuffer#data}, {@link DecoderInputBuffer#supplementalData} and
|
||||
* {@link DecoderInputBuffer#cryptoInfo} should not be populated when reading a sample buffer.
|
||||
*
|
||||
* <p>This flag is useful for efficiently reading or (when combined with {@link #FLAG_PEEK})
|
||||
* peeking sample metadata. It can also be used for efficiency by a caller wishing to skip a
|
||||
* sample buffer.
|
||||
*/
|
||||
int FLAG_OMIT_SAMPLE_DATA = 1 << 2;
|
||||
|
||||
/** Return values of {@link #readData}. */
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({C.RESULT_NOTHING_READ, C.RESULT_FORMAT_READ, C.RESULT_BUFFER_READ})
|
||||
|
|
@ -38,10 +74,9 @@ public interface SampleStream {
|
|||
|
||||
/**
|
||||
* Returns whether data is available to be read.
|
||||
* <p>
|
||||
* Note: If the stream has ended then a buffer with the end of stream flag can always be read from
|
||||
* {@link #readData(FormatHolder, DecoderInputBuffer, boolean)}. Hence an ended stream is always
|
||||
* ready.
|
||||
*
|
||||
* <p>Note: If the stream has ended then a buffer with the end of stream flag can always be read
|
||||
* from {@link #readData}. Hence an ended stream is always ready.
|
||||
*
|
||||
* @return Whether data is available to be read.
|
||||
*/
|
||||
|
|
@ -66,21 +101,15 @@ public interface SampleStream {
|
|||
* @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 and a sample is read, then
|
||||
* only the buffer {@link DecoderInputBuffer#timeUs timestamp} and flags will be populated,
|
||||
* and the read position will not be advanced.
|
||||
* @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.
|
||||
* @return The status of read, one of {@link ReadDataResult}.
|
||||
* @throws InsufficientCapacityException If the {@code buffer} is not a {@link
|
||||
* DecoderInputBuffer#isFlagsOnly() flags-only} buffer and has insufficient capacity to hold
|
||||
* C#BUFFER_FLAG_END_OF_STREAM} flag will be set on the buffer.
|
||||
* @param readFlags Flags controlling the behavior of this read operation.
|
||||
* @return The {@link ReadDataResult result} of the read operation.
|
||||
* @throws InsufficientCapacityException If the {@code buffer} has insufficient capacity to hold
|
||||
* the data of a sample being read. The buffer {@link DecoderInputBuffer#timeUs timestamp} and
|
||||
* flags are populated if this exception is thrown, but the read position is not advanced.
|
||||
*/
|
||||
@ReadDataResult
|
||||
int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired);
|
||||
int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags);
|
||||
|
||||
/**
|
||||
* Attempts to skip to the keyframe before the specified position, or to the end of the stream if
|
||||
|
|
@ -90,5 +119,4 @@ public interface SampleStream {
|
|||
* @return The number of samples that were skipped.
|
||||
*/
|
||||
int skipData(long positionUs);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,8 +292,8 @@ public final class SilenceMediaSource extends BaseMediaSource {
|
|||
|
||||
@Override
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) {
|
||||
if (!sentFormat || formatRequired) {
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
if (!sentFormat || (readFlags & FLAG_REQUIRE_FORMAT) != 0) {
|
||||
formatHolder.format = FORMAT;
|
||||
sentFormat = true;
|
||||
return C.RESULT_FORMAT_READ;
|
||||
|
|
@ -307,14 +307,14 @@ public final class SilenceMediaSource extends BaseMediaSource {
|
|||
|
||||
buffer.timeUs = getAudioPositionUs(positionBytes);
|
||||
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||
if (buffer.isFlagsOnly()) {
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
|
||||
int bytesToWrite = (int) min(SILENCE_SAMPLE.length, bytesRemaining);
|
||||
buffer.ensureSpaceForWrite(bytesToWrite);
|
||||
buffer.data.put(SILENCE_SAMPLE, /* offset= */ 0, bytesToWrite);
|
||||
positionBytes += bytesToWrite;
|
||||
if ((readFlags & FLAG_OMIT_SAMPLE_DATA) == 0) {
|
||||
buffer.ensureSpaceForWrite(bytesToWrite);
|
||||
buffer.data.put(SILENCE_SAMPLE, /* offset= */ 0, bytesToWrite);
|
||||
}
|
||||
if ((readFlags & FLAG_PEEK) == 0) {
|
||||
positionBytes += bytesToWrite;
|
||||
}
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -349,31 +349,39 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
|
||||
@Override
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) {
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
maybeNotifyDownstreamFormat();
|
||||
if (streamState == STREAM_STATE_END_OF_STREAM) {
|
||||
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||
return C.RESULT_BUFFER_READ;
|
||||
} else if (requireFormat || streamState == STREAM_STATE_SEND_FORMAT) {
|
||||
}
|
||||
|
||||
if ((readFlags & FLAG_REQUIRE_FORMAT) != 0 || streamState == STREAM_STATE_SEND_FORMAT) {
|
||||
formatHolder.format = format;
|
||||
streamState = STREAM_STATE_SEND_SAMPLE;
|
||||
return C.RESULT_FORMAT_READ;
|
||||
} else if (loadingFinished) {
|
||||
if (sampleData != null) {
|
||||
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||
buffer.timeUs = 0;
|
||||
if (buffer.isFlagsOnly()) {
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
buffer.ensureSpaceForWrite(sampleSize);
|
||||
buffer.data.put(sampleData, 0, sampleSize);
|
||||
} else {
|
||||
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadingFinished) {
|
||||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
|
||||
if (sampleData == null) {
|
||||
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||
streamState = STREAM_STATE_END_OF_STREAM;
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
return C.RESULT_NOTHING_READ;
|
||||
|
||||
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
|
||||
buffer.timeUs = 0;
|
||||
if ((readFlags & FLAG_OMIT_SAMPLE_DATA) == 0) {
|
||||
buffer.ensureSpaceForWrite(sampleSize);
|
||||
buffer.data.put(sampleData, 0, sampleSize);
|
||||
}
|
||||
if ((readFlags & FLAG_PEEK) == 0) {
|
||||
streamState = STREAM_STATE_END_OF_STREAM;
|
||||
}
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -381,8 +381,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
}
|
||||
|
||||
@Override
|
||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||
boolean formatRequired) {
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
if (isPendingReset()) {
|
||||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
|
|
@ -395,7 +395,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
}
|
||||
maybeNotifyPrimaryTrackFormatChanged();
|
||||
|
||||
return primarySampleQueue.read(formatHolder, buffer, formatRequired, loadingFinished);
|
||||
return primarySampleQueue.read(formatHolder, buffer, readFlags, loadingFinished);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -862,8 +862,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
}
|
||||
|
||||
@Override
|
||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||
boolean formatRequired) {
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
if (isPendingReset()) {
|
||||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
|
|
@ -875,7 +875,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
maybeNotifyDownstreamFormat();
|
||||
return sampleQueue.read(formatHolder, buffer, formatRequired, loadingFinished);
|
||||
return sampleQueue.read(formatHolder, buffer, readFlags, loadingFinished);
|
||||
}
|
||||
|
||||
public void release() {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -273,7 +273,7 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
|||
return;
|
||||
}
|
||||
// Try and read the next subtitle from the source.
|
||||
@SampleStream.ReadDataResult int result = readSource(formatHolder, nextInputBuffer, false);
|
||||
@ReadDataResult int result = readSource(formatHolder, nextInputBuffer, /* readFlags= */ 0);
|
||||
if (result == C.RESULT_BUFFER_READ) {
|
||||
if (nextInputBuffer.isEndOfStream()) {
|
||||
inputStreamEnded = true;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.video;
|
|||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DISCARD_REASON_DRM_SESSION_CHANGED;
|
||||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DISCARD_REASON_REUSE_NOT_IMPLEMENTED;
|
||||
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.REUSE_RESULT_NO;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||
import static java.lang.Math.max;
|
||||
|
||||
import android.os.Handler;
|
||||
|
|
@ -41,7 +42,7 @@ import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
|
|||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.TimedValueQueue;
|
||||
|
|
@ -165,7 +166,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
|||
joiningDeadlineMs = C.TIME_UNSET;
|
||||
clearReportedVideoSize();
|
||||
formatQueue = new TimedValueQueue<>();
|
||||
flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
|
||||
flagsOnlyBuffer = DecoderInputBuffer.newNoDataInstance();
|
||||
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
|
||||
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
|
||||
outputMode = C.VIDEO_OUTPUT_MODE_NONE;
|
||||
|
|
@ -183,7 +184,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
|||
// We don't have a format yet, so try and read one.
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
flagsOnlyBuffer.clear();
|
||||
@SampleStream.ReadDataResult int result = readSource(formatHolder, flagsOnlyBuffer, true);
|
||||
@ReadDataResult int result = readSource(formatHolder, flagsOnlyBuffer, FLAG_REQUIRE_FORMAT);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
onInputFormatChanged(formatHolder);
|
||||
} else if (result == C.RESULT_BUFFER_READ) {
|
||||
|
|
@ -745,7 +746,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
|||
}
|
||||
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
switch (readSource(formatHolder, inputBuffer, /* formatRequired= */ false)) {
|
||||
switch (readSource(formatHolder, inputBuffer, /* readFlags= */ 0)) {
|
||||
case C.RESULT_NOTHING_READ:
|
||||
return false;
|
||||
case C.RESULT_FORMAT_READ:
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import com.google.android.exoplayer2.FormatHolder;
|
|||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -94,8 +94,7 @@ public final class CameraMotionRenderer extends BaseRenderer {
|
|||
while (!hasReadStreamToEnd() && lastTimestampUs < positionUs + SAMPLE_WINDOW_DURATION_US) {
|
||||
buffer.clear();
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(formatHolder, buffer, /* formatRequired= */ false);
|
||||
@ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */ 0);
|
||||
if (result != C.RESULT_BUFFER_READ || buffer.isEndOfStream()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.source;
|
||||
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
|
||||
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
|
@ -93,11 +94,11 @@ public final class MergingMediaPeriodTest {
|
|||
FormatHolder formatHolder = new FormatHolder();
|
||||
DecoderInputBuffer inputBuffer =
|
||||
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||
assertThat(streams[1].readData(formatHolder, inputBuffer, /* formatRequired= */ true))
|
||||
assertThat(streams[1].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT))
|
||||
.isEqualTo(C.RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.format).isEqualTo(childFormat12);
|
||||
|
||||
assertThat(streams[2].readData(formatHolder, inputBuffer, /* formatRequired= */ true))
|
||||
assertThat(streams[2].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT))
|
||||
.isEqualTo(C.RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.format).isEqualTo(childFormat21);
|
||||
}
|
||||
|
|
@ -134,20 +135,20 @@ public final class MergingMediaPeriodTest {
|
|||
FormatHolder formatHolder = new FormatHolder();
|
||||
DecoderInputBuffer inputBuffer =
|
||||
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||
streams[0].readData(formatHolder, inputBuffer, /* formatRequired= */ true);
|
||||
streams[1].readData(formatHolder, inputBuffer, /* formatRequired= */ true);
|
||||
streams[0].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT);
|
||||
streams[1].readData(formatHolder, inputBuffer, FLAG_REQUIRE_FORMAT);
|
||||
|
||||
FakeMediaPeriodWithSelectTracksPosition childMediaPeriod1 =
|
||||
(FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(0);
|
||||
assertThat(childMediaPeriod1.selectTracksPositionUs).isEqualTo(0);
|
||||
assertThat(streams[0].readData(formatHolder, inputBuffer, /* formatRequired= */ false))
|
||||
assertThat(streams[0].readData(formatHolder, inputBuffer, /* readFlags= */ 0))
|
||||
.isEqualTo(C.RESULT_BUFFER_READ);
|
||||
assertThat(inputBuffer.timeUs).isEqualTo(123_000L);
|
||||
|
||||
FakeMediaPeriodWithSelectTracksPosition childMediaPeriod2 =
|
||||
(FakeMediaPeriodWithSelectTracksPosition) mergingMediaPeriod.getChildPeriod(1);
|
||||
assertThat(childMediaPeriod2.selectTracksPositionUs).isEqualTo(3000L);
|
||||
assertThat(streams[1].readData(formatHolder, inputBuffer, /* formatRequired= */ false))
|
||||
assertThat(streams[1].readData(formatHolder, inputBuffer, /* readFlags= */ 0))
|
||||
.isEqualTo(C.RESULT_BUFFER_READ);
|
||||
assertThat(inputBuffer.timeUs).isEqualTo(456_000 - 3000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import static com.google.android.exoplayer2.C.BUFFER_FLAG_KEY_FRAME;
|
|||
import static com.google.android.exoplayer2.C.RESULT_BUFFER_READ;
|
||||
import static com.google.android.exoplayer2.C.RESULT_FORMAT_READ;
|
||||
import static com.google.android.exoplayer2.C.RESULT_NOTHING_READ;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_OMIT_SAMPLE_DATA;
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_PEEK;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
import static java.lang.Long.MIN_VALUE;
|
||||
|
|
@ -208,14 +210,11 @@ public final class SampleQueueTest {
|
|||
sampleQueue.format(FORMAT_1);
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result =
|
||||
sampleQueue.peek(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
sampleQueue.read(formatHolder, inputBuffer, FLAG_PEEK, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
// formatHolder should be populated.
|
||||
assertThat(formatHolder.format).isEqualTo(FORMAT_1);
|
||||
result =
|
||||
sampleQueue.peek(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
result = sampleQueue.read(formatHolder, inputBuffer, FLAG_PEEK, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_NOTHING_READ);
|
||||
}
|
||||
|
||||
|
|
@ -454,7 +453,7 @@ public final class SampleQueueTest {
|
|||
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession);
|
||||
assertReadEncryptedSample(/* sampleIndex= */ 0);
|
||||
|
|
@ -463,13 +462,13 @@ public final class SampleQueueTest {
|
|||
assertThat(formatHolder.drmSession).isNull();
|
||||
result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.drmSession).isNull();
|
||||
assertReadEncryptedSample(/* sampleIndex= */ 2);
|
||||
result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession);
|
||||
}
|
||||
|
|
@ -484,7 +483,7 @@ public final class SampleQueueTest {
|
|||
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession);
|
||||
assertReadEncryptedSample(/* sampleIndex= */ 0);
|
||||
|
|
@ -493,13 +492,13 @@ public final class SampleQueueTest {
|
|||
assertThat(formatHolder.drmSession).isNull();
|
||||
result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.drmSession).isSameInstanceAs(mockPlaceholderDrmSession);
|
||||
assertReadEncryptedSample(/* sampleIndex= */ 2);
|
||||
result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
assertThat(formatHolder.drmSession).isSameInstanceAs(mockDrmSession);
|
||||
assertReadEncryptedSample(/* sampleIndex= */ 3);
|
||||
|
|
@ -527,7 +526,7 @@ public final class SampleQueueTest {
|
|||
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
|
||||
// Fill cryptoInfo.iv with non-zero data. When the 8 byte initialization vector is written into
|
||||
|
|
@ -537,7 +536,7 @@ public final class SampleQueueTest {
|
|||
|
||||
result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_BUFFER_READ);
|
||||
|
||||
// Assert cryptoInfo.iv contains the 8-byte initialization vector and that the trailing 8 bytes
|
||||
|
|
@ -1558,7 +1557,11 @@ public final class SampleQueueTest {
|
|||
private void assertReadNothing(boolean formatRequired) {
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result =
|
||||
sampleQueue.read(formatHolder, inputBuffer, formatRequired, /* loadingFinished= */ false);
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
formatRequired ? SampleStream.FLAG_REQUIRE_FORMAT : 0,
|
||||
/* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_NOTHING_READ);
|
||||
// formatHolder should not be populated.
|
||||
assertThat(formatHolder.format).isNull();
|
||||
|
|
@ -1576,7 +1579,11 @@ public final class SampleQueueTest {
|
|||
private void assertReadEndOfStream(boolean formatRequired) {
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result =
|
||||
sampleQueue.read(formatHolder, inputBuffer, formatRequired, /* loadingFinished= */ true);
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
formatRequired ? SampleStream.FLAG_REQUIRE_FORMAT : 0,
|
||||
/* loadingFinished= */ true);
|
||||
assertThat(result).isEqualTo(RESULT_BUFFER_READ);
|
||||
// formatHolder should not be populated.
|
||||
assertThat(formatHolder.format).isNull();
|
||||
|
|
@ -1597,7 +1604,11 @@ public final class SampleQueueTest {
|
|||
private void assertReadFormat(boolean formatRequired, Format format) {
|
||||
clearFormatHolderAndInputBuffer();
|
||||
int result =
|
||||
sampleQueue.read(formatHolder, inputBuffer, formatRequired, /* loadingFinished= */ false);
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
inputBuffer,
|
||||
formatRequired ? SampleStream.FLAG_REQUIRE_FORMAT : 0,
|
||||
/* loadingFinished= */ false);
|
||||
assertThat(result).isEqualTo(RESULT_FORMAT_READ);
|
||||
// formatHolder should be populated.
|
||||
assertThat(formatHolder.format).isEqualTo(format);
|
||||
|
|
@ -1641,24 +1652,51 @@ public final class SampleQueueTest {
|
|||
byte[] sampleData,
|
||||
int offset,
|
||||
int length) {
|
||||
// Check that peeks yields the expected values.
|
||||
clearFormatHolderAndInputBuffer();
|
||||
// Check that peek whilst omitting data yields the expected values.
|
||||
formatHolder.format = null;
|
||||
DecoderInputBuffer flagsOnlyBuffer = DecoderInputBuffer.newNoDataInstance();
|
||||
int result =
|
||||
sampleQueue.peek(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
assertBufferReadResult(
|
||||
sampleQueue.read(
|
||||
formatHolder,
|
||||
flagsOnlyBuffer,
|
||||
FLAG_OMIT_SAMPLE_DATA | FLAG_PEEK,
|
||||
/* loadingFinished= */ false);
|
||||
assertSampleBufferReadResult(
|
||||
flagsOnlyBuffer, result, timeUs, isKeyFrame, isDecodeOnly, isEncrypted);
|
||||
|
||||
// Check that peek yields the expected values.
|
||||
clearFormatHolderAndInputBuffer();
|
||||
result = sampleQueue.read(formatHolder, inputBuffer, FLAG_PEEK, /* loadingFinished= */ false);
|
||||
assertSampleBufferReadResult(
|
||||
result, timeUs, isKeyFrame, isDecodeOnly, isEncrypted, sampleData, offset, length);
|
||||
|
||||
// Check that read yields the expected values.
|
||||
clearFormatHolderAndInputBuffer();
|
||||
result =
|
||||
sampleQueue.read(
|
||||
formatHolder, inputBuffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
assertBufferReadResult(
|
||||
formatHolder, inputBuffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
assertSampleBufferReadResult(
|
||||
result, timeUs, isKeyFrame, isDecodeOnly, isEncrypted, sampleData, offset, length);
|
||||
}
|
||||
|
||||
private void assertBufferReadResult(
|
||||
private void assertSampleBufferReadResult(
|
||||
DecoderInputBuffer inputBuffer,
|
||||
int result,
|
||||
long timeUs,
|
||||
boolean isKeyFrame,
|
||||
boolean isDecodeOnly,
|
||||
boolean isEncrypted) {
|
||||
assertThat(result).isEqualTo(RESULT_BUFFER_READ);
|
||||
// formatHolder should not be populated.
|
||||
assertThat(formatHolder.format).isNull();
|
||||
// inputBuffer should be populated with metadata.
|
||||
assertThat(inputBuffer.timeUs).isEqualTo(timeUs);
|
||||
assertThat(inputBuffer.isKeyFrame()).isEqualTo(isKeyFrame);
|
||||
assertThat(inputBuffer.isDecodeOnly()).isEqualTo(isDecodeOnly);
|
||||
assertThat(inputBuffer.isEncrypted()).isEqualTo(isEncrypted);
|
||||
}
|
||||
|
||||
private void assertSampleBufferReadResult(
|
||||
int result,
|
||||
long timeUs,
|
||||
boolean isKeyFrame,
|
||||
|
|
@ -1667,14 +1705,9 @@ public final class SampleQueueTest {
|
|||
byte[] sampleData,
|
||||
int offset,
|
||||
int length) {
|
||||
assertThat(result).isEqualTo(RESULT_BUFFER_READ);
|
||||
// formatHolder should not be populated.
|
||||
assertThat(formatHolder.format).isNull();
|
||||
// inputBuffer should be populated.
|
||||
assertThat(inputBuffer.timeUs).isEqualTo(timeUs);
|
||||
assertThat(inputBuffer.isKeyFrame()).isEqualTo(isKeyFrame);
|
||||
assertThat(inputBuffer.isDecodeOnly()).isEqualTo(isDecodeOnly);
|
||||
assertThat(inputBuffer.isEncrypted()).isEqualTo(isEncrypted);
|
||||
assertSampleBufferReadResult(
|
||||
inputBuffer, result, timeUs, isKeyFrame, isDecodeOnly, isEncrypted);
|
||||
// inputBuffer should be populated with data.
|
||||
inputBuffer.flip();
|
||||
assertThat(inputBuffer.data.limit()).isEqualTo(length);
|
||||
byte[] readData = new byte[length];
|
||||
|
|
|
|||
|
|
@ -98,9 +98,9 @@ import java.io.IOException;
|
|||
}
|
||||
|
||||
@Override
|
||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||
boolean formatRequired) {
|
||||
if (formatRequired || !isFormatSentDownstream) {
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
if ((readFlags & FLAG_REQUIRE_FORMAT) != 0 || !isFormatSentDownstream) {
|
||||
formatHolder.format = upstreamFormat;
|
||||
isFormatSentDownstream = true;
|
||||
return C.RESULT_FORMAT_READ;
|
||||
|
|
|
|||
|
|
@ -360,8 +360,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
|
|||
private MetadataInputBuffer dequeueSample() {
|
||||
buffer.clear();
|
||||
int result =
|
||||
sampleQueue.read(
|
||||
formatHolder, buffer, /* formatRequired= */ false, /* loadingFinished= */ false);
|
||||
sampleQueue.read(formatHolder, buffer, /* readFlags= */ 0, /* loadingFinished= */ false);
|
||||
if (result == C.RESULT_BUFFER_READ) {
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public final class EventSampleStreamTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests that {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} will
|
||||
* Tests that {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} will
|
||||
* return format for the first call.
|
||||
*/
|
||||
@Test
|
||||
|
|
@ -106,7 +106,7 @@ public final class EventSampleStreamTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests that {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} will
|
||||
* Tests that {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} will
|
||||
* return sample data after the first call.
|
||||
*/
|
||||
@Test
|
||||
|
|
@ -127,8 +127,8 @@ public final class EventSampleStreamTest {
|
|||
|
||||
/**
|
||||
* Tests that {@link EventSampleStream#skipData(long)} will skip until the given position, and the
|
||||
* next {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} call will
|
||||
* return sample data from that position.
|
||||
* next {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return
|
||||
* sample data from that position.
|
||||
*/
|
||||
@Test
|
||||
public void skipDataThenReadDataReturnDataFromSkippedPosition() {
|
||||
|
|
@ -153,7 +153,7 @@ public final class EventSampleStreamTest {
|
|||
|
||||
/**
|
||||
* Tests that {@link EventSampleStream#seekToUs(long)} (long)} will seek to the given position,
|
||||
* and the next {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} call
|
||||
* and the next {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call
|
||||
* will return sample data from that position.
|
||||
*/
|
||||
@Test
|
||||
|
|
@ -179,8 +179,8 @@ public final class EventSampleStreamTest {
|
|||
/**
|
||||
* Tests that {@link EventSampleStream#updateEventStream(EventStream, boolean)} will update the
|
||||
* underlying event stream, but keep the read timestamp, so the next {@link
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} call will return sample
|
||||
* data from after the last read sample timestamp.
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return sample data
|
||||
* from after the last read sample timestamp.
|
||||
*/
|
||||
@Test
|
||||
public void updateEventStreamContinueToReadAfterLastReadSamplePresentationTime() {
|
||||
|
|
@ -213,8 +213,8 @@ public final class EventSampleStreamTest {
|
|||
/**
|
||||
* Tests that {@link EventSampleStream#updateEventStream(EventStream, boolean)} will update the
|
||||
* underlying event stream, but keep the timestamp the stream has skipped to, so the next {@link
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} call will return sample
|
||||
* data from the skipped position.
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return sample data
|
||||
* from the skipped position.
|
||||
*/
|
||||
@Test
|
||||
public void skipDataThenUpdateStreamContinueToReadFromSkippedPosition() {
|
||||
|
|
@ -246,8 +246,8 @@ public final class EventSampleStreamTest {
|
|||
* Tests that {@link EventSampleStream#skipData(long)} will only skip to the point right after it
|
||||
* last event. A following {@link EventSampleStream#updateEventStream(EventStream, boolean)} will
|
||||
* update the underlying event stream and keep the timestamp the stream has skipped to, so the
|
||||
* next {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} call will
|
||||
* return sample data from the skipped position.
|
||||
* next {@link EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return
|
||||
* sample data from the skipped position.
|
||||
*/
|
||||
@Test
|
||||
public void skipDataThenUpdateStreamContinueToReadDoNotSkippedMoreThanAvailable() {
|
||||
|
|
@ -280,8 +280,8 @@ public final class EventSampleStreamTest {
|
|||
/**
|
||||
* Tests that {@link EventSampleStream#updateEventStream(EventStream, boolean)} will update the
|
||||
* underlying event stream, but keep the timestamp the stream has seek to, so the next {@link
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} call will return sample
|
||||
* data from the seek position.
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return sample data
|
||||
* from the seek position.
|
||||
*/
|
||||
@Test
|
||||
public void seekToUsThenUpdateStreamContinueToReadFromSeekPosition() {
|
||||
|
|
@ -312,8 +312,8 @@ public final class EventSampleStreamTest {
|
|||
/**
|
||||
* Tests that {@link EventSampleStream#updateEventStream(EventStream, boolean)} will update the
|
||||
* underlying event stream, but keep the timestamp the stream has seek to, so the next {@link
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, boolean)} call will return sample
|
||||
* data from the seek position.
|
||||
* EventSampleStream#readData(FormatHolder, DecoderInputBuffer, int)} call will return sample data
|
||||
* from the seek position.
|
||||
*/
|
||||
@Test
|
||||
public void seekToThenUpdateStreamContinueToReadFromSeekPositionEvenSeekMoreThanAvailable() {
|
||||
|
|
@ -343,7 +343,7 @@ public final class EventSampleStreamTest {
|
|||
|
||||
private int readData(EventSampleStream sampleStream) {
|
||||
inputBuffer.clear();
|
||||
return sampleStream.readData(formatHolder, inputBuffer, false);
|
||||
return sampleStream.readData(formatHolder, inputBuffer, /* readFlags= */ 0);
|
||||
}
|
||||
|
||||
private EventMessage newEventMessageWithId(int id) {
|
||||
|
|
|
|||
|
|
@ -70,13 +70,14 @@ import java.io.IOException;
|
|||
}
|
||||
|
||||
@Override
|
||||
public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) {
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
if (sampleQueueIndex == HlsSampleStreamWrapper.SAMPLE_QUEUE_INDEX_NO_MAPPING_NON_FATAL) {
|
||||
buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
|
||||
return C.RESULT_BUFFER_READ;
|
||||
}
|
||||
return hasValidSampleQueueIndex()
|
||||
? sampleStreamWrapper.readData(sampleQueueIndex, formatHolder, buffer, requireFormat)
|
||||
? sampleStreamWrapper.readData(sampleQueueIndex, formatHolder, buffer, readFlags)
|
||||
: C.RESULT_NOTHING_READ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
|||
import com.google.android.exoplayer2.source.SampleQueue;
|
||||
import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadFlags;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
|
|
@ -569,8 +570,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
chunkSource.maybeThrowError();
|
||||
}
|
||||
|
||||
public int readData(int sampleQueueIndex, FormatHolder formatHolder, DecoderInputBuffer buffer,
|
||||
boolean requireFormat) {
|
||||
public int readData(
|
||||
int sampleQueueIndex,
|
||||
FormatHolder formatHolder,
|
||||
DecoderInputBuffer buffer,
|
||||
@ReadFlags int readFlags) {
|
||||
if (isPendingReset()) {
|
||||
return C.RESULT_NOTHING_READ;
|
||||
}
|
||||
|
|
@ -602,7 +606,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
}
|
||||
|
||||
int result =
|
||||
sampleQueues[sampleQueueIndex].read(formatHolder, buffer, requireFormat, loadingFinished);
|
||||
sampleQueues[sampleQueueIndex].read(formatHolder, buffer, readFlags, loadingFinished);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
Format format = Assertions.checkNotNull(formatHolder.format);
|
||||
if (sampleQueueIndex == primarySampleQueueIndex) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.google.android.exoplayer2.transformer;
|
||||
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||
import static java.lang.Math.min;
|
||||
|
|
@ -31,7 +32,7 @@ import com.google.android.exoplayer2.audio.AudioProcessor;
|
|||
import com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat;
|
||||
import com.google.android.exoplayer2.audio.SonicAudioProcessor;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
|
@ -273,8 +274,8 @@ import java.nio.ByteBuffer;
|
|||
}
|
||||
|
||||
decoderInputBuffer.clear();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(getFormatHolder(), decoderInputBuffer, /* formatRequired= */ false);
|
||||
@ReadDataResult
|
||||
int result = readSource(getFormatHolder(), decoderInputBuffer, /* readFlags= */ 0);
|
||||
switch (result) {
|
||||
case C.RESULT_BUFFER_READ:
|
||||
mediaClock.updateTimeForTrackType(getTrackType(), decoderInputBuffer.timeUs);
|
||||
|
|
@ -373,8 +374,7 @@ import java.nio.ByteBuffer;
|
|||
}
|
||||
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(formatHolder, decoderInputBuffer, /* formatRequired= */ true);
|
||||
@ReadDataResult int result = readSource(formatHolder, decoderInputBuffer, FLAG_REQUIRE_FORMAT);
|
||||
if (result != C.RESULT_FORMAT_READ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package com.google.android.exoplayer2.transformer;
|
||||
|
||||
import static com.google.android.exoplayer2.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -24,7 +25,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
@RequiresApi(18)
|
||||
|
|
@ -59,8 +60,7 @@ import java.nio.ByteBuffer;
|
|||
|
||||
if (!formatRead) {
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(formatHolder, buffer, /* formatRequired= */ true);
|
||||
@ReadDataResult int result = readSource(formatHolder, buffer, FLAG_REQUIRE_FORMAT);
|
||||
if (result != C.RESULT_FORMAT_READ) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -102,8 +102,7 @@ import java.nio.ByteBuffer;
|
|||
*/
|
||||
private boolean readAndTransformBuffer() {
|
||||
buffer.clear();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(getFormatHolder(), buffer, /* formatRequired= */ false);
|
||||
@ReadDataResult int result = readSource(getFormatHolder(), buffer, /* readFlags= */ 0);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
throw new IllegalStateException("Format changes are not supported.");
|
||||
} else if (result == C.RESULT_NOTHING_READ) {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import com.google.android.exoplayer2.Renderer;
|
|||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -92,8 +92,7 @@ public class FakeRenderer extends BaseRenderer {
|
|||
if (!hasPendingBuffer) {
|
||||
FormatHolder formatHolder = getFormatHolder();
|
||||
buffer.clear();
|
||||
@SampleStream.ReadDataResult
|
||||
int result = readSource(formatHolder, buffer, /* formatRequired= */ false);
|
||||
@ReadDataResult int result = readSource(formatHolder, buffer, /* readFlags= */ 0);
|
||||
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
DrmSession.replaceSession(currentDrmSession, formatHolder.drmSession);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ import java.util.List;
|
|||
*/
|
||||
public class FakeSampleStream implements SampleStream {
|
||||
|
||||
/** Item to customize a return value of {@link FakeSampleStream#readData}. */
|
||||
/** Item to customize a return value of {@link SampleStream#readData}. */
|
||||
public static final class FakeSampleStreamItem {
|
||||
|
||||
/** Item that designates the end of stream has been reached. */
|
||||
|
|
@ -265,12 +265,12 @@ public class FakeSampleStream implements SampleStream {
|
|||
|
||||
@Override
|
||||
public int readData(
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) {
|
||||
int result = sampleQueue.read(formatHolder, buffer, formatRequired, loadingFinished);
|
||||
FormatHolder formatHolder, DecoderInputBuffer buffer, @ReadFlags int readFlags) {
|
||||
int result = sampleQueue.read(formatHolder, buffer, readFlags, loadingFinished);
|
||||
if (result == C.RESULT_FORMAT_READ) {
|
||||
downstreamFormat = checkNotNull(formatHolder.format);
|
||||
}
|
||||
if (result == C.RESULT_BUFFER_READ && !buffer.isFlagsOnly()) {
|
||||
if (result == C.RESULT_BUFFER_READ && (readFlags & FLAG_OMIT_SAMPLE_DATA) == 0) {
|
||||
maybeNotifyDownstreamFormat(buffer.timeUs);
|
||||
}
|
||||
return result;
|
||||
|
|
|
|||
Loading…
Reference in a new issue