From 16c2e9e299b73401620ee92e8b742328d212c3ed Mon Sep 17 00:00:00 2001 From: Mohellebi abdessalem Date: Fri, 17 Oct 2025 10:32:40 +0100 Subject: [PATCH 1/2] change file --- .../TextureExoPlayerEventListener.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/texture/TextureExoPlayerEventListener.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/texture/TextureExoPlayerEventListener.java index bcc901b7218..19fbed6680a 100644 --- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/texture/TextureExoPlayerEventListener.java +++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/texture/TextureExoPlayerEventListener.java @@ -4,6 +4,8 @@ package io.flutter.plugins.videoplayer.texture; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.OptIn; import androidx.media3.common.Format; @@ -60,3 +62,71 @@ private int getRotationCorrectionFromFormat(ExoPlayer exoPlayer) { return videoFormat.rotationDegrees; } } + + +//// Copyright 2013 The Flutter Authors +//// 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.texture; +// +//import android.util.Log; +// +//import androidx.annotation.NonNull; +//import androidx.annotation.OptIn; +//import androidx.media3.common.Format; +//import androidx.media3.common.VideoSize; +//import androidx.media3.exoplayer.ExoPlayer; +//import io.flutter.plugins.videoplayer.ExoPlayerEventListener; +//import io.flutter.plugins.videoplayer.VideoPlayerCallbacks; +//import java.util.Objects; +// +//public final class TextureExoPlayerEventListener extends ExoPlayerEventListener { +// private final boolean surfaceProducerHandlesCropAndRotation; +// +// public TextureExoPlayerEventListener( +// @NonNull ExoPlayer exoPlayer, +// @NonNull VideoPlayerCallbacks events, +// boolean surfaceProducerHandlesCropAndRotation) { +// super(exoPlayer, events); +// this.surfaceProducerHandlesCropAndRotation = surfaceProducerHandlesCropAndRotation; +// } +// +// @Override +// protected void sendInitialized() { +// long duration = exoPlayer.getDuration(); +// +// if (duration == androidx.media3.common.C.TIME_UNSET) { +// // Duration not yet available — wait a bit and try again +// new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(this::sendInitialized, 100); +// return; +// } +// +// VideoSize videoSize = exoPlayer.getVideoSize(); +// RotationDegrees rotationCorrection = RotationDegrees.ROTATE_0; +// int width = videoSize.width; +// int height = videoSize.height; +// +// if (width != 0 && height != 0 && !surfaceProducerHandlesCropAndRotation) { +// try { +// int rawVideoFormatRotation = getRotationCorrectionFromFormat(exoPlayer); +// rotationCorrection = RotationDegrees.fromDegrees(rawVideoFormatRotation); +// } catch (IllegalArgumentException e) { +// rotationCorrection = RotationDegrees.ROTATE_0; +// } +// } +// +// Log.v("VideoPlayer", "sendInitialized(): duration=" + duration + " width=" + width + " height=" + height); +// events.onInitialized(width, height, duration, rotationCorrection.getDegrees()); +// } +// +// +// @OptIn(markerClass = androidx.media3.common.util.UnstableApi.class) +// // A video's Format and its rotation degrees are unstable because they are not guaranteed +// // the same implementation across API versions. It is possible that this logic may need +// // revisiting should the implementation change across versions of the Exoplayer API. +// private int getRotationCorrectionFromFormat(ExoPlayer exoPlayer) { +// Format videoFormat = Objects.requireNonNull(exoPlayer.getVideoFormat()); +// return videoFormat.rotationDegrees; +// } +//} From 9331ca61627aa8eec38365dbe91c89ef99b436ea Mon Sep 17 00:00:00 2001 From: Mohellebi abdessalem Date: Fri, 17 Oct 2025 10:33:35 +0100 Subject: [PATCH 2/2] Refactor ExoPlayerEventListener for timeline changes Removed sendInitialized() from onPlaybackStateChanged and handled it in onTimelineChanged. Added timeline handling to check for initialization. --- .../videoplayer/ExoPlayerEventListener.java | 233 +++++++++++++----- 1 file changed, 167 insertions(+), 66 deletions(-) diff --git a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java index 5b5203b39e7..669ab557c69 100644 --- a/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java +++ b/packages/video_player/video_player_android/android/src/main/java/io/flutter/plugins/videoplayer/ExoPlayerEventListener.java @@ -1,3 +1,95 @@ +//// Copyright 2013 The Flutter Authors +//// 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.annotation.NonNull; +//import androidx.media3.common.PlaybackException; +//import androidx.media3.common.Player; +//import androidx.media3.exoplayer.ExoPlayer; +// +//public abstract class ExoPlayerEventListener implements Player.Listener { +// private boolean isInitialized = false; +// protected final ExoPlayer exoPlayer; +// protected final VideoPlayerCallbacks events; +// +// protected enum RotationDegrees { +// ROTATE_0(0), +// ROTATE_90(90), +// ROTATE_180(180), +// ROTATE_270(270); +// +// private final int degrees; +// +// RotationDegrees(int degrees) { +// this.degrees = degrees; +// } +// +// public static RotationDegrees fromDegrees(int degrees) { +// for (RotationDegrees rotationDegrees : RotationDegrees.values()) { +// if (rotationDegrees.degrees == degrees) { +// return rotationDegrees; +// } +// } +// throw new IllegalArgumentException("Invalid rotation degrees specified: " + degrees); +// } +// +// public int getDegrees() { +// return this.degrees; +// } +// } +// +// public ExoPlayerEventListener( +// @NonNull ExoPlayer exoPlayer, @NonNull VideoPlayerCallbacks events) { +// this.exoPlayer = exoPlayer; +// this.events = events; +// } +// +// protected abstract void sendInitialized(); +// +// @Override +// public void onPlaybackStateChanged(final int playbackState) { +// PlatformPlaybackState platformState = PlatformPlaybackState.UNKNOWN; +// switch (playbackState) { +// case Player.STATE_BUFFERING: +// platformState = PlatformPlaybackState.BUFFERING; +// break; +// case Player.STATE_READY: +// platformState = PlatformPlaybackState.READY; +// if (!isInitialized) { +// isInitialized = true; +// sendInitialized(); +// } +// break; +// case Player.STATE_ENDED: +// platformState = PlatformPlaybackState.ENDED; +// break; +// case Player.STATE_IDLE: +// platformState = PlatformPlaybackState.IDLE; +// break; +// } +// events.onPlaybackStateChanged(platformState); +// } +// +// @Override +// public void onPlayerError(@NonNull final PlaybackException error) { +// if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { +// // See +// // https://exoplayer.dev/live-streaming.html#behindlivewindowexception-and-error_code_behind_live_window +// exoPlayer.seekToDefaultPosition(); +// exoPlayer.prepare(); +// } else { +// events.onError("VideoError", "Video player had error " + error, null); +// } +// } +// +// @Override +// public void onIsPlayingChanged(boolean isPlaying) { +// events.onIsPlayingStateUpdate(isPlaying); +// } +//} + // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,85 +99,94 @@ import androidx.annotation.NonNull; import androidx.media3.common.PlaybackException; import androidx.media3.common.Player; +import androidx.media3.common.Timeline; import androidx.media3.exoplayer.ExoPlayer; +import androidx.media3.common.C; + public abstract class ExoPlayerEventListener implements Player.Listener { - private boolean isInitialized = false; - protected final ExoPlayer exoPlayer; - protected final VideoPlayerCallbacks events; + private boolean isInitialized = false; + protected final ExoPlayer exoPlayer; + protected final VideoPlayerCallbacks events; - protected enum RotationDegrees { - ROTATE_0(0), - ROTATE_90(90), - ROTATE_180(180), - ROTATE_270(270); + protected enum RotationDegrees { + ROTATE_0(0), + ROTATE_90(90), + ROTATE_180(180), + ROTATE_270(270); - private final int degrees; + private final int degrees; - RotationDegrees(int degrees) { - this.degrees = degrees; - } + RotationDegrees(int degrees) { + this.degrees = degrees; + } - public static RotationDegrees fromDegrees(int degrees) { - for (RotationDegrees rotationDegrees : RotationDegrees.values()) { - if (rotationDegrees.degrees == degrees) { - return rotationDegrees; + public static RotationDegrees fromDegrees(int degrees) { + for (RotationDegrees rotationDegrees : RotationDegrees.values()) { + if (rotationDegrees.degrees == degrees) { + return rotationDegrees; + } + } + throw new IllegalArgumentException("Invalid rotation degrees specified: " + degrees); } - } - throw new IllegalArgumentException("Invalid rotation degrees specified: " + degrees); + + public int getDegrees() { + return this.degrees; + } + } + + public ExoPlayerEventListener( + @NonNull ExoPlayer exoPlayer, @NonNull VideoPlayerCallbacks events) { + this.exoPlayer = exoPlayer; + this.events = events; } - public int getDegrees() { - return this.degrees; + protected abstract void sendInitialized(); + + @Override + public void onPlaybackStateChanged(final int playbackState) { + PlatformPlaybackState platformState = PlatformPlaybackState.UNKNOWN; + switch (playbackState) { + case Player.STATE_BUFFERING: + platformState = PlatformPlaybackState.BUFFERING; + break; + case Player.STATE_READY: + platformState = PlatformPlaybackState.READY; + // ⚠️ Removed sendInitialized() from here — handled by onTimelineChanged() + break; + case Player.STATE_ENDED: + platformState = PlatformPlaybackState.ENDED; + break; + case Player.STATE_IDLE: + platformState = PlatformPlaybackState.IDLE; + break; + } + events.onPlaybackStateChanged(platformState); } - } - - public ExoPlayerEventListener( - @NonNull ExoPlayer exoPlayer, @NonNull VideoPlayerCallbacks events) { - this.exoPlayer = exoPlayer; - this.events = events; - } - - protected abstract void sendInitialized(); - - @Override - public void onPlaybackStateChanged(final int playbackState) { - PlatformPlaybackState platformState = PlatformPlaybackState.UNKNOWN; - switch (playbackState) { - case Player.STATE_BUFFERING: - platformState = PlatformPlaybackState.BUFFERING; - break; - case Player.STATE_READY: - platformState = PlatformPlaybackState.READY; - if (!isInitialized) { - isInitialized = true; - sendInitialized(); + + @Override + public void onTimelineChanged(@NonNull Timeline timeline, int reason) { + long duration = exoPlayer.getDuration(); + if (!isInitialized && duration != C.TIME_UNSET){ + isInitialized = true; + sendInitialized(); } - break; - case Player.STATE_ENDED: - platformState = PlatformPlaybackState.ENDED; - break; - case Player.STATE_IDLE: - platformState = PlatformPlaybackState.IDLE; - break; } - events.onPlaybackStateChanged(platformState); - } - - @Override - public void onPlayerError(@NonNull final PlaybackException error) { - if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { - // See - // https://exoplayer.dev/live-streaming.html#behindlivewindowexception-and-error_code_behind_live_window - exoPlayer.seekToDefaultPosition(); - exoPlayer.prepare(); - } else { - events.onError("VideoError", "Video player had error " + error, null); + + @Override + public void onPlayerError(@NonNull final PlaybackException error) { + if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) { + // See + // https://exoplayer.dev/live-streaming.html#behindlivewindowexception-and-error_code_behind_live_window + exoPlayer.seekToDefaultPosition(); + exoPlayer.prepare(); + } else { + events.onError("VideoError", "Video player had error " + error, null); + } } - } - @Override - public void onIsPlayingChanged(boolean isPlaying) { - events.onIsPlayingStateUpdate(isPlaying); - } + @Override + public void onIsPlayingChanged(boolean isPlaying) { + events.onIsPlayingStateUpdate(isPlaying); + } }