From 62da288cafcf673bd631eec463c17e74dab484b9 Mon Sep 17 00:00:00 2001 From: claincly Date: Mon, 12 Aug 2024 08:25:33 -0700 Subject: [PATCH] Support removing video in previewing Video playback will be disabled if *any* `EditedMediaItem` removes video. This is consistent with Transformer. PiperOrigin-RevId: 662093484 --- .../performance/CompositionPlaybackTest.java | 37 ++++++++++++++ .../media3/transformer/CompositionPlayer.java | 50 ++++++++++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/performance/CompositionPlaybackTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/performance/CompositionPlaybackTest.java index ca6c16eb64..c37d5d9707 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/performance/CompositionPlaybackTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/performance/CompositionPlaybackTest.java @@ -462,4 +462,41 @@ public class CompositionPlaybackTest { capturingAudioSink, "audiosinkdumps/wav/playback_sequenceOfThreeVideosWithRemovingMiddleAudio_succeeds.dump"); } + + @Test + public void playback_sequenceOfThreeVideosRemovingMiddleVideo_noFrameIsRendered() + throws Exception { + InputTimestampRecordingShaderProgram inputTimestampRecordingShaderProgram = + new InputTimestampRecordingShaderProgram(); + + EditedMediaItem videoEditedMediaItem = + new EditedMediaItem.Builder(VIDEO_MEDIA_ITEM) + .setDurationUs(VIDEO_DURATION_US) + .setEffects( + new Effects( + /* audioProcessors= */ ImmutableList.of(), + /* videoEffects= */ ImmutableList.of( + (GlEffect) (context, useHdr) -> inputTimestampRecordingShaderProgram))) + .build(); + EditedMediaItem videoEditedMediaItemRemoveVideo = + videoEditedMediaItem.buildUpon().setRemoveVideo(true).build(); + Composition composition = + new Composition.Builder( + new EditedMediaItemSequence( + videoEditedMediaItem, videoEditedMediaItemRemoveVideo, videoEditedMediaItem)) + .build(); + + getInstrumentation() + .runOnMainSync( + () -> { + player = new CompositionPlayer.Builder(context).build(); + player.addListener(playerTestListener); + player.setComposition(composition); + player.prepare(); + player.play(); + }); + playerTestListener.waitUntilPlayerEnded(); + + assertThat(inputTimestampRecordingShaderProgram.getInputTimestampsUs()).isEmpty(); + } } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java index 618bb807e2..fc85bd57e6 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java @@ -676,6 +676,9 @@ public final class CompositionPlayer extends SimpleBasePlayer .setClock(clock) .build(); compositingVideoSinkProvider.addListener(this); + + // Video playback is disabled when one EditedMediaItem removes video. + boolean disableVideoPlayback = shouldDisableVideoPlayback(composition); for (int i = 0; i < composition.sequences.size(); i++) { EditedMediaItemSequence editedMediaItemSequence = composition.sequences.get(i); SequencePlayerRenderersWrapper playerRenderersWrapper = @@ -697,7 +700,7 @@ public final class CompositionPlayer extends SimpleBasePlayer .setClock(clock); if (i == 0) { - playerBuilder.setTrackSelector(new CompositionTrackSelector(context)); + playerBuilder.setTrackSelector(new CompositionTrackSelector(context, disableVideoPlayback)); } ExoPlayer player = playerBuilder.build(); @@ -964,6 +967,19 @@ public final class CompositionPlayer extends SimpleBasePlayer return compositionDurationUs; } + private static boolean shouldDisableVideoPlayback(Composition composition) { + for (int i = 0; i < composition.sequences.size(); i++) { + EditedMediaItemSequence editedMediaItemSequence = composition.sequences.get(i); + for (int j = 0; j < editedMediaItemSequence.editedMediaItems.size(); j++) { + EditedMediaItem editedMediaItem = editedMediaItemSequence.editedMediaItems.get(j); + if (editedMediaItem.removeVideo) { + return true; + } + } + } + return false; + } + /** * A {@link VideoFrameReleaseControl.FrameTimingEvaluator} for composition frames. * @@ -1054,9 +1070,11 @@ public final class CompositionPlayer extends SimpleBasePlayer private static final class CompositionTrackSelector extends DefaultTrackSelector { private static final String SILENCE_AUDIO_TRACK_GROUP_ID = "1:"; + private final boolean disableVideoPlayback; - public CompositionTrackSelector(Context context) { + public CompositionTrackSelector(Context context, boolean disableVideoPlayback) { super(context); + this.disableVideoPlayback = disableVideoPlayback; } @Nullable @@ -1108,5 +1126,33 @@ public final class CompositionPlayer extends SimpleBasePlayer return super.selectAudioTrack( mappedTrackInfo, rendererFormatSupports, rendererMixedMimeTypeAdaptationSupports, params); } + + @Nullable + @Override + protected Pair selectVideoTrack( + MappedTrackInfo mappedTrackInfo, + @RendererCapabilities.Capabilities int[][][] rendererFormatSupports, + @RendererCapabilities.AdaptiveSupport int[] mixedMimeTypeSupports, + Parameters params) + throws ExoPlaybackException { + if (disableVideoPlayback) { + return null; + } + return super.selectVideoTrack( + mappedTrackInfo, rendererFormatSupports, mixedMimeTypeSupports, params); + } + + @Nullable + @Override + protected Pair selectImageTrack( + MappedTrackInfo mappedTrackInfo, + @RendererCapabilities.Capabilities int[][][] rendererFormatSupports, + Parameters params) + throws ExoPlaybackException { + if (disableVideoPlayback) { + return null; + } + return super.selectImageTrack(mappedTrackInfo, rendererFormatSupports, params); + } } }