Skip to content

Commit f61a98a

Browse files
authored
Revert "[video_player] Relands #6456: Uses SurfaceProducer, this time with setCallback for suspend/resume lifecycles" (#7497)
Reverts #6989 Fixes flutter/flutter#154054 , flutter/flutter#154050
1 parent 62b4cb0 commit f61a98a

File tree

6 files changed

+59
-182
lines changed

6 files changed

+59
-182
lines changed

packages/video_player/video_player_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.7.1
2+
3+
* Revert Impeller support.
4+
15
## 2.7.0
26

37
* Re-adds [support for Impeller](https://docs.flutter.dev/release/breaking-changes/android-surface-plugins).

packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerState.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java

Lines changed: 40 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88
import static androidx.media3.common.Player.REPEAT_MODE_OFF;
99

1010
import android.content.Context;
11+
import android.view.Surface;
1112
import androidx.annotation.NonNull;
12-
import androidx.annotation.Nullable;
13-
import androidx.annotation.RestrictTo;
1413
import androidx.annotation.VisibleForTesting;
1514
import androidx.media3.common.AudioAttributes;
1615
import androidx.media3.common.C;
@@ -19,97 +18,60 @@
1918
import androidx.media3.exoplayer.ExoPlayer;
2019
import io.flutter.view.TextureRegistry;
2120

22-
final class VideoPlayer implements TextureRegistry.SurfaceProducer.Callback {
23-
@NonNull private final ExoPlayerProvider exoPlayerProvider;
24-
@NonNull private final MediaItem mediaItem;
25-
@NonNull private final TextureRegistry.SurfaceProducer surfaceProducer;
26-
@NonNull private final VideoPlayerCallbacks videoPlayerEvents;
27-
@NonNull private final VideoPlayerOptions options;
28-
@NonNull private ExoPlayer exoPlayer;
29-
@Nullable private ExoPlayerState savedStateDuring;
21+
final class VideoPlayer {
22+
private ExoPlayer exoPlayer;
23+
private Surface surface;
24+
private final TextureRegistry.SurfaceTextureEntry textureEntry;
25+
private final VideoPlayerCallbacks videoPlayerEvents;
26+
private final VideoPlayerOptions options;
3027

3128
/**
3229
* Creates a video player.
3330
*
3431
* @param context application context.
3532
* @param events event callbacks.
36-
* @param surfaceProducer produces a texture to render to.
33+
* @param textureEntry texture to render to.
3734
* @param asset asset to play.
3835
* @param options options for playback.
3936
* @return a video player instance.
4037
*/
4138
@NonNull
4239
static VideoPlayer create(
43-
@NonNull Context context,
44-
@NonNull VideoPlayerCallbacks events,
45-
@NonNull TextureRegistry.SurfaceProducer surfaceProducer,
46-
@NonNull VideoAsset asset,
47-
@NonNull VideoPlayerOptions options) {
48-
return new VideoPlayer(
49-
() -> {
50-
ExoPlayer.Builder builder =
51-
new ExoPlayer.Builder(context)
52-
.setMediaSourceFactory(asset.getMediaSourceFactory(context));
53-
return builder.build();
54-
},
55-
events,
56-
surfaceProducer,
57-
asset.getMediaItem(),
58-
options);
59-
}
60-
61-
/** A closure-compatible signature since {@link java.util.function.Supplier} is API level 24. */
62-
interface ExoPlayerProvider {
63-
/**
64-
* Returns a new {@link ExoPlayer}.
65-
*
66-
* @return new instance.
67-
*/
68-
ExoPlayer get();
40+
Context context,
41+
VideoPlayerCallbacks events,
42+
TextureRegistry.SurfaceTextureEntry textureEntry,
43+
VideoAsset asset,
44+
VideoPlayerOptions options) {
45+
ExoPlayer.Builder builder =
46+
new ExoPlayer.Builder(context).setMediaSourceFactory(asset.getMediaSourceFactory(context));
47+
return new VideoPlayer(builder, events, textureEntry, asset.getMediaItem(), options);
6948
}
7049

7150
@VisibleForTesting
7251
VideoPlayer(
73-
@NonNull ExoPlayerProvider exoPlayerProvider,
74-
@NonNull VideoPlayerCallbacks events,
75-
@NonNull TextureRegistry.SurfaceProducer surfaceProducer,
76-
@NonNull MediaItem mediaItem,
77-
@NonNull VideoPlayerOptions options) {
78-
this.exoPlayerProvider = exoPlayerProvider;
52+
ExoPlayer.Builder builder,
53+
VideoPlayerCallbacks events,
54+
TextureRegistry.SurfaceTextureEntry textureEntry,
55+
MediaItem mediaItem,
56+
VideoPlayerOptions options) {
7957
this.videoPlayerEvents = events;
80-
this.surfaceProducer = surfaceProducer;
81-
this.mediaItem = mediaItem;
58+
this.textureEntry = textureEntry;
8259
this.options = options;
83-
this.exoPlayer = createVideoPlayer();
84-
surfaceProducer.setCallback(this);
85-
}
8660

87-
@RestrictTo(RestrictTo.Scope.LIBRARY)
88-
public void onSurfaceCreated() {
89-
exoPlayer = createVideoPlayer();
90-
if (savedStateDuring != null) {
91-
savedStateDuring.restore(exoPlayer);
92-
savedStateDuring = null;
93-
}
94-
}
61+
ExoPlayer exoPlayer = builder.build();
62+
exoPlayer.setMediaItem(mediaItem);
63+
exoPlayer.prepare();
9564

96-
@RestrictTo(RestrictTo.Scope.LIBRARY)
97-
public void onSurfaceDestroyed() {
98-
exoPlayer.stop();
99-
savedStateDuring = ExoPlayerState.save(exoPlayer);
100-
exoPlayer.release();
65+
setUpVideoPlayer(exoPlayer);
10166
}
10267

103-
private ExoPlayer createVideoPlayer() {
104-
ExoPlayer exoPlayer = exoPlayerProvider.get();
105-
exoPlayer.setMediaItem(mediaItem);
106-
exoPlayer.prepare();
68+
private void setUpVideoPlayer(ExoPlayer exoPlayer) {
69+
this.exoPlayer = exoPlayer;
10770

108-
exoPlayer.setVideoSurface(surfaceProducer.getSurface());
109-
exoPlayer.addListener(new ExoPlayerEventListener(exoPlayer, videoPlayerEvents));
71+
surface = new Surface(textureEntry.surfaceTexture());
72+
exoPlayer.setVideoSurface(surface);
11073
setAudioAttributes(exoPlayer, options.mixWithOthers);
111-
112-
return exoPlayer;
74+
exoPlayer.addListener(new ExoPlayerEventListener(exoPlayer, videoPlayerEvents));
11375
}
11476

11577
void sendBufferingUpdate() {
@@ -123,11 +85,11 @@ private static void setAudioAttributes(ExoPlayer exoPlayer, boolean isMixMode) {
12385
}
12486

12587
void play() {
126-
exoPlayer.play();
88+
exoPlayer.setPlayWhenReady(true);
12789
}
12890

12991
void pause() {
130-
exoPlayer.pause();
92+
exoPlayer.setPlayWhenReady(false);
13193
}
13294

13395
void setLooping(boolean value) {
@@ -156,7 +118,12 @@ long getPosition() {
156118
}
157119

158120
void dispose() {
159-
surfaceProducer.release();
160-
exoPlayer.release();
121+
textureEntry.release();
122+
if (surface != null) {
123+
surface.release();
124+
}
125+
if (exoPlayer != null) {
126+
exoPlayer.release();
127+
}
161128
}
162129
}

packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import io.flutter.view.TextureRegistry;
2525
import java.security.KeyManagementException;
2626
import java.security.NoSuchAlgorithmException;
27+
import java.util.Map;
2728
import javax.net.ssl.HttpsURLConnection;
2829

2930
/** Android platform implementation of the VideoPlayerPlugin. */
@@ -93,7 +94,8 @@ public void initialize() {
9394
}
9495

9596
public @NonNull TextureMessage create(@NonNull CreateMessage arg) {
96-
TextureRegistry.SurfaceProducer handle = flutterState.textureRegistry.createSurfaceProducer();
97+
TextureRegistry.SurfaceTextureEntry handle =
98+
flutterState.textureRegistry.createSurfaceTexture();
9799
EventChannel eventChannel =
98100
new EventChannel(
99101
flutterState.binaryMessenger, "flutter.io/videoPlayer/videoEvents" + handle.id());
@@ -111,6 +113,7 @@ public void initialize() {
111113
} else if (arg.getUri().startsWith("rtsp://")) {
112114
videoAsset = VideoAsset.fromRtspUrl(arg.getUri());
113115
} else {
116+
Map<String, String> httpHeaders = arg.getHttpHeaders();
114117
VideoAsset.StreamingFormat streamingFormat = VideoAsset.StreamingFormat.UNKNOWN;
115118
String formatHint = arg.getFormatHint();
116119
if (formatHint != null) {

packages/video_player/video_player_android/android/src/test/java/io/flutter/plugins/videoplayer/VideoPlayerTest.java

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import static org.mockito.ArgumentMatchers.any;
99
import static org.mockito.Mockito.*;
1010

11-
import android.view.Surface;
11+
import android.graphics.SurfaceTexture;
1212
import androidx.media3.common.AudioAttributes;
1313
import androidx.media3.common.C;
1414
import androidx.media3.common.PlaybackParameters;
@@ -44,17 +44,18 @@ public final class VideoPlayerTest {
4444
private FakeVideoAsset fakeVideoAsset;
4545

4646
@Mock private VideoPlayerCallbacks mockEvents;
47-
@Mock private TextureRegistry.SurfaceProducer mockProducer;
47+
@Mock private TextureRegistry.SurfaceTextureEntry mockTexture;
48+
@Mock private ExoPlayer.Builder mockBuilder;
4849
@Mock private ExoPlayer mockExoPlayer;
4950
@Captor private ArgumentCaptor<AudioAttributes> attributesCaptor;
50-
@Captor private ArgumentCaptor<TextureRegistry.SurfaceProducer.Callback> callbackCaptor;
5151

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

5454
@Before
5555
public void setUp() {
5656
fakeVideoAsset = new FakeVideoAsset(FAKE_ASSET_URL);
57-
when(mockProducer.getSurface()).thenReturn(mock(Surface.class));
57+
when(mockBuilder.build()).thenReturn(mockExoPlayer);
58+
when(mockTexture.surfaceTexture()).thenReturn(mock(SurfaceTexture.class));
5859
}
5960

6061
private VideoPlayer createVideoPlayer() {
@@ -63,7 +64,7 @@ private VideoPlayer createVideoPlayer() {
6364

6465
private VideoPlayer createVideoPlayer(VideoPlayerOptions options) {
6566
return new VideoPlayer(
66-
() -> mockExoPlayer, mockEvents, mockProducer, fakeVideoAsset.getMediaItem(), options);
67+
mockBuilder, mockEvents, mockTexture, fakeVideoAsset.getMediaItem(), options);
6768
}
6869

6970
@Test
@@ -72,7 +73,7 @@ public void loadsAndPreparesProvidedMediaEnablesAudioFocusByDefault() {
7273

7374
verify(mockExoPlayer).setMediaItem(fakeVideoAsset.getMediaItem());
7475
verify(mockExoPlayer).prepare();
75-
verify(mockProducer).getSurface();
76+
verify(mockTexture).surfaceTexture();
7677
verify(mockExoPlayer).setVideoSurface(any());
7778

7879
verify(mockExoPlayer).setAudioAttributes(attributesCaptor.capture(), eq(true));
@@ -99,10 +100,10 @@ public void playsAndPausesProvidedMedia() {
99100
VideoPlayer videoPlayer = createVideoPlayer();
100101

101102
videoPlayer.play();
102-
verify(mockExoPlayer).play();
103+
verify(mockExoPlayer).setPlayWhenReady(true);
103104

104105
videoPlayer.pause();
105-
verify(mockExoPlayer).pause();
106+
verify(mockExoPlayer).setPlayWhenReady(false);
106107

107108
videoPlayer.dispose();
108109
}
@@ -168,41 +169,12 @@ public void seekAndGetPosition() {
168169
assertEquals(20L, videoPlayer.getPosition());
169170
}
170171

171-
@Test
172-
public void onSurfaceProducerDestroyedAndRecreatedReleasesAndThenRecreatesAndResumesPlayer() {
173-
VideoPlayer videoPlayer = createVideoPlayer();
174-
175-
verify(mockProducer).setCallback(callbackCaptor.capture());
176-
verify(mockExoPlayer, never()).release();
177-
178-
when(mockExoPlayer.getCurrentPosition()).thenReturn(10L);
179-
when(mockExoPlayer.getRepeatMode()).thenReturn(Player.REPEAT_MODE_ALL);
180-
when(mockExoPlayer.getVolume()).thenReturn(0.5f);
181-
when(mockExoPlayer.getPlaybackParameters()).thenReturn(new PlaybackParameters(2.5f));
182-
183-
TextureRegistry.SurfaceProducer.Callback producerLifecycle = callbackCaptor.getValue();
184-
producerLifecycle.onSurfaceDestroyed();
185-
186-
verify(mockExoPlayer).release();
187-
188-
// Create a new mock exo player so that we get a new instance.
189-
mockExoPlayer = mock(ExoPlayer.class);
190-
producerLifecycle.onSurfaceCreated();
191-
192-
verify(mockExoPlayer).seekTo(10L);
193-
verify(mockExoPlayer).setRepeatMode(Player.REPEAT_MODE_ALL);
194-
verify(mockExoPlayer).setVolume(0.5f);
195-
verify(mockExoPlayer).setPlaybackParameters(new PlaybackParameters(2.5f));
196-
197-
videoPlayer.dispose();
198-
}
199-
200172
@Test
201173
public void disposeReleasesTextureAndPlayer() {
202174
VideoPlayer videoPlayer = createVideoPlayer();
203175
videoPlayer.dispose();
204176

205-
verify(mockProducer).release();
177+
verify(mockTexture).release();
206178
verify(mockExoPlayer).release();
207179
}
208180
}

packages/video_player/video_player_android/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: video_player_android
22
description: Android implementation of the video_player plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22
5-
version: 2.7.0
5+
version: 2.7.1
66

77
environment:
88
sdk: ^3.4.0

0 commit comments

Comments
 (0)