From 3972d25a8a399f7e88c0416f7398b5f3ace1762d Mon Sep 17 00:00:00 2001 From: tonihei Date: Mon, 11 Mar 2024 09:46:07 -0700 Subject: [PATCH] Always set PARAMETER_KEY_TUNNEL_PEEK when tunneling This should already be the default, but some devices seem to not adhere to this contract and assume the default is unset. Issue: androidx/media#1169 PiperOrigin-RevId: 614697283 (cherry picked from commit cbed80ecf36d3ff49ec9d2806670f1fda3551aba) --- RELEASENOTES.md | 3 ++ .../video/MediaCodecVideoRenderer.java | 42 +++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b28575c27a..7e5bf2b051 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -27,6 +27,9 @@ * Add workaround for a device issue on Galaxy Tab S7 FE, Chromecast with Google TV, and Lenovo M10 FHD Plus that causes 60fps H265 streams to be marked as unsupported + * Add workaround that ensures the first frame is always rendered while + tunneling even if the device does not do this automatically as required + by the API ([#1169](https://github.com/androidx/media/issues/1169)). ([#966](https://github.com/androidx/media/issues/966)). * DRM: * Work around a `NoSuchMethodError` which can be thrown by the `MediaDrm` diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java index 884002da1d..93051fbfd4 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java @@ -659,7 +659,7 @@ protected void onPositionReset(long positionUs, boolean joining) throws ExoPlayb if (joining) { videoFrameReleaseControl.join(); } - maybeUpdateOnFrameRenderedListener(); + maybeSetupTunnelingForFirstFrame(); consecutiveDroppedFrameCount = 0; } @@ -704,7 +704,7 @@ protected void onStopped() { protected void onDisabled() { reportedVideoSize = null; videoFrameReleaseControl.onDisabled(); - maybeUpdateOnFrameRenderedListener(); + maybeSetupTunnelingForFirstFrame(); haveReportedFirstFrameRenderedForCurrentSurface = false; tunnelingOnFrameRenderedListener = null; try { @@ -846,7 +846,7 @@ private void setOutput(@Nullable Object output) throws ExoPlaybackException { videoSinkProvider.clearOutputSurfaceInfo(); } } - maybeUpdateOnFrameRenderedListener(); + maybeSetupTunnelingForFirstFrame(); } else if (displaySurface != null && displaySurface != placeholderSurface) { // The display surface is set and unchanged. If we know the video size and/or have already // rendered to the display surface, report these again immediately. @@ -1129,9 +1129,7 @@ protected void onCodecInitialized( codecNeedsSetOutputSurfaceWorkaround = codecNeedsSetOutputSurfaceWorkaround(name); codecHandlesHdr10PlusOutOfBandMetadata = checkNotNull(getCodecInfo()).isHdr10PlusOutOfBandMetadataSupported(); - if (Util.SDK_INT >= 23 && tunneling) { - tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(checkNotNull(getCodec())); - } + maybeSetupTunnelingForFirstFrame(); } @Override @@ -1462,7 +1460,7 @@ protected void onProcessedOutputBuffer(long presentationTimeUs) { protected void onProcessedStreamChange() { super.onProcessedStreamChange(); videoFrameReleaseControl.onProcessedStreamChange(); - maybeUpdateOnFrameRenderedListener(); + maybeSetupTunnelingForFirstFrame(); if (videoSinkProvider.isInitialized()) { videoSinkProvider.setStreamOffsetUs(getOutputStreamOffsetUs()); } @@ -1693,17 +1691,25 @@ private void releasePlaceholderSurface() { } } - private void maybeUpdateOnFrameRenderedListener() { - // The first frame notification is triggered by renderOutputBuffer or renderOutputBufferV21 for - // non-tunneled playback, onQueueInputBuffer for tunneled playback prior to API level 23, and - // OnFrameRenderedListenerV23.onFrameRenderedListener for tunneled playback on API level 23 and - // above. - if (Util.SDK_INT >= 23 && tunneling) { - @Nullable MediaCodecAdapter codec = getCodec(); - // If codec is null then the listener will be instantiated in configureCodec. - if (codec != null) { - tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec); - } + private void maybeSetupTunnelingForFirstFrame() { + if (!tunneling || Util.SDK_INT < 23) { + // The first frame notification for tunneling is triggered by onQueueInputBuffer prior to API + // level 23 and no setup is needed here. + return; + } + @Nullable MediaCodecAdapter codec = getCodec(); + if (codec == null) { + // If codec is null, then the setup will be triggered again in onCodecInitialized. + return; + } + tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec); + if (Util.SDK_INT >= 33) { + // This should be the default anyway according to the API contract, but some devices are known + // to not adhere to this contract and need to get the parameter explicitly. See + // https://github.com/androidx/media/issues/1169. + Bundle codecParameters = new Bundle(); + codecParameters.putInt(MediaCodec.PARAMETER_KEY_TUNNEL_PEEK, 1); + codec.setParameters(codecParameters); } }