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
Prev Previous commit
Next Next commit
Fix code + add tests
  • Loading branch information
camsim99 committed Oct 16, 2024
commit 2664b51063017bf5f2a97cfa19e7fc4ccb4b3031
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.media3.common.Format;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.VideoSize;
Expand Down Expand Up @@ -42,29 +44,34 @@ private void setBuffering(boolean buffering) {

@SuppressWarnings("SuspiciousNameCombination")
private void sendInitialized() {
System.out.println("Hello???");
if (isInitialized) {
return;
}
isInitialized = true;
VideoSize videoSize = exoPlayer.getVideoSize();
int rotationCorrection = 0;
int width = videoSize.width;
int height = videoSize.height;
int rotationCorrection = 0;
if (width != 0 && height != 0) {
int reportedRotationCorrection;

if (Build.VERSION.SDK_INT <= 21) {
// On API 21 and below, Exoplayer may not internally handle rotation correction
// and reports it through VideoSize.unappliedRotationDegrees.
rotationCorrection = getRotationCorrectionFromUnappliedRotation(videoSize);
// and reports it through VideoSize.unappliedRotationDegrees. We may apply it to
// fix the case of upside-down playback.
reportedRotationCorrection = videoSize.unappliedRotationDegrees;
rotationCorrection = getRotationCorrectionFromUnappliedRotation(reportedRotationCorrection);
} else {
// Above API 21, Exoplayer handles the VideoSize.unappliedRotationDegrees
// correction internally. However, the video's Format also provides a rotation
// correction that may be used to correct the rotation, so we try to use that.
Format videoFormat = Objects.requireNonNull(exoPlayer.getVideoFormat());
rotationCorrection = getRotationCorrectionFromFormat(videoFormat);
rotationCorrection = getRotationCorrectionFromFormat(exoPlayer);
reportedRotationCorrection = rotationCorrection;
}

// Switch the width/height if video was taken in portrait mode.
if (rotationDegrees == 90 || rotationDegrees == 270) {
if (reportedRotationCorrection == 90 || reportedRotationCorrection == 270) {
width = videoSize.height;
height = videoSize.width;
}
Expand All @@ -73,22 +80,23 @@ private void sendInitialized() {
events.onInitialized(width, height, exoPlayer.getDuration(), rotationCorrection);
}

private int getRotationCorrectionFromUnappliedRotation(VideoSize videoSize) {
int rotationCorrection = 0;
int unappliedRotationDegrees = videoSize.unappliedRotationDegrees;
private int getRotationCorrectionFromUnappliedRotation(int unappliedRotationDegrees) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using an enum instead of an int since our code does not actually handle in between values.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 enum

int rotationCorrection = 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 == 180) {
rotationCorrection = unappliedRotationDegrees;
}
// 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 == 180) {
rotationCorrection = unappliedRotationDegrees;
}

return rotationCorrection;
}

private int getRotationCorrectionFromFormat(Format videoFormat) {
@OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
private int getRotationCorrectionFromFormat(ExoPlayer exoPlayer) {
Format videoFormat = Objects.requireNonNull(exoPlayer.getVideoFormat());
return videoFormat.rotationDegrees;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import androidx.media3.common.Format;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.VideoSize;
Expand All @@ -24,6 +25,7 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

/**
* Unit tests for {@link ExoPlayerEventListener}.
Expand Down Expand Up @@ -58,18 +60,24 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid21() {

@Test
@Config(sdk = 22)
public void onPlaybackStateChangedReadySendInitialized_aboveAndroid21() {
public void
onPlaybackStateChangedReadySendInitializedWithRotationCorrectionAndWidthAndHeightSwap_aboveAndroid21() {
VideoSize size = new VideoSize(800, 400, 0, 0);
int rotationCorrection = 90;
Format mockFormat = new Format.Builder().setRotationDegrees(rotationCorrection);
when(mockExoPlayer.getVideoFormat()).thenReturn(mockFormat);
Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();

when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);

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

@Test
@Config(sdk = 21)
public void onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_belowAndroid21() {
public void
onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_belowAndroid21() {
VideoSize size = new VideoSize(800, 400, 90, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
Expand All @@ -79,16 +87,25 @@ public void onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight
}

@Test
@Config(sdk = 21)
public void onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_aboveAndroid21() {
@Config(sdk = 22)
public void
onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_aboveAndroid21() {
VideoSize size = new VideoSize(800, 400, 0, 0);
int rotationCorrection = 90;
Format mockFormat = new Format.Builder().setRotationDegrees(rotationCorrection);
when(mockExoPlayer.getVideoFormat()).thenReturn(mockFormat);
Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();

when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);

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

@Test
@Config(sdk = 21)
public void onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_belowAndroid21() {
public void
onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_belowAndroid21() {
VideoSize size = new VideoSize(800, 400, 270, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
Expand All @@ -97,6 +114,22 @@ public void onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeigh
verify(mockCallbacks).onInitialized(400, 800, 10L, 0);
}

@Test
@Config(sdk = 22)
public void
onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_aboveAndroid21() {
VideoSize size = new VideoSize(800, 400, 0, 0);
int rotationCorrection = 270;
Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();

when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
when(mockExoPlayer.getVideoFormat()).thenReturn(videoFormat);

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

@Test
@Config(sdk = 21)
public void onPlaybackStateChangedReadyFlipped180DegreesInformEventHandler_belowAndroid21() {
Expand Down