Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix(video_player_android): remove incorrect width/height swap for 90/…
…270 rotation

Since #6535 `VideoSize` is used to get width and height instead of getting them from the video `Format`. My testing concluded that `VideoSize` dimension values are post rotation and do not need to be swapped when there is a 90 or 270 degree rotation present.
  • Loading branch information
marvin-kolja committed May 4, 2025
commit a633acaeee84d6eb8cc86020310a122bc61ea18f
Original file line number Diff line number Diff line change
Expand Up @@ -30,70 +30,58 @@ public TextureExoPlayerEventListener(
@Override
protected void sendInitialized() {
VideoSize videoSize = exoPlayer.getVideoSize();
int rotationCorrection = 0;
RotationDegrees rotationCorrection = RotationDegrees.ROTATE_0;
int width = videoSize.width;
int height = videoSize.height;
if (width != 0 && height != 0) {
RotationDegrees reportedRotationCorrection = RotationDegrees.ROTATE_0;

if (Build.VERSION.SDK_INT <= 21) {
// On API 21 and below, Exoplayer may not internally handle rotation correction
// and reports it through VideoSize.unappliedRotationDegrees. We may apply it to
// fix the case of upside-down playback.
try {
reportedRotationCorrection =
RotationDegrees unappliedRotation =
RotationDegrees.fromDegrees(videoSize.unappliedRotationDegrees);
rotationCorrection =
getRotationCorrectionFromUnappliedRotation(reportedRotationCorrection);
rotationCorrection = getRotationCorrectionFromUnappliedRotation(unappliedRotation);
} catch (IllegalArgumentException e) {
// Unapplied rotation other than 0, 90, 180, 270 reported by VideoSize. Because this is
// unexpected, we apply no rotation correction.
reportedRotationCorrection = RotationDegrees.ROTATE_0;
rotationCorrection = 0;
rotationCorrection = RotationDegrees.ROTATE_0;
}
}
// TODO(camsim99): Replace this with a call to `handlesCropAndRotation` when it is
// available in stable. https://github.com/flutter/flutter/issues/157198
else if (Build.VERSION.SDK_INT < 29) {
// When the SurfaceTexture backend for Impeller is used, the preview should already
// be correctly rotated.
rotationCorrection = 0;
rotationCorrection = RotationDegrees.ROTATE_0;
} else {
// The video's Format also provides a rotation correction that may be used to
// correct the rotation, so we try to use that to correct the video rotation
// when the ImageReader backend for Impeller is used.
rotationCorrection = getRotationCorrectionFromFormat(exoPlayer);
int rawVideoFormatRotation = getRotationCorrectionFromFormat(exoPlayer);

try {
reportedRotationCorrection = RotationDegrees.fromDegrees(rotationCorrection);
rotationCorrection = RotationDegrees.fromDegrees(rawVideoFormatRotation);
} catch (IllegalArgumentException e) {
// Rotation correction other than 0, 90, 180, 270 reported by Format. Because this is
// unexpected we apply no rotation correction.
reportedRotationCorrection = RotationDegrees.ROTATE_0;
rotationCorrection = 0;
rotationCorrection = RotationDegrees.ROTATE_0;
}
}

// Switch the width/height if video was taken in portrait mode and a rotation
// correction was detected.
if (reportedRotationCorrection == RotationDegrees.ROTATE_90
|| reportedRotationCorrection == RotationDegrees.ROTATE_270) {
width = videoSize.height;
height = videoSize.width;
}
}
events.onInitialized(width, height, exoPlayer.getDuration(), rotationCorrection);
events.onInitialized(width, height, exoPlayer.getDuration(), rotationCorrection.getDegrees());
}

private int getRotationCorrectionFromUnappliedRotation(RotationDegrees unappliedRotationDegrees) {
int rotationCorrection = 0;
private RotationDegrees getRotationCorrectionFromUnappliedRotation(
RotationDegrees unappliedRotationDegrees) {
RotationDegrees rotationCorrection = RotationDegrees.ROTATE_0;

// Rotating the video with ExoPlayer does not seem to be possible with a Surface,
// so inform the Flutter code that the widget needs to be rotated to prevent
// upside-down playback for videos with unappliedRotationDegrees of 180 (other orientations
// work correctly without correction).
if (unappliedRotationDegrees == RotationDegrees.ROTATE_180) {
rotationCorrection = unappliedRotationDegrees.getDegrees();
rotationCorrection = unappliedRotationDegrees;
}

return rotationCorrection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);

eventListener.onPlaybackStateChanged(Player.STATE_READY);
verify(mockCallbacks).onInitialized(400, 800, 10L, rotationCorrection);
verify(mockCallbacks).onInitialized(800, 400, 10L, rotationCorrection);
}

@Test
Expand All @@ -78,7 +78,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
when(mockExoPlayer.getDuration()).thenReturn(10L);

eventListener.onPlaybackStateChanged(Player.STATE_READY);
verify(mockCallbacks).onInitialized(400, 800, 10L, 0);
verify(mockCallbacks).onInitialized(800, 400, 10L, 0);
}

@Test
Expand Down Expand Up @@ -107,7 +107,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);

eventListener.onPlaybackStateChanged(Player.STATE_READY);
verify(mockCallbacks).onInitialized(400, 800, 10L, 90);
verify(mockCallbacks).onInitialized(800, 400, 10L, 90);
}

@Test
Expand All @@ -119,7 +119,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
when(mockExoPlayer.getDuration()).thenReturn(10L);

eventListener.onPlaybackStateChanged(Player.STATE_READY);
verify(mockCallbacks).onInitialized(400, 800, 10L, 0);
verify(mockCallbacks).onInitialized(800, 400, 10L, 0);
}

@Test
Expand Down Expand Up @@ -147,7 +147,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);

eventListener.onPlaybackStateChanged(Player.STATE_READY);
verify(mockCallbacks).onInitialized(400, 800, 10L, 270);
verify(mockCallbacks).onInitialized(800, 400, 10L, 270);
}

@Test
Expand Down