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
This commit is contained in:
christosts 2023-12-11 07:53:53 -08:00 committed by Copybara-Service
parent 379cb3ba54
commit 4c4c5f6a90

View File

@ -283,8 +283,7 @@ public final class CompositingVideoSinkProvider
/* compositionEffects= */ ImmutableList.of(), /* compositionEffects= */ ImmutableList.of(),
/* initialTimestampOffsetUs= */ 0); /* initialTimestampOffsetUs= */ 0);
videoSinkImpl = videoSinkImpl =
new VideoSinkImpl( new VideoSinkImpl(context, /* compositingVideoSinkProvider= */ this, videoGraph);
context, /* compositingVideoSinkProvider= */ this, videoGraph, sourceFormat);
} catch (VideoFrameProcessingException e) { } catch (VideoFrameProcessingException e) {
throw new VideoSink.VideoSinkException(e, sourceFormat); throw new VideoSink.VideoSinkException(e, sourceFormat);
} }
@ -520,7 +519,7 @@ public final class CompositingVideoSinkProvider
private final VideoFrameProcessor videoFrameProcessor; private final VideoFrameProcessor videoFrameProcessor;
private final int videoFrameProcessorMaxPendingFrameCount; private final int videoFrameProcessorMaxPendingFrameCount;
private final ArrayList<Effect> videoEffects; private final ArrayList<Effect> videoEffects;
@Nullable private final Effect rotationEffect; @Nullable private Effect rotationEffect;
@Nullable private Format inputFormat; @Nullable private Format inputFormat;
private long inputStreamOffsetUs; private long inputStreamOffsetUs;
@ -541,8 +540,7 @@ public final class CompositingVideoSinkProvider
public VideoSinkImpl( public VideoSinkImpl(
Context context, Context context,
CompositingVideoSinkProvider compositingVideoSinkProvider, CompositingVideoSinkProvider compositingVideoSinkProvider,
PreviewingVideoGraph videoGraph, PreviewingVideoGraph videoGraph)
Format sourceFormat)
throws VideoFrameProcessingException { throws VideoFrameProcessingException {
this.context = context; this.context = context;
this.compositingVideoSinkProvider = compositingVideoSinkProvider; this.compositingVideoSinkProvider = compositingVideoSinkProvider;
@ -556,11 +554,6 @@ public final class CompositingVideoSinkProvider
videoFrameProcessor = videoGraph.getProcessor(videoGraphInputId); videoFrameProcessor = videoGraph.getProcessor(videoGraphInputId);
videoEffects = new ArrayList<>(); 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; finalBufferPresentationTimeUs = C.TIME_UNSET;
lastBufferPresentationTimeUs = C.TIME_UNSET; lastBufferPresentationTimeUs = C.TIME_UNSET;
} }
@ -596,6 +589,20 @@ public final class CompositingVideoSinkProvider
if (inputType != INPUT_TYPE_SURFACE) { if (inputType != INPUT_TYPE_SURFACE) {
throw new UnsupportedOperationException("Unsupported input type " + inputType); 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; this.inputFormat = format;
if (!hasRegisteredFirstInputStream) { if (!hasRegisteredFirstInputStream) {