diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index e4cc2ae3ce..d0417bc37e 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -65,6 +65,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { private final boolean playClearSamplesWithoutKeys; private final EventDispatcher eventDispatcher; private final FormatHolder formatHolder; + private final DecoderInputBuffer flagsOnlyBuffer; private final DrmSessionManager drmSessionManager; private DecoderCounters decoderCounters; @@ -149,6 +150,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { joiningDeadlineMs = -1; clearLastReportedVideoSize(); formatHolder = new FormatHolder(); + flagsOnlyBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); eventDispatcher = new EventDispatcher(eventHandler, eventListener); outputMode = VpxDecoder.OUTPUT_MODE_NONE; } @@ -165,10 +167,22 @@ public final class LibvpxVideoRenderer extends BaseRenderer { return; } - // Try and read a format if we don't have one already. - if (format == null && !readFormat()) { - // We can't make progress without one. - return; + if (format == null) { + // We don't have a format yet, so try and read one. + flagsOnlyBuffer.clear(); + int result = readSource(formatHolder, flagsOnlyBuffer, true); + if (result == C.RESULT_FORMAT_READ) { + onInputFormatChanged(formatHolder.format); + } else if (result == C.RESULT_BUFFER_READ) { + // End of stream read having not read a format. + Assertions.checkState(flagsOnlyBuffer.isEndOfStream()); + inputStreamEnded = true; + outputStreamEnded = true; + return; + } else { + // We still don't have a format and can't make progress without one. + return; + } } if (isRendererAvailable()) { @@ -327,7 +341,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { // We've already read an encrypted sample into buffer, and are waiting for keys. result = C.RESULT_BUFFER_READ; } else { - result = readSource(formatHolder, inputBuffer); + result = readSource(formatHolder, inputBuffer, false); } if (result == C.RESULT_NOTHING_READ) { @@ -485,15 +499,6 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } - private boolean readFormat() throws ExoPlaybackException { - int result = readSource(formatHolder, null); - if (result == C.RESULT_FORMAT_READ) { - onInputFormatChanged(formatHolder.format); - return true; - } - return false; - } - private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException { Format oldFormat = format; format = newFormat; diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 1197139b01..2ad1159c3e 100644 --- a/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -513,8 +513,9 @@ public final class ExoPlayerTest extends TestCase { } @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { - if (buffer == null || !readFormat) { + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean formatRequired) { + if (formatRequired || !readFormat) { formatHolder.format = format; readFormat = true; return C.RESULT_FORMAT_READ; @@ -571,7 +572,7 @@ public final class ExoPlayerTest extends TestCase { FormatHolder formatHolder = new FormatHolder(); DecoderInputBuffer buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); - int result = readSource(formatHolder, buffer); + int result = readSource(formatHolder, buffer, false); if (result == C.RESULT_FORMAT_READ) { formatReadCount++; assertEquals(expectedFormat, formatHolder.format); diff --git a/library/src/main/java/com/google/android/exoplayer2/BaseRenderer.java b/library/src/main/java/com/google/android/exoplayer2/BaseRenderer.java index 9973a50cff..7266e2cd30 100644 --- a/library/src/main/java/com/google/android/exoplayer2/BaseRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/BaseRenderer.java @@ -262,13 +262,16 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { * @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. May be null if the - * caller requires that the format of the stream be read even if it's not changing. + * {@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 result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or * {@link C#RESULT_BUFFER_READ}. */ - protected final int readSource(FormatHolder formatHolder, DecoderInputBuffer buffer) { - int result = stream.readData(formatHolder, buffer); + protected final int readSource(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean formatRequired) { + int result = stream.readData(formatHolder, buffer, formatRequired); if (result == C.RESULT_BUFFER_READ) { if (buffer.isEndOfStream()) { readEndOfStream = true; diff --git a/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index 5e93aa920c..e80c9bb70a 100644 --- a/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -34,6 +34,7 @@ import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; import com.google.android.exoplayer2.drm.DrmSession; import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.ExoMediaCrypto; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MediaClock; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.TraceUtil; @@ -67,12 +68,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements */ private static final int REINITIALIZATION_STATE_WAIT_END_OF_STREAM = 2; + private final DrmSessionManager drmSessionManager; private final boolean playClearSamplesWithoutKeys; - private final EventDispatcher eventDispatcher; private final AudioTrack audioTrack; - private final DrmSessionManager drmSessionManager; private final FormatHolder formatHolder; + private final DecoderInputBuffer flagsOnlyBuffer; private DecoderCounters decoderCounters; private Format inputFormat; @@ -142,11 +143,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys, BufferProcessor... bufferProcessors) { super(C.TRACK_TYPE_AUDIO); + this.drmSessionManager = drmSessionManager; + this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys; eventDispatcher = new EventDispatcher(eventHandler, eventListener); audioTrack = new AudioTrack(audioCapabilities, bufferProcessors, new AudioTrackListener()); - this.drmSessionManager = drmSessionManager; formatHolder = new FormatHolder(); - this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys; + flagsOnlyBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); decoderReinitializationState = REINITIALIZATION_STATE_NONE; audioTrackNeedsConfigure = true; } @@ -187,9 +189,22 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements } // Try and read a format if we don't have one already. - if (inputFormat == null && !readFormat()) { - // We can't make progress without one. - return; + if (inputFormat == null) { + // We don't have a format yet, so try and read one. + flagsOnlyBuffer.clear(); + int result = readSource(formatHolder, flagsOnlyBuffer, true); + if (result == C.RESULT_FORMAT_READ) { + onInputFormatChanged(formatHolder.format); + } else if (result == C.RESULT_BUFFER_READ) { + // End of stream read having not read a format. + Assertions.checkState(flagsOnlyBuffer.isEndOfStream()); + inputStreamEnded = true; + processEndOfStream(); + return; + } else { + // We still don't have a format and can't make progress without one. + return; + } } // If we don't have a decoder yet, we need to instantiate one. @@ -284,8 +299,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements } else { outputBuffer.release(); outputBuffer = null; - outputStreamEnded = true; - audioTrack.playToEndOfStream(); + processEndOfStream(); } return false; } @@ -334,7 +348,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements // We've already read an encrypted sample into buffer, and are waiting for keys. result = C.RESULT_BUFFER_READ; } else { - result = readSource(formatHolder, inputBuffer); + result = readSource(formatHolder, inputBuffer, false); } if (result == C.RESULT_NOTHING_READ) { @@ -375,6 +389,15 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements && (bufferEncrypted || !playClearSamplesWithoutKeys); } + private void processEndOfStream() throws ExoPlaybackException { + outputStreamEnded = true; + try { + audioTrack.playToEndOfStream(); + } catch (AudioTrack.WriteException e) { + throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex()); + } + } + private void flushDecoder() throws ExoPlaybackException { waitingForKeys = false; if (decoderReinitializationState != REINITIALIZATION_STATE_NONE) { @@ -523,15 +546,6 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements decoderReceivedBuffers = false; } - private boolean readFormat() throws ExoPlaybackException { - int result = readSource(formatHolder, null); - if (result == C.RESULT_FORMAT_READ) { - onInputFormatChanged(formatHolder.format); - return true; - } - return false; - } - private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException { Format oldFormat = inputFormat; inputFormat = newFormat; diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java b/library/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java index 460e8d33a8..8aff8858a1 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/DefaultTrackOutput.java @@ -267,40 +267,42 @@ public final class DefaultTrackOutput 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. May be null if the - * caller requires that the format of the stream be read even if it's not changing. + * {@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. * @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}. */ - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean loadingFinished, - long decodeOnlyUntilUs) { - switch (infoQueue.readData(formatHolder, buffer, downstreamFormat, extrasHolder)) { - case C.RESULT_NOTHING_READ: - if (loadingFinished) { - buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); - return C.RESULT_BUFFER_READ; - } - return C.RESULT_NOTHING_READ; + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired, + boolean loadingFinished, long decodeOnlyUntilUs) { + int result = infoQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, + downstreamFormat, extrasHolder); + switch (result) { case C.RESULT_FORMAT_READ: downstreamFormat = formatHolder.format; return C.RESULT_FORMAT_READ; case C.RESULT_BUFFER_READ: - if (buffer.timeUs < decodeOnlyUntilUs) { - buffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY); + if (!buffer.isEndOfStream()) { + if (buffer.timeUs < decodeOnlyUntilUs) { + buffer.addFlag(C.BUFFER_FLAG_DECODE_ONLY); + } + // Read encryption data if the sample is encrypted. + if (buffer.isEncrypted()) { + readEncryptionData(buffer, extrasHolder); + } + // Write the sample data into the holder. + buffer.ensureSpaceForWrite(extrasHolder.size); + readData(extrasHolder.offset, buffer.data, extrasHolder.size); + // Advance the read head. + dropDownstreamTo(extrasHolder.nextOffset); } - // Read encryption data if the sample is encrypted. - if (buffer.isEncrypted()) { - readEncryptionData(buffer, extrasHolder); - } - // Write the sample data into the holder. - buffer.ensureSpaceForWrite(extrasHolder.size); - readData(extrasHolder.offset, buffer.data, extrasHolder.size); - // Advance the read head. - dropDownstreamTo(extrasHolder.nextOffset); return C.RESULT_BUFFER_READ; + case C.RESULT_NOTHING_READ: + return C.RESULT_NOTHING_READ; default: throw new IllegalStateException(); } @@ -760,23 +762,34 @@ public final class DefaultTrackOutput implements TrackOutput { * and the absolute position of the first byte that may still be required after the current * sample has been read. May be null if the caller requires that the format of the stream be * read even if it's not changing. + * @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 downstreamFormat The current downstream {@link Format}. If the format of the next * sample is different to the current downstream format then a format will be read. * @param extrasHolder The holder into which extra sample information should be written. * @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} * or {@link C#RESULT_BUFFER_READ}. */ + @SuppressWarnings("ReferenceEquality") public synchronized int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, - Format downstreamFormat, BufferExtrasHolder extrasHolder) { + boolean formatRequired, boolean loadingFinished, Format downstreamFormat, + BufferExtrasHolder extrasHolder) { if (queueSize == 0) { - if (upstreamFormat != null && (buffer == null || upstreamFormat != downstreamFormat)) { + if (loadingFinished) { + buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); + return C.RESULT_BUFFER_READ; + } else if (upstreamFormat != null + && (formatRequired || upstreamFormat != downstreamFormat)) { formatHolder.format = upstreamFormat; return C.RESULT_FORMAT_READ; + } else { + return C.RESULT_NOTHING_READ; } - return C.RESULT_NOTHING_READ; } - if (buffer == null || formats[relativeReadIndex] != downstreamFormat) { + if (formatRequired || formats[relativeReadIndex] != downstreamFormat) { formatHolder.format = formats[relativeReadIndex]; return C.RESULT_FORMAT_READ; } diff --git a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index cf8d766c0c..3fbbfac652 100644 --- a/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -484,7 +484,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return; } if (format == null) { - readFormat(); + // We don't have a format yet, so try and read one. + buffer.clear(); + int result = readSource(formatHolder, buffer, true); + if (result == C.RESULT_FORMAT_READ) { + onInputFormatChanged(formatHolder.format); + } else if (result == C.RESULT_BUFFER_READ) { + // End of stream read having not read a format. + Assertions.checkState(buffer.isEndOfStream()); + inputStreamEnded = true; + processEndOfStream(); + return; + } else { + // We still don't have a format and can't make progress without one. + return; + } } maybeInitCodec(); if (codec != null) { @@ -498,13 +512,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { decoderCounters.ensureUpdated(); } - private void readFormat() throws ExoPlaybackException { - int result = readSource(formatHolder, null); - if (result == C.RESULT_FORMAT_READ) { - onInputFormatChanged(formatHolder.format); - } - } - protected void flushCodec() throws ExoPlaybackException { codecHotswapDeadlineMs = C.TIME_UNSET; inputIndex = C.INDEX_UNSET; @@ -594,7 +601,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING; } adaptiveReconfigurationBytes = buffer.data.position(); - result = readSource(formatHolder, buffer); + result = readSource(formatHolder, buffer, false); } if (result == C.RESULT_NOTHING_READ) { diff --git a/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java b/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java index 550a13771f..6c2ef319fd 100644 --- a/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/metadata/MetadataRenderer.java @@ -109,7 +109,7 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { if (!inputStreamEnded && pendingMetadata == null) { buffer.clear(); - int result = readSource(formatHolder, buffer); + int result = readSource(formatHolder, buffer, false); if (result == C.RESULT_BUFFER_READ) { if (buffer.isEndOfStream()) { inputStreamEnded = true; diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index b18eabf493..51663a21c6 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -231,18 +231,16 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb } @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean requireFormat) { if (pendingDiscontinuity) { return C.RESULT_NOTHING_READ; } - if (buffer == null) { - return stream.readData(formatHolder, null); - } if (sentEos) { buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); return C.RESULT_BUFFER_READ; } - int result = stream.readData(formatHolder, buffer); + int result = stream.readData(formatHolder, buffer, requireFormat); // TODO: Clear gapless playback metadata if a format was read (if applicable). if (endUs != C.TIME_END_OF_SOURCE && ((result == C.RESULT_BUFFER_READ && buffer.timeUs >= endUs) || (result == C.RESULT_NOTHING_READ diff --git a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java index dc189058a6..97e9ddd7e7 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaPeriod.java @@ -325,13 +325,14 @@ import java.io.IOException; loader.maybeThrowError(); } - /* package */ int readData(int track, FormatHolder formatHolder, DecoderInputBuffer buffer) { + /* package */ int readData(int track, FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean formatRequired) { if (notifyReset || isPendingReset()) { return C.RESULT_NOTHING_READ; } - return sampleQueues.valueAt(track).readData(formatHolder, buffer, loadingFinished, - lastSeekPositionUs); + return sampleQueues.valueAt(track).readData(formatHolder, buffer, formatRequired, + loadingFinished, lastSeekPositionUs); } // Loader.Callback implementation. @@ -552,8 +553,9 @@ import java.io.IOException; } @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { - return ExtractorMediaPeriod.this.readData(track, formatHolder, buffer); + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean formatRequired) { + return ExtractorMediaPeriod.this.readData(track, formatHolder, buffer, formatRequired); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SampleStream.java b/library/src/main/java/com/google/android/exoplayer2/source/SampleStream.java index 5ee70cd2ed..90153d1790 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/SampleStream.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/SampleStream.java @@ -45,20 +45,24 @@ public interface SampleStream { /** * Attempts to read from the stream. *

- * If no data is available then {@link C#RESULT_NOTHING_READ} is returned. If the format of the - * media is changing or if {@code buffer == null} then {@code formatHolder} is populated and + * If the stream has ended then {@link C#BUFFER_FLAG_END_OF_STREAM} flag is set on {@code buffer} + * and {@link C#RESULT_BUFFER_READ} is returned. Else if no data is available then + * {@link C#RESULT_NOTHING_READ} is returned. Else if the format of the media is changing or if + * {@code formatRequired} is set then {@code formatHolder} is populated and * {@link C#RESULT_FORMAT_READ} is returned. Else {@code buffer} is populated and * {@link C#RESULT_BUFFER_READ} is returned. * * @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. May be null if the - * caller requires that the format of the stream be read even if it's not changing. + * {@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 result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or * {@link C#RESULT_BUFFER_READ}. */ - int readData(FormatHolder formatHolder, DecoderInputBuffer buffer); + int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired); /** * Attempts to skip to the keyframe before the specified time. diff --git a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java index c78bb5371b..fd2ebffe8e 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java @@ -205,14 +205,15 @@ import java.util.Arrays; } @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { - if (buffer == null || streamState == STREAM_STATE_SEND_FORMAT) { + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean requireFormat) { + 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) { formatHolder.format = format; streamState = STREAM_STATE_SEND_SAMPLE; return C.RESULT_FORMAT_READ; - } else if (streamState == STREAM_STATE_END_OF_STREAM) { - buffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM); - return C.RESULT_BUFFER_READ; } Assertions.checkState(streamState == STREAM_STATE_SEND_SAMPLE); diff --git a/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index 3955d64034..7149ce3f99 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -169,7 +169,8 @@ public class ChunkSampleStream implements SampleStream, S } @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean formatRequired) { if (isPendingReset()) { return C.RESULT_NOTHING_READ; } @@ -187,7 +188,8 @@ public class ChunkSampleStream implements SampleStream, S currentChunk.startTimeUs); } downstreamTrackFormat = trackFormat; - return sampleQueue.readData(formatHolder, buffer, loadingFinished, lastSeekPositionUs); + return sampleQueue.readData(formatHolder, buffer, formatRequired, loadingFinished, + lastSeekPositionUs); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java index 04fe8a093c..d8eb7e1ae8 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStream.java @@ -45,8 +45,8 @@ import java.io.IOException; } @Override - public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer) { - return sampleStreamWrapper.readData(group, formatHolder, buffer); + public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean requireFormat) { + return sampleStreamWrapper.readData(group, formatHolder, buffer, requireFormat); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 0e3ee6fa9c..8bd966f177 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -290,7 +290,8 @@ import java.util.LinkedList; chunkSource.maybeThrowError(); } - /* package */ int readData(int group, FormatHolder formatHolder, DecoderInputBuffer buffer) { + /* package */ int readData(int group, FormatHolder formatHolder, DecoderInputBuffer buffer, + boolean requireFormat) { if (isPendingReset()) { return C.RESULT_NOTHING_READ; } @@ -307,8 +308,8 @@ import java.util.LinkedList; } downstreamTrackFormat = trackFormat; - return sampleQueues.valueAt(group).readData(formatHolder, buffer, loadingFinished, - lastSeekPositionUs); + return sampleQueues.valueAt(group).readData(formatHolder, buffer, requireFormat, + loadingFinished, lastSeekPositionUs); } /* package */ void skipToKeyframeBefore(int group, long timeUs) { diff --git a/library/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java b/library/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java index 649575865e..a7e05a010a 100644 --- a/library/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java @@ -189,7 +189,7 @@ public final class TextRenderer extends BaseRenderer implements Callback { } } // Try and read the next subtitle from the source. - int result = readSource(formatHolder, nextInputBuffer); + int result = readSource(formatHolder, nextInputBuffer, false); if (result == C.RESULT_BUFFER_READ) { if (nextInputBuffer.isEndOfStream()) { inputStreamEnded = true;