Skip to content

[video_player_android] Add video track selection support#11475

Open
nateshmbhat wants to merge 1 commit intoflutter:mainfrom
nateshmbhat:breakout/video-track-android
Open

[video_player_android] Add video track selection support#11475
nateshmbhat wants to merge 1 commit intoflutter:mainfrom
nateshmbhat:breakout/video-track-android

Conversation

@nateshmbhat
Copy link
Copy Markdown
Contributor

Summary

Android breakout PR for #10688.

  • Implements getVideoTracks() and selectVideoTrack() methods using ExoPlayer's TrackSelectionOverride
  • Adds onVideoTrackChanged event callback for track change notifications
  • Adds comprehensive Java and Dart unit tests

Dependency Chain

This PR is second in a series of breakout PRs:

  1. video_player_platform_interface ([video_player_platform_interface] Add video track selection support #11474) - pending
  2. video_player_android (this PR)
  3. video_player_avfoundation (pending)
  4. video_player + video_player_web (pending - original PR [video_player] : Add video track selection support for Android and iOS #10688 updated)

Note: This PR depends on video_player_platform_interface 6.7.0 being published first.

Test Plan

  • Java unit tests for getVideoTracks() and selectVideoTrack() in VideoPlayerTest.java
  • Java unit tests for onVideoTrackChanged callback in VideoPlayerEventCallbacksTest.java
  • Dart unit tests for AndroidVideoPlayer overrides

Implements getVideoTracks() and selectVideoTrack() methods for video
track (quality) selection using ExoPlayer.

Android breakout PR for flutter#10688.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces video track selection capabilities to the Android video player plugin. Key changes include adding getVideoTracks(), selectVideoTrack(), and enableAutoVideoQuality() methods to the VideoPlayerInstanceApi and their implementations in VideoPlayer.java and android_video_player.dart. A workaround is implemented in selectVideoTrack to handle video dimension changes by temporarily disabling and re-enabling the video track type to force a renderer reset. New Pigeon messages and data structures are introduced to support video track information exchange, and ExoPlayerEventListener is updated to notify about video track changes. Comprehensive unit tests for the new video track functionalities have also been added. The review comment points out a potential crash risk in the postDelayed workaround within VideoPlayer.java if the player is disposed during the 150ms delay, as the current trackSelector == null guard is ineffective. It recommends using a cancellable callback mechanism or an isDisposed flag for robust handling.

Comment on lines +410 to +431
new android.os.Handler(android.os.Looper.getMainLooper())
.postDelayed(
() -> {
// Guard against player disposal during the delay
if (trackSelector == null) {
return;
}

trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setTrackTypeDisabled(C.TRACK_TYPE_VIDEO, false)
.setOverrideForType(override)
.build());

// Restore playback state
exoPlayer.seekTo(currentPosition);
if (wasPlaying) {
exoPlayer.play();
}
},
150);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The postDelayed workaround for dimension changes introduces a potential crash risk. If the VideoPlayer is disposed (and the ExoPlayer released) during the 150ms delay, the calls to exoPlayer.seekTo() and exoPlayer.play() inside the delayed callback will throw an IllegalStateException because the player has been released.

The current guard if (trackSelector == null) (line 414) is likely ineffective because trackSelector is a final field in this class and is not nullified during the dispose() call in the current implementation of this plugin.

Recommendation:
Use a mechanism to cancel the pending callback or a robust way to check if the player has been disposed. For example, you could use a member Handler and call handler.removeCallbacksAndMessages(null) in dispose(), or maintain an isDisposed boolean flag that is set to true in dispose() and checked at the beginning of the delayed callback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant