From 39935d7f1202a4e327b968815bf499cc7bcab4c4 Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 27 Feb 2023 10:41:38 +0000 Subject: [PATCH] Correctly update output info if previous stream has been fully rendered The output info for a new stream is marked pending until the last sample of the previous stream has been processed. However, this fails if the previous stream has already been fully processed. We need to detect this case explicitly to avoid signalling the output change one sample too late. #minor-release PiperOrigin-RevId: 512572854 --- .../exoplayer2/mediacodec/MediaCodecRenderer.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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 f059a2f6e4..37132ebbf1 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 @@ -358,6 +358,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @Nullable private ExoPlaybackException pendingPlaybackException; protected DecoderCounters decoderCounters; private OutputStreamInfo outputStreamInfo; + private long lastProcessedOutputBufferTimeUs; /** * @param trackType The {@link C.TrackType track type} that the renderer handles. @@ -409,6 +410,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecHotswapDeadlineMs = C.TIME_UNSET; largestQueuedPresentationTimeUs = C.TIME_UNSET; lastBufferInStreamPresentationTimeUs = C.TIME_UNSET; + lastProcessedOutputBufferTimeUs = C.TIME_UNSET; codecDrainState = DRAIN_STATE_NONE; codecDrainAction = DRAIN_ACTION_NONE; } @@ -638,8 +640,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @Override protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) throws ExoPlaybackException { - if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET) { - checkState(outputStreamInfo.startPositionUs == C.TIME_UNSET); + if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET + || (pendingOutputStreamChanges.isEmpty() + && lastProcessedOutputBufferTimeUs != C.TIME_UNSET + && lastProcessedOutputBufferTimeUs >= largestQueuedPresentationTimeUs)) { + // This is the first stream, or the previous has been fully output already. setOutputStreamInfo( new OutputStreamInfo( /* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, startPositionUs, offsetUs)); @@ -873,6 +878,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { decodeOnlyPresentationTimestamps.clear(); largestQueuedPresentationTimeUs = C.TIME_UNSET; lastBufferInStreamPresentationTimeUs = C.TIME_UNSET; + lastProcessedOutputBufferTimeUs = C.TIME_UNSET; if (c2Mp3TimestampTracker != null) { c2Mp3TimestampTracker.reset(); } @@ -1586,6 +1592,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { */ @CallSuper protected void onProcessedOutputBuffer(long presentationTimeUs) { + lastProcessedOutputBufferTimeUs = presentationTimeUs; if (!pendingOutputStreamChanges.isEmpty() && presentationTimeUs >= pendingOutputStreamChanges.peek().previousStreamLastBufferTimeUs) { setOutputStreamInfo(pendingOutputStreamChanges.poll());