From 4c4c5f6a9005f31b62aaf03b11f2a3d2709d408f Mon Sep 17 00:00:00 2001 From: christosts Date: Mon, 11 Dec 2023 07:53:53 -0800 Subject: [PATCH] CompositionVideoSinkProvider: apply rotation effects per video There is a bug in CompositionVideoSinkProvider where the rotation effect is applied only on the first video and the same effect is applied on subsequent videos without checking if the next items in the playlist must be rotated. The bug applies only on devices with API < 21. PiperOrigin-RevId: 589823797 --- .../video/CompositingVideoSinkProvider.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java index 6a101eff94..ac1c281869 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java @@ -283,8 +283,7 @@ public final class CompositingVideoSinkProvider /* compositionEffects= */ ImmutableList.of(), /* initialTimestampOffsetUs= */ 0); videoSinkImpl = - new VideoSinkImpl( - context, /* compositingVideoSinkProvider= */ this, videoGraph, sourceFormat); + new VideoSinkImpl(context, /* compositingVideoSinkProvider= */ this, videoGraph); } catch (VideoFrameProcessingException e) { throw new VideoSink.VideoSinkException(e, sourceFormat); } @@ -520,7 +519,7 @@ public final class CompositingVideoSinkProvider private final VideoFrameProcessor videoFrameProcessor; private final int videoFrameProcessorMaxPendingFrameCount; private final ArrayList videoEffects; - @Nullable private final Effect rotationEffect; + @Nullable private Effect rotationEffect; @Nullable private Format inputFormat; private long inputStreamOffsetUs; @@ -541,8 +540,7 @@ public final class CompositingVideoSinkProvider public VideoSinkImpl( Context context, CompositingVideoSinkProvider compositingVideoSinkProvider, - PreviewingVideoGraph videoGraph, - Format sourceFormat) + PreviewingVideoGraph videoGraph) throws VideoFrameProcessingException { this.context = context; this.compositingVideoSinkProvider = compositingVideoSinkProvider; @@ -556,11 +554,6 @@ public final class CompositingVideoSinkProvider videoFrameProcessor = videoGraph.getProcessor(videoGraphInputId); videoEffects = new ArrayList<>(); - // MediaCodec applies rotation after API 21. - rotationEffect = - Util.SDK_INT < 21 && sourceFormat.rotationDegrees != 0 - ? ScaleAndRotateAccessor.createRotationEffect(sourceFormat.rotationDegrees) - : null; finalBufferPresentationTimeUs = C.TIME_UNSET; lastBufferPresentationTimeUs = C.TIME_UNSET; } @@ -596,6 +589,20 @@ public final class CompositingVideoSinkProvider if (inputType != INPUT_TYPE_SURFACE) { throw new UnsupportedOperationException("Unsupported input type " + inputType); } + // MediaCodec applies rotation after API 21. + if (Util.SDK_INT < 21 + && format.rotationDegrees != Format.NO_VALUE + && format.rotationDegrees != 0) { + // We must apply a rotation effect. + if (rotationEffect == null + || this.inputFormat == null + || this.inputFormat.rotationDegrees != format.rotationDegrees) { + rotationEffect = ScaleAndRotateAccessor.createRotationEffect(format.rotationDegrees); + } // Else, the rotation effect matches the previous format's rotation degrees, keep the same + // instance. + } else { + rotationEffect = null; + } this.inputFormat = format; if (!hasRegisteredFirstInputStream) {