From dcae49a561d3dd0a67a44a913c063b0232bbc445 Mon Sep 17 00:00:00 2001 From: claincly Date: Mon, 29 Jan 2024 04:20:55 -0800 Subject: [PATCH] Fix blank video when switching on/off screen This happens when using `ExoPlayer.setVideoEffects()`. This CL also fixes the first frame not rendered problem, originally solved in https://github.com/androidx/media/commit/7e65cce9678447b7420a0809f88709f0f98b203e, but rolled back in https://github.com/androidx/media/commit/5056dfaa2b9f37f3708cea9ca1c0d4624c149190 because the solution introduces the flash that is observed in b/292111083. Before media3 1.1 release, the output size of `VideoFrameProcessor` is not reported to the app. This was changed later after introducing `CompositingVideoSinkProvider`, where the video size after processing **is** reported to the app. After this CL, the size is again, not reported. PiperOrigin-RevId: 602345087 --- .../media3/effect/EffectPlaybackTest.java | 2 -- .../exoplayer/video/MediaCodecVideoRenderer.java | 16 +++++++++++----- .../exoplayer/video/VideoFrameRenderControl.java | 7 +------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libraries/effect/src/androidTest/java/androidx/media3/effect/EffectPlaybackTest.java b/libraries/effect/src/androidTest/java/androidx/media3/effect/EffectPlaybackTest.java index 1dcdc24c0f..29de571455 100644 --- a/libraries/effect/src/androidTest/java/androidx/media3/effect/EffectPlaybackTest.java +++ b/libraries/effect/src/androidTest/java/androidx/media3/effect/EffectPlaybackTest.java @@ -55,7 +55,6 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.junit.After; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -103,7 +102,6 @@ public class EffectPlaybackTest { } @Test - @Ignore("b/292111083") public void exoplayerEffectsPreviewTest_ensuresFirstFrameRendered() throws Exception { assumeTrue(Util.SDK_INT >= 18); 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 c02f3bb12b..dca7777385 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 @@ -154,6 +154,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer private boolean codecNeedsSetOutputSurfaceWorkaround; private boolean codecHandlesHdr10PlusOutOfBandMetadata; @Nullable private Surface displaySurface; + @Nullable private Size outputResolution; @Nullable private PlaceholderSurface placeholderSurface; private boolean haveReportedFirstFrameRenderedForCurrentSurface; private @C.VideoScalingMode int scalingMode; @@ -771,14 +772,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer setVideoEffects(videoEffects); break; case MSG_SET_VIDEO_OUTPUT_RESOLUTION: - Size outputResolution = (Size) checkNotNull(message); + outputResolution = (Size) checkNotNull(message); // TODO: b/292111083 Set the surface on the videoSinkProvider before it's initialized // otherwise the first frames are missed until a new video output resolution arrives. if (videoSinkProvider.isInitialized() - && outputResolution.getWidth() != 0 - && outputResolution.getHeight() != 0 + && checkNotNull(outputResolution).getWidth() != 0 + && checkNotNull(outputResolution).getHeight() != 0 && displaySurface != null) { - videoSinkProvider.setOutputSurfaceInfo(displaySurface, outputResolution); + videoSinkProvider.setOutputSurfaceInfo(displaySurface, checkNotNull(outputResolution)); } break; case MSG_SET_AUDIO_ATTRIBUTES: @@ -1063,6 +1064,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer if (frameMetadataListener != null) { videoSinkProvider.setVideoFrameMetadataListener(frameMetadataListener); } + if (displaySurface != null && outputResolution != null) { + videoSinkProvider.setOutputSurfaceInfo(displaySurface, outputResolution); + } } catch (VideoSink.VideoSinkException e) { throw createRendererException( e, format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSOR_INIT_FAILED); @@ -1087,7 +1091,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer @Override public void onVideoSizeChanged(VideoSink videoSink, VideoSize videoSize) { - maybeNotifyVideoSizeChanged(videoSize); + // TODO: b/292111083 - Report video size change to app. Video size reporting is + // removed at the moment to ensure the first frame is rendered, and the video is + // rendered after switching on/off the screen. } @Override diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameRenderControl.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameRenderControl.java index 3824ac6eb2..624c977c81 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameRenderControl.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoFrameRenderControl.java @@ -81,8 +81,6 @@ import androidx.media3.exoplayer.ExoPlaybackException; private VideoSize reportedVideoSize; private long outputStreamOffsetUs; - // TODO b/292111083 - Remove the field and trigger the callback on every video size change. - private boolean reportedVideoSizeChange; private long lastPresentationTimeUs; /** Creates an instance. */ @@ -122,8 +120,6 @@ import androidx.media3.exoplayer.ExoPlaybackException; // we keep the latest value of pendingOutputVideoSize videoSizeChanges.clear(); } - // Do not clear reportedVideoSizeChange because we report a video size change at most once - // (b/292111083). } /** Returns whether the renderer is ready. */ @@ -230,9 +226,8 @@ import androidx.media3.exoplayer.ExoPlaybackException; long presentationTimeUs = checkStateNotNull(presentationTimestampsUs.remove()); boolean videoSizeUpdated = maybeUpdateVideoSize(presentationTimeUs); - if (videoSizeUpdated && !reportedVideoSizeChange) { + if (videoSizeUpdated) { frameRenderer.onVideoSizeChanged(reportedVideoSize); - reportedVideoSizeChange = true; } long renderTimeNs = shouldRenderImmediately