From ca287ba5623a01007067f2bf0692622ff92fefe2 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 23 Dec 2020 15:36:11 +0000 Subject: [PATCH] Fix bypass mode when the stream is empty Issue: #8374 PiperOrigin-RevId: 348792965 --- RELEASENOTES.md | 2 ++ .../exoplayer2/mediacodec/BatchBuffer.java | 36 +++++++++---------- .../mediacodec/MediaCodecRenderer.java | 30 +++++++++------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 28d897f9047..77d8ffc8c76 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -5,6 +5,8 @@ * Core library: * Fix playback issues after seeking during an ad ([#8349](https://github.com/google/ExoPlayer/issues/8349)). + * Fix `MediaCodecRenderer` issue where empty streams would fail to play in + bypass mode ([#8374](https://github.com/google/ExoPlayer/issues/8374)). * UI: * Fix issue where pop-up menus belonging to `StyledPlayerControlView` would not be dismissed when tapping outside of the menu area or pressing diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/BatchBuffer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/BatchBuffer.java index 3c40fe02d48..f770e92a210 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/BatchBuffer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/BatchBuffer.java @@ -153,26 +153,26 @@ private boolean canBatch(DecoderInputBuffer accessUnit) { } private void putAccessUnit(DecoderInputBuffer accessUnit) { - @Nullable ByteBuffer accessUnitData = accessUnit.data; - if (accessUnitData != null) { - accessUnit.flip(); - ensureSpaceForWrite(accessUnitData.remaining()); - this.data.put(accessUnitData); - } - if (accessUnit.isEndOfStream()) { setFlags(C.BUFFER_FLAG_END_OF_STREAM); - } - if (accessUnit.isDecodeOnly()) { - setFlags(C.BUFFER_FLAG_DECODE_ONLY); - } - if (accessUnit.isKeyFrame()) { - setFlags(C.BUFFER_FLAG_KEY_FRAME); - } - accessUnitCount++; - timeUs = accessUnit.timeUs; - if (accessUnitCount == 1) { // First read of the buffer - firstAccessUnitTimeUs = timeUs; + } else { + timeUs = accessUnit.timeUs; + if (accessUnit.isDecodeOnly()) { + setFlags(C.BUFFER_FLAG_DECODE_ONLY); + } + if (accessUnit.isKeyFrame()) { + setFlags(C.BUFFER_FLAG_KEY_FRAME); + } + @Nullable ByteBuffer accessUnitData = accessUnit.data; + if (accessUnitData != null) { + accessUnit.flip(); + ensureSpaceForWrite(accessUnitData.remaining()); + this.data.put(accessUnitData); + } + accessUnitCount++; + if (accessUnitCount == 1) { + firstAccessUnitTimeUs = timeUs; + } } accessUnit.clear(); } 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 4cecf7ce3c3..75ee7f5c818 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 @@ -450,6 +450,11 @@ public MediaCodecRenderer( outputStreamStartPositionUs = C.TIME_UNSET; outputStreamOffsetUs = C.TIME_UNSET; bypassBatchBuffer = new BatchBuffer(); + bypassBatchBuffer.ensureSpaceForWrite(/* length= */ 0); + // 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. + bypassBatchBuffer.data.order(ByteOrder.nativeOrder()); resetCodecStateForRelease(); } @@ -2134,7 +2139,7 @@ private FrameworkMediaCrypto getFrameworkMediaCrypto(DrmSession drmSession) * iteration of the rendering loop. * @param elapsedRealtimeUs {@link SystemClock#elapsedRealtime()} in microseconds, measured at the * start of the current iteration of the rendering loop. - * @return If more buffers are ready to be rendered. + * @return Whether immediately calling this method again will make more progress. * @throws ExoPlaybackException If an error occurred while processing a buffer or handling a * format change. */ @@ -2142,7 +2147,7 @@ private boolean bypassRender(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { BatchBuffer batchBuffer = bypassBatchBuffer; - // Let's process the pending buffer if any. + // Process any data in the batch buffer. checkState(!outputStreamEnded); if (!batchBuffer.isEmpty()) { // Optimisation: Do not process buffer if empty. if (processOutputBuffer( @@ -2157,12 +2162,13 @@ private boolean bypassRender(long positionUs, long elapsedRealtimeUs) batchBuffer.isDecodeOnly(), batchBuffer.isEndOfStream(), outputFormat)) { - // Buffer completely processed onProcessedOutputBuffer(batchBuffer.getLastAccessUnitTimeUs()); } else { - return false; // Could not process buffer, let's try later. + // Could not process the whole buffer. Try again later. + return false; } } + // Process the end of stream, if it has been reached. if (batchBuffer.isEndOfStream()) { outputStreamEnded = true; return false; @@ -2197,19 +2203,17 @@ private boolean bypassRender(long positionUs, long elapsedRealtimeUs) onInputFormatChanged(formatHolder); } + boolean haveDataToProcess = false; if (batchBuffer.isEndOfStream()) { inputStreamEnded = true; + haveDataToProcess = true; } - - if (batchBuffer.isEmpty()) { - return false; // The buffer could not be filled, there is nothing more to do. + if (!batchBuffer.isEmpty()) { + batchBuffer.flip(); + haveDataToProcess = true; } - batchBuffer.flip(); // Buffer at least partially full, it can now be processed. - // MediaCodec outputs buffers in native endian: - // https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers - // and code called from processOutputBuffer expects this endianness. - batchBuffer.data.order(ByteOrder.nativeOrder()); - return true; + + return haveDataToProcess; } /**