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 12aacaed51..a893255736 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 @@ -1318,6 +1318,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return false; } + // This logic is required for cases where the decoder needs to be flushed or re-instantiated + // during normal consumption of samples from the source (i.e., without a corresponding + // Renderer.enable or Renderer.resetPosition call). This is necessary for certain legacy and + // workaround behaviors, for example when switching the output Surface on API levels prior to + // the introduction of MediaCodec.setOutputSurface. + if (!codecReceivedBuffers && !buffer.isKeyFrame()) { + buffer.clear(); + if (codecReconfigurationState == RECONFIGURATION_STATE_QUEUE_PENDING) { + // The buffer we just cleared contained reconfiguration data. We need to re-write this data + // into a subsequent buffer (if there is one). + codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING; + } + return true; + } + boolean bufferEncrypted = buffer.isEncrypted(); if (bufferEncrypted) { buffer.cryptoInfo.increaseClearDataFirstSubSampleBy(adaptiveReconfigurationBytes); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/audio/MediaCodecAudioRendererTest.java b/library/core/src/test/java/com/google/android/exoplayer2/audio/MediaCodecAudioRendererTest.java index 21c5086c5a..2ff458147a 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/audio/MediaCodecAudioRendererTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/audio/MediaCodecAudioRendererTest.java @@ -115,13 +115,13 @@ public class MediaCodecAudioRendererTest { /* eventDispatcher= */ null, /* initialFormat= */ AUDIO_AAC, ImmutableList.of( - oneByteSample(/* timeUs= */ 0), - oneByteSample(/* timeUs= */ 50), - oneByteSample(/* timeUs= */ 100), + oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 50, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 100, C.BUFFER_FLAG_KEY_FRAME), format(changedFormat), - oneByteSample(/* timeUs= */ 150), - oneByteSample(/* timeUs= */ 200), - oneByteSample(/* timeUs= */ 250), + oneByteSample(/* timeUs= */ 150, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 200, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 250, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM)); mediaCodecAudioRenderer.enable( @@ -162,13 +162,13 @@ public class MediaCodecAudioRendererTest { /* eventDispatcher= */ null, /* initialFormat= */ AUDIO_AAC, ImmutableList.of( - oneByteSample(/* timeUs= */ 0), - oneByteSample(/* timeUs= */ 50), - oneByteSample(/* timeUs= */ 100), + oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 50, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 100, C.BUFFER_FLAG_KEY_FRAME), format(changedFormat), - oneByteSample(/* timeUs= */ 150), - oneByteSample(/* timeUs= */ 200), - oneByteSample(/* timeUs= */ 250), + oneByteSample(/* timeUs= */ 150, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 200, C.BUFFER_FLAG_KEY_FRAME), + oneByteSample(/* timeUs= */ 250, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM)); mediaCodecAudioRenderer.enable( @@ -228,7 +228,8 @@ public class MediaCodecAudioRendererTest { DrmSessionManager.DUMMY, /* eventDispatcher= */ null, /* initialFormat= */ AUDIO_AAC, - ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM)); + ImmutableList.of( + oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM)); exceptionThrowingRenderer.enable( RendererConfiguration.DEFAULT, diff --git a/library/core/src/test/java/com/google/android/exoplayer2/video/MediaCodecVideoRendererTest.java b/library/core/src/test/java/com/google/android/exoplayer2/video/MediaCodecVideoRendererTest.java index 840b87e227..efab1309ba 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/video/MediaCodecVideoRendererTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/video/MediaCodecVideoRendererTest.java @@ -133,7 +133,7 @@ public class MediaCodecVideoRendererTest { /* eventDispatcher= */ null, /* initialFormat= */ VIDEO_H264, ImmutableList.of( - oneByteSample(/* timeUs= */ 0), // First buffer. + oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), // First buffer. oneByteSample(/* timeUs= */ 50_000), // Late buffer. oneByteSample(/* timeUs= */ 100_000), // Last buffer. FakeSampleStreamItem.END_OF_STREAM_ITEM)); @@ -169,7 +169,8 @@ public class MediaCodecVideoRendererTest { /* eventDispatcher= */ null, /* initialFormat= */ VIDEO_H264, ImmutableList.of( - oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM)), + oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), + FakeSampleStreamItem.END_OF_STREAM_ITEM)), /* positionUs= */ 0, /* joining= */ false, /* mayRenderStartOfStream= */ true, @@ -204,7 +205,7 @@ public class MediaCodecVideoRendererTest { DrmSessionManager.DUMMY, /* eventDispatcher= */ null, /* initialFormat= */ pAsp1, - ImmutableList.of(oneByteSample(/* timeUs= */ 0))); + ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME))); mediaCodecVideoRenderer.enable( RendererConfiguration.DEFAULT, @@ -248,7 +249,7 @@ public class MediaCodecVideoRendererTest { DrmSessionManager.DUMMY, /* eventDispatcher= */ null, /* initialFormat= */ VIDEO_H264, - ImmutableList.of(oneByteSample(/* timeUs= */ 0))); + ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME))); mediaCodecVideoRenderer.enable( RendererConfiguration.DEFAULT, new Format[] {VIDEO_H264}, @@ -262,7 +263,8 @@ public class MediaCodecVideoRendererTest { mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); mediaCodecVideoRenderer.resetPosition(0); mediaCodecVideoRenderer.setCurrentStreamFinal(); - fakeSampleStream.addFakeSampleStreamItem(oneByteSample(/* timeUs= */ 0)); + fakeSampleStream.addFakeSampleStreamItem( + oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME)); fakeSampleStream.addFakeSampleStreamItem(FakeSampleStreamItem.END_OF_STREAM_ITEM); int positionUs = 10; do { @@ -280,7 +282,7 @@ public class MediaCodecVideoRendererTest { DrmSessionManager.DUMMY, /* eventDispatcher= */ null, /* initialFormat= */ VIDEO_H264, - ImmutableList.of(oneByteSample(/* timeUs= */ 0))); + ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME))); mediaCodecVideoRenderer.enable( RendererConfiguration.DEFAULT, @@ -329,7 +331,7 @@ public class MediaCodecVideoRendererTest { DrmSessionManager.DUMMY, /* eventDispatcher= */ null, /* initialFormat= */ VIDEO_H264, - ImmutableList.of(oneByteSample(/* timeUs= */ 0))); + ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME))); mediaCodecVideoRenderer.enable( RendererConfiguration.DEFAULT, @@ -445,16 +447,16 @@ public class MediaCodecVideoRendererTest { /* eventDispatcher= */ null, /* initialFormat= */ mp4Uhd, ImmutableList.of( - oneByteSample(/* timeUs= */ 0), + oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), format(VIDEO_H264), - oneByteSample(/* timeUs= */ 50), + oneByteSample(/* timeUs= */ 50, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 100), format(mp4Uhd), - oneByteSample(/* timeUs= */ 150), + oneByteSample(/* timeUs= */ 150, C.BUFFER_FLAG_KEY_FRAME), oneByteSample(/* timeUs= */ 200), oneByteSample(/* timeUs= */ 250), format(VIDEO_H264), - oneByteSample(/* timeUs= */ 300), + oneByteSample(/* timeUs= */ 300, C.BUFFER_FLAG_KEY_FRAME), FakeSampleStreamItem.END_OF_STREAM_ITEM)); mediaCodecVideoRenderer.enable(