diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index e008e92e243..f059a2f6e47 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -207,10 +207,6 @@ private static String buildCustomDiagnosticInfo(int errorCode) { */ private static final long MAX_CODEC_HOTSWAP_TIME_MS = 1000; - // Generally there is zero or one pending output stream offset. We track more offsets to allow for - // pending output streams that have fewer frames than the codec latency. - private static final int MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT = 10; - @Documented @Retention(RetentionPolicy.SOURCE) @Target(TYPE_USE) @@ -305,9 +301,7 @@ private static String buildCustomDiagnosticInfo(int errorCode) { private final TimedValueQueue formatQueue; private final ArrayList decodeOnlyPresentationTimestamps; private final MediaCodec.BufferInfo outputBufferInfo; - private final long[] pendingOutputStreamStartPositionsUs; - private final long[] pendingOutputStreamOffsetsUs; - private final long[] pendingOutputStreamSwitchTimesUs; + private final ArrayDeque pendingOutputStreamChanges; private final OggOpusAudioPacketizer oggOpusAudioPacketizer; @Nullable private Format inputFormat; @@ -363,9 +357,7 @@ private static String buildCustomDiagnosticInfo(int errorCode) { private boolean pendingOutputEndOfStream; @Nullable private ExoPlaybackException pendingPlaybackException; protected DecoderCounters decoderCounters; - private long outputStreamStartPositionUs; - private long outputStreamOffsetUs; - private int pendingOutputStreamOffsetCount; + private OutputStreamInfo outputStreamInfo; /** * @param trackType The {@link C.TrackType track type} that the renderer handles. @@ -398,11 +390,8 @@ public MediaCodecRenderer( currentPlaybackSpeed = 1f; targetPlaybackSpeed = 1f; renderTimeLimitMs = C.TIME_UNSET; - pendingOutputStreamStartPositionsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; - pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; - pendingOutputStreamSwitchTimesUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; - outputStreamStartPositionUs = C.TIME_UNSET; - setOutputStreamOffsetUs(C.TIME_UNSET); + pendingOutputStreamChanges = new ArrayDeque<>(); + setOutputStreamInfo(OutputStreamInfo.UNSET); // MediaCodec outputs audio buffers in native endian: // https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers // and code called from MediaCodecAudioRenderer.processOutputBuffer expects this endianness. @@ -649,23 +638,14 @@ protected void onEnabled(boolean joining, boolean mayRenderStartOfStream) @Override protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) throws ExoPlaybackException { - if (this.outputStreamOffsetUs == C.TIME_UNSET) { - checkState(this.outputStreamStartPositionUs == C.TIME_UNSET); - this.outputStreamStartPositionUs = startPositionUs; - setOutputStreamOffsetUs(offsetUs); + if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET) { + checkState(outputStreamInfo.startPositionUs == C.TIME_UNSET); + setOutputStreamInfo( + new OutputStreamInfo( + /* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, startPositionUs, offsetUs)); } else { - if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) { - Log.w( - TAG, - "Too many stream changes, so dropping offset: " - + pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]); - } else { - pendingOutputStreamOffsetCount++; - } - pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1] = startPositionUs; - pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1] = offsetUs; - pendingOutputStreamSwitchTimesUs[pendingOutputStreamOffsetCount - 1] = - largestQueuedPresentationTimeUs; + pendingOutputStreamChanges.add( + new OutputStreamInfo(largestQueuedPresentationTimeUs, startPositionUs, offsetUs)); } } @@ -688,12 +668,7 @@ protected void onPositionReset(long positionUs, boolean joining) throws ExoPlayb waitingForFirstSampleInFormat = true; } formatQueue.clear(); - if (pendingOutputStreamOffsetCount != 0) { - setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]); - outputStreamStartPositionUs = - pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1]; - pendingOutputStreamOffsetCount = 0; - } + pendingOutputStreamChanges.clear(); } @Override @@ -707,9 +682,8 @@ public void setPlaybackSpeed(float currentPlaybackSpeed, float targetPlaybackSpe @Override protected void onDisabled() { inputFormat = null; - outputStreamStartPositionUs = C.TIME_UNSET; - setOutputStreamOffsetUs(C.TIME_UNSET); - pendingOutputStreamOffsetCount = 0; + setOutputStreamInfo(OutputStreamInfo.UNSET); + pendingOutputStreamChanges.clear(); flushOrReleaseCodec(); } @@ -1612,29 +1586,9 @@ protected void onQueueInputBuffer(DecoderInputBuffer buffer) throws ExoPlaybackE */ @CallSuper protected void onProcessedOutputBuffer(long presentationTimeUs) { - while (pendingOutputStreamOffsetCount != 0 - && presentationTimeUs >= pendingOutputStreamSwitchTimesUs[0]) { - outputStreamStartPositionUs = pendingOutputStreamStartPositionsUs[0]; - setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[0]); - pendingOutputStreamOffsetCount--; - System.arraycopy( - pendingOutputStreamStartPositionsUs, - /* srcPos= */ 1, - pendingOutputStreamStartPositionsUs, - /* destPos= */ 0, - pendingOutputStreamOffsetCount); - System.arraycopy( - pendingOutputStreamOffsetsUs, - /* srcPos= */ 1, - pendingOutputStreamOffsetsUs, - /* destPos= */ 0, - pendingOutputStreamOffsetCount); - System.arraycopy( - pendingOutputStreamSwitchTimesUs, - /* srcPos= */ 1, - pendingOutputStreamSwitchTimesUs, - /* destPos= */ 0, - pendingOutputStreamOffsetCount); + if (!pendingOutputStreamChanges.isEmpty() + && presentationTimeUs >= pendingOutputStreamChanges.peek().previousStreamLastBufferTimeUs) { + setOutputStreamInfo(pendingOutputStreamChanges.poll()); onProcessedStreamChange(); } } @@ -2081,13 +2035,13 @@ protected final void setPendingOutputEndOfStream() { * boolean, Format)} to get the playback position with respect to the media. */ protected final long getOutputStreamOffsetUs() { - return outputStreamOffsetUs; + return outputStreamInfo.streamOffsetUs; } - private void setOutputStreamOffsetUs(long outputStreamOffsetUs) { - this.outputStreamOffsetUs = outputStreamOffsetUs; - if (outputStreamOffsetUs != C.TIME_UNSET) { - onOutputStreamOffsetUsChanged(outputStreamOffsetUs); + private void setOutputStreamInfo(OutputStreamInfo outputStreamInfo) { + this.outputStreamInfo = outputStreamInfo; + if (outputStreamInfo.streamOffsetUs != C.TIME_UNSET) { + onOutputStreamOffsetUsChanged(outputStreamInfo.streamOffsetUs); } } @@ -2541,6 +2495,26 @@ private static boolean codecNeedsMonoChannelCountWorkaround(String name, Format && "OMX.MTK.AUDIO.DECODER.MP3".equals(name); } + private static final class OutputStreamInfo { + + public static final OutputStreamInfo UNSET = + new OutputStreamInfo( + /* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, + /* startPositionUs= */ C.TIME_UNSET, + /* streamOffsetUs= */ C.TIME_UNSET); + + public final long previousStreamLastBufferTimeUs; + public final long startPositionUs; + public final long streamOffsetUs; + + public OutputStreamInfo( + long previousStreamLastBufferTimeUs, long startPositionUs, long streamOffsetUs) { + this.previousStreamLastBufferTimeUs = previousStreamLastBufferTimeUs; + this.startPositionUs = startPositionUs; + this.streamOffsetUs = streamOffsetUs; + } + } + @RequiresApi(31) private static final class Api31 { private Api31() {}