Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[video_player_android] Use handlesCropAndRotation to detect the SurfaceTexture vs ImageReader backend #8764

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion packages/video_player/video_player_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
## NEXT
## 2.7.18

* Suppresses deprecation and removal warnings for
`TextureRegistry.SurfaceProducer.onSurfaceDestroyed`.
* Changes plugin to use `TextureRegistry.SurfaceProducer.handlesCropAndRotation`
to detect the backend used to provide `Surface`s.

## 2.7.17

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ final class ExoPlayerEventListener implements Player.Listener {
private final VideoPlayerCallbacks events;
private boolean isBuffering = false;
private boolean isInitialized;
private boolean surfaceProducerHandlesCropAndRotation;

private enum RotationDegrees {
ROTATE_0(0),
Expand Down Expand Up @@ -46,14 +47,15 @@ public int getDegrees() {
}
}

ExoPlayerEventListener(ExoPlayer exoPlayer, VideoPlayerCallbacks events) {
this(exoPlayer, events, false);
ExoPlayerEventListener(ExoPlayer exoPlayer, VideoPlayerCallbacks events, boolean surfaceProducerHandlesCropAndRotation) {
this(exoPlayer, events, false, surfaceProducerHandlesCropAndRotation);
}

ExoPlayerEventListener(ExoPlayer exoPlayer, VideoPlayerCallbacks events, boolean initialized) {
ExoPlayerEventListener(ExoPlayer exoPlayer, VideoPlayerCallbacks events, boolean initialized, boolean surfaceProducerHandlesCropAndRotation) {
this.exoPlayer = exoPlayer;
this.events = events;
this.isInitialized = initialized;
this.surfaceProducerHandlesCropAndRotation = surfaceProducerHandlesCropAndRotation;
}

private void setBuffering(boolean buffering) {
Expand Down Expand Up @@ -97,9 +99,7 @@ private void sendInitialized() {
rotationCorrection = 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) {
else if (surfaceProducerHandlesCropAndRotation) {
// When the SurfaceTexture backend for Impeller is used, the preview should already
// be correctly rotated.
rotationCorrection = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ private ExoPlayer createVideoPlayer() {
exoPlayer.setVideoSurface(surfaceProducer.getSurface());

boolean wasInitialized = savedStateDuring != null;
exoPlayer.addListener(new ExoPlayerEventListener(exoPlayer, videoPlayerEvents, wasInitialized));
boolean surfaceProducerHandlesCropAndRotation = surfaceProducer.handlesCropAndRotation();
exoPlayer.addListener(new ExoPlayerEventListener(exoPlayer, videoPlayerEvents, wasInitialized, surfaceProducerHandlesCropAndRotation));
setAudioAttributes(exoPlayer, options.mixWithOthers);

return exoPlayer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,22 @@ public final class ExoPlayerEventListenerTest {

@Rule public MockitoRule initRule = MockitoJUnit.rule();

@Before
public void setUp() {
eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks);
@Test
@Config(maxSdk = 21)
public void onPlaybackStateChangedReadySendInitialized_belowAndroid21() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
VideoSize size = new VideoSize(800, 400, 0, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);

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

@Test
@Config(maxSdk = 28)
public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
@Config(minSdk = 22)
public void onPlaybackStateChangedReadySendInitialized_whenSurfaceProducerHandlesCropAndRotation() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
VideoSize size = new VideoSize(800, 400, 0, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
Expand All @@ -59,9 +67,10 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
}

@Test
@Config(minSdk = 29)
@Config(minSdk = 22)
public void
onPlaybackStateChangedReadySendInitializedWithRotationCorrectionAndWidthAndHeightSwap_aboveAndroid29() {
onPlaybackStateChangedReadySendInitializedWithRotationCorrectionAndWidthAndHeightSwap_whenSurfaceProducerDoesNotHandleCropAndRotation() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, false);
VideoSize size = new VideoSize(800, 400, 0, 0);
int rotationCorrection = 90;
Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();
Expand All @@ -78,6 +87,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
@Config(maxSdk = 21)
public void
onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_belowAndroid21() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
VideoSize size = new VideoSize(800, 400, 90, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
Expand All @@ -87,9 +97,10 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
}

@Test
@Config(minSdk = 22, maxSdk = 28)
@Config(minSdk = 22)
public void
onPlaybackStateChangedReadyInPortraitMode90DegreesDoesNotSwapWidthAndHeight_aboveAndroid21belowAndroid29() {
onPlaybackStateChangedReadyInPortraitMode90DegreesDoesNotSwapWidthAndHeight_whenSurfaceProducerHandlesCropAndRotation() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
VideoSize size = new VideoSize(800, 400, 90, 0);

when(mockExoPlayer.getVideoSize()).thenReturn(size);
Expand All @@ -100,9 +111,10 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
}

@Test
@Config(minSdk = 29)
@Config(minSdk = 22)
public void
onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_aboveAndroid29() {
onPlaybackStateChangedReadyInPortraitMode90DegreesSwapWidthAndHeight_whenSurfaceProducerDoesNotHandleCropAndRotation() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, false);
VideoSize size = new VideoSize(800, 400, 0, 0);
int rotationCorrection = 90;
Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();
Expand All @@ -119,6 +131,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
@Config(maxSdk = 21)
public void
onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_belowAndroid21() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
VideoSize size = new VideoSize(800, 400, 270, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
Expand All @@ -128,9 +141,10 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
}

@Test
@Config(minSdk = 22, maxSdk = 28)
@Config(minSdk = 22)
public void
onPlaybackStateChangedReadyInPortraitMode270DegreesDoesNotSwapWidthAndHeight_aboveAndroid21belowAndroid29() {
onPlaybackStateChangedReadyInPortraitMode270DegreesDoesNotSwapWidthAndHeight_whenSurfaceProducerHandlesCropAndRotation() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
VideoSize size = new VideoSize(800, 400, 270, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
Expand All @@ -140,9 +154,10 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
}

@Test
@Config(minSdk = 29)
@Config(minSdk = 22)
public void
onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_aboveAndroid29() {
onPlaybackStateChangedReadyInPortraitMode270DegreesSwapWidthAndHeight_whenSurfaceProducerDoesNotHandleCropAndRotation() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, false);
VideoSize size = new VideoSize(800, 400, 0, 0);
int rotationCorrection = 270;
Format videoFormat = new Format.Builder().setRotationDegrees(rotationCorrection).build();
Expand All @@ -158,6 +173,7 @@ public void onPlaybackStateChangedReadySendInitialized_belowAndroid29() {
@Test
@Config(maxSdk = 21)
public void onPlaybackStateChangedReadyFlipped180DegreesInformEventHandler_belowAndroid21() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
VideoSize size = new VideoSize(800, 400, 180, 0);
when(mockExoPlayer.getVideoSize()).thenReturn(size);
when(mockExoPlayer.getDuration()).thenReturn(10L);
Expand All @@ -168,6 +184,7 @@ public void onPlaybackStateChangedReadyFlipped180DegreesInformEventHandler_below

@Test
public void onPlaybackStateChangedBufferingSendsBufferingStartAndUpdates() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
when(mockExoPlayer.getBufferedPosition()).thenReturn(10L);
eventListener.onPlaybackStateChanged(Player.STATE_BUFFERING);

Expand All @@ -182,6 +199,7 @@ public void onPlaybackStateChangedBufferingSendsBufferingStartAndUpdates() {

@Test
public void onPlaybackStateChangedEndedSendsOnCompleted() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
eventListener.onPlaybackStateChanged(Player.STATE_ENDED);

verify(mockCallbacks).onCompleted();
Expand All @@ -190,6 +208,7 @@ public void onPlaybackStateChangedEndedSendsOnCompleted() {

@Test
public void onPlaybackStateChangedEndedAfterBufferingSendsBufferingEndAndOnCompleted() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
when(mockExoPlayer.getBufferedPosition()).thenReturn(10L);
eventListener.onPlaybackStateChanged(Player.STATE_BUFFERING);
verify(mockCallbacks).onBufferingStart();
Expand All @@ -204,13 +223,15 @@ public void onPlaybackStateChangedEndedAfterBufferingSendsBufferingEndAndOnCompl

@Test
public void onPlaybackStateChangedIdleDoNothing() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
eventListener.onPlaybackStateChanged(Player.STATE_IDLE);

verifyNoInteractions(mockCallbacks);
}

@Test
public void onPlaybackStateChangedIdleAfterBufferingSendsBufferingEnd() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
when(mockExoPlayer.getBufferedPosition()).thenReturn(10L);
eventListener.onPlaybackStateChanged(Player.STATE_BUFFERING);
verify(mockCallbacks).onBufferingStart();
Expand All @@ -224,6 +245,7 @@ public void onPlaybackStateChangedIdleAfterBufferingSendsBufferingEnd() {

@Test
public void onErrorVideoErrorWhenBufferingInProgressAlsoEndBuffering() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
when(mockExoPlayer.getBufferedPosition()).thenReturn(10L);
eventListener.onPlaybackStateChanged(Player.STATE_BUFFERING);
verify(mockCallbacks).onBufferingStart();
Expand All @@ -237,6 +259,7 @@ public void onErrorVideoErrorWhenBufferingInProgressAlsoEndBuffering() {

@Test
public void onErrorBehindLiveWindowSeekToDefaultAndPrepare() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
eventListener.onPlayerError(
new PlaybackException("SORT_OF_OK", null, PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW));

Expand All @@ -247,6 +270,7 @@ public void onErrorBehindLiveWindowSeekToDefaultAndPrepare() {

@Test
public void onIsPlayingChangedToggled() {
ExoPlayerEventListener eventListener = new ExoPlayerEventListener(mockExoPlayer, mockCallbacks, true);
eventListener.onIsPlayingChanged(true);
verify(mockCallbacks).onIsPlayingStateUpdate(true);

Expand Down
2 changes: 1 addition & 1 deletion packages/video_player/video_player_android/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: video_player_android
description: Android implementation of the video_player plugin.
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
version: 2.7.17
version: 2.7.18

environment:
sdk: ^3.6.0
Expand Down