diff --git a/packages/video_player/video_player_android/CHANGELOG.md b/packages/video_player/video_player_android/CHANGELOG.md index 721c08cdbf55..e88f3385c874 100644 --- a/packages/video_player/video_player_android/CHANGELOG.md +++ b/packages/video_player/video_player_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.7.1 + +* Revert Impeller support. + ## 2.7.0 * Re-adds [support for Impeller](https://docs.flutter.dev/release/breaking-changes/android-surface-plugins). diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerState.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerState.java deleted file mode 100644 index cd55b54c1247..000000000000 --- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerState.java +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package io.flutter.plugins.videoplayer; - -import androidx.media3.common.PlaybackParameters; -import androidx.media3.exoplayer.ExoPlayer; - -/** - * Internal state representing an {@link ExoPlayer} instance at a snapshot in time. - * - *
During the Android application lifecycle, the underlying {@link android.view.Surface} being - * rendered to by the player can be destroyed when the application is in the background and memory - * is reclaimed. Upon resume, the player will need to be recreated, but start again at the - * previous point (and settings). - */ -final class ExoPlayerState { - /** - * Saves a representation of the current state of the player at the current point in time. - * - *
The inverse of this operation is {@link #restore(ExoPlayer)}. - * - * @param exoPlayer the active player instance. - * @return an opaque object representing the state. - */ - static ExoPlayerState save(ExoPlayer exoPlayer) { - return new ExoPlayerState( - /*position=*/ exoPlayer.getCurrentPosition(), - /*repeatMode=*/ exoPlayer.getRepeatMode(), - /*volume=*/ exoPlayer.getVolume(), - /*playbackParameters=*/ exoPlayer.getPlaybackParameters()); - } - - private ExoPlayerState( - long position, int repeatMode, float volume, PlaybackParameters playbackParameters) { - this.position = position; - this.repeatMode = repeatMode; - this.volume = volume; - this.playbackParameters = playbackParameters; - } - - /** Previous value of {@link ExoPlayer#getCurrentPosition()}. */ - private final long position; - - /** Previous value of {@link ExoPlayer#getRepeatMode()}. */ - private final int repeatMode; - - /** Previous value of {@link ExoPlayer#getVolume()}. */ - private final float volume; - - /** Previous value of {@link ExoPlayer#getPlaybackParameters()}. */ - private final PlaybackParameters playbackParameters; - - /** - * Restores the captured state onto the provided player. - * - *
This will typically be done after creating a new player, setting up a media source, and
- * listening to events.
- *
- * @param exoPlayer the new player instance to reflect the state back to.
- */
- void restore(ExoPlayer exoPlayer) {
- exoPlayer.seekTo(position);
- exoPlayer.setRepeatMode(repeatMode);
- exoPlayer.setVolume(volume);
- exoPlayer.setPlaybackParameters(playbackParameters);
- }
-}
diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java
index 8b12c8a2a0b8..ab20b30f42d0 100644
--- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java
+++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayer.java
@@ -8,9 +8,8 @@
import static androidx.media3.common.Player.REPEAT_MODE_OFF;
import android.content.Context;
+import android.view.Surface;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C;
@@ -19,97 +18,60 @@
import androidx.media3.exoplayer.ExoPlayer;
import io.flutter.view.TextureRegistry;
-final class VideoPlayer implements TextureRegistry.SurfaceProducer.Callback {
- @NonNull private final ExoPlayerProvider exoPlayerProvider;
- @NonNull private final MediaItem mediaItem;
- @NonNull private final TextureRegistry.SurfaceProducer surfaceProducer;
- @NonNull private final VideoPlayerCallbacks videoPlayerEvents;
- @NonNull private final VideoPlayerOptions options;
- @NonNull private ExoPlayer exoPlayer;
- @Nullable private ExoPlayerState savedStateDuring;
+final class VideoPlayer {
+ private ExoPlayer exoPlayer;
+ private Surface surface;
+ private final TextureRegistry.SurfaceTextureEntry textureEntry;
+ private final VideoPlayerCallbacks videoPlayerEvents;
+ private final VideoPlayerOptions options;
/**
* Creates a video player.
*
* @param context application context.
* @param events event callbacks.
- * @param surfaceProducer produces a texture to render to.
+ * @param textureEntry texture to render to.
* @param asset asset to play.
* @param options options for playback.
* @return a video player instance.
*/
@NonNull
static VideoPlayer create(
- @NonNull Context context,
- @NonNull VideoPlayerCallbacks events,
- @NonNull TextureRegistry.SurfaceProducer surfaceProducer,
- @NonNull VideoAsset asset,
- @NonNull VideoPlayerOptions options) {
- return new VideoPlayer(
- () -> {
- ExoPlayer.Builder builder =
- new ExoPlayer.Builder(context)
- .setMediaSourceFactory(asset.getMediaSourceFactory(context));
- return builder.build();
- },
- events,
- surfaceProducer,
- asset.getMediaItem(),
- options);
- }
-
- /** A closure-compatible signature since {@link java.util.function.Supplier} is API level 24. */
- interface ExoPlayerProvider {
- /**
- * Returns a new {@link ExoPlayer}.
- *
- * @return new instance.
- */
- ExoPlayer get();
+ Context context,
+ VideoPlayerCallbacks events,
+ TextureRegistry.SurfaceTextureEntry textureEntry,
+ VideoAsset asset,
+ VideoPlayerOptions options) {
+ ExoPlayer.Builder builder =
+ new ExoPlayer.Builder(context).setMediaSourceFactory(asset.getMediaSourceFactory(context));
+ return new VideoPlayer(builder, events, textureEntry, asset.getMediaItem(), options);
}
@VisibleForTesting
VideoPlayer(
- @NonNull ExoPlayerProvider exoPlayerProvider,
- @NonNull VideoPlayerCallbacks events,
- @NonNull TextureRegistry.SurfaceProducer surfaceProducer,
- @NonNull MediaItem mediaItem,
- @NonNull VideoPlayerOptions options) {
- this.exoPlayerProvider = exoPlayerProvider;
+ ExoPlayer.Builder builder,
+ VideoPlayerCallbacks events,
+ TextureRegistry.SurfaceTextureEntry textureEntry,
+ MediaItem mediaItem,
+ VideoPlayerOptions options) {
this.videoPlayerEvents = events;
- this.surfaceProducer = surfaceProducer;
- this.mediaItem = mediaItem;
+ this.textureEntry = textureEntry;
this.options = options;
- this.exoPlayer = createVideoPlayer();
- surfaceProducer.setCallback(this);
- }
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- public void onSurfaceCreated() {
- exoPlayer = createVideoPlayer();
- if (savedStateDuring != null) {
- savedStateDuring.restore(exoPlayer);
- savedStateDuring = null;
- }
- }
+ ExoPlayer exoPlayer = builder.build();
+ exoPlayer.setMediaItem(mediaItem);
+ exoPlayer.prepare();
- @RestrictTo(RestrictTo.Scope.LIBRARY)
- public void onSurfaceDestroyed() {
- exoPlayer.stop();
- savedStateDuring = ExoPlayerState.save(exoPlayer);
- exoPlayer.release();
+ setUpVideoPlayer(exoPlayer);
}
- private ExoPlayer createVideoPlayer() {
- ExoPlayer exoPlayer = exoPlayerProvider.get();
- exoPlayer.setMediaItem(mediaItem);
- exoPlayer.prepare();
+ private void setUpVideoPlayer(ExoPlayer exoPlayer) {
+ this.exoPlayer = exoPlayer;
- exoPlayer.setVideoSurface(surfaceProducer.getSurface());
- exoPlayer.addListener(new ExoPlayerEventListener(exoPlayer, videoPlayerEvents));
+ surface = new Surface(textureEntry.surfaceTexture());
+ exoPlayer.setVideoSurface(surface);
setAudioAttributes(exoPlayer, options.mixWithOthers);
-
- return exoPlayer;
+ exoPlayer.addListener(new ExoPlayerEventListener(exoPlayer, videoPlayerEvents));
}
void sendBufferingUpdate() {
@@ -123,11 +85,11 @@ private static void setAudioAttributes(ExoPlayer exoPlayer, boolean isMixMode) {
}
void play() {
- exoPlayer.play();
+ exoPlayer.setPlayWhenReady(true);
}
void pause() {
- exoPlayer.pause();
+ exoPlayer.setPlayWhenReady(false);
}
void setLooping(boolean value) {
@@ -156,7 +118,12 @@ long getPosition() {
}
void dispose() {
- surfaceProducer.release();
- exoPlayer.release();
+ textureEntry.release();
+ if (surface != null) {
+ surface.release();
+ }
+ if (exoPlayer != null) {
+ exoPlayer.release();
+ }
}
}
diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java
index 2a9f5cc38579..af13c5395512 100644
--- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java
+++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/VideoPlayerPlugin.java
@@ -24,6 +24,7 @@
import io.flutter.view.TextureRegistry;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
+import java.util.Map;
import javax.net.ssl.HttpsURLConnection;
/** Android platform implementation of the VideoPlayerPlugin. */
@@ -93,7 +94,8 @@ public void initialize() {
}
public @NonNull TextureMessage create(@NonNull CreateMessage arg) {
- TextureRegistry.SurfaceProducer handle = flutterState.textureRegistry.createSurfaceProducer();
+ TextureRegistry.SurfaceTextureEntry handle =
+ flutterState.textureRegistry.createSurfaceTexture();
EventChannel eventChannel =
new EventChannel(
flutterState.binaryMessenger, "flutter.io/videoPlayer/videoEvents" + handle.id());
@@ -111,6 +113,7 @@ public void initialize() {
} else if (arg.getUri().startsWith("rtsp://")) {
videoAsset = VideoAsset.fromRtspUrl(arg.getUri());
} else {
+ Map