Skip to content

Commit

Permalink
Fix bypass mode when the stream is empty
Browse files Browse the repository at this point in the history
#minor-release
Issue: #8374
PiperOrigin-RevId: 348792965
  • Loading branch information
ojw28 committed Dec 23, 2020
1 parent e71ce06 commit 5f3d1c1
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 31 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
([#5887](https://github.com/google/ExoPlayer/issues/5887)).
* Fix bug where `AnalyticsListener` callbacks can arrive in the wrong
order ([#8048](https://github.com/google/ExoPlayer/issues/8048)).
* Fix `MediaCodecRenderer` issue where empty streams would fail to play in
bypass mode ([#8374](https://github.com/google/ExoPlayer/issues/8374)).
* Add `onEvents` callback to `Player.EventListener` and
`AnalyticsListener` to notify when all simultaneous state changes have
been handled and the values reported through callbacks are again
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,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();
}

Expand Down Expand Up @@ -2122,15 +2127,15 @@ 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.
*/
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(
Expand All @@ -2145,12 +2150,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;
Expand Down Expand Up @@ -2185,19 +2191,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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,25 @@ public void test_500ms() throws Exception {
DumpFileAsserts.assertOutput(
applicationContext, playbackOutput, "playbackdumps/silence/500ms.dump");
}

@Test
public void test_0ms() throws Exception {
Context applicationContext = ApplicationProvider.getApplicationContext();
CapturingRenderersFactory capturingRenderersFactory =
new CapturingRenderersFactory(applicationContext);
SimpleExoPlayer player =
new SimpleExoPlayer.Builder(applicationContext, capturingRenderersFactory)
.setClock(new AutoAdvancingFakeClock())
.build();
PlaybackOutput playbackOutput = PlaybackOutput.register(player, capturingRenderersFactory);

player.setMediaSource(new SilenceMediaSource(/* durationUs= */ 0));
player.prepare();
player.play();
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED);
player.release();

DumpFileAsserts.assertOutput(
applicationContext, playbackOutput, "playbackdumps/silence/0ms.dump");
}
}
Empty file.

0 comments on commit 5f3d1c1

Please sign in to comment.