-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Migrate video_player/android
from SurfaceTexture
->SurfaceProducer
.
#6456
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
Changes from all commits
77ccaea
54b24cb
6866d44
d3eacba
782ee27
3ae8f75
89296f6
c0c6b9b
8b46bd6
9b378ae
54a0738
713cbc7
6664ecd
76ec4bd
076d53b
a9e9f2a
90eb1d5
f9cf7d4
5e3289c
ee2a30d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,6 @@ | |
|
||
import android.content.Context; | ||
import android.net.Uri; | ||
import android.view.Surface; | ||
import androidx.annotation.NonNull; | ||
import androidx.annotation.VisibleForTesting; | ||
import com.google.android.exoplayer2.C; | ||
|
@@ -48,32 +47,37 @@ final class VideoPlayer { | |
|
||
private ExoPlayer exoPlayer; | ||
|
||
private Surface surface; | ||
|
||
private final TextureRegistry.SurfaceTextureEntry textureEntry; | ||
private TextureRegistry.SurfaceProducer surfaceProducer; | ||
|
||
private QueuingEventSink eventSink; | ||
|
||
private final EventChannel eventChannel; | ||
|
||
private static final String USER_AGENT = "User-Agent"; | ||
|
||
private MediaSource mediaSource; | ||
|
||
@VisibleForTesting boolean isInitialized = false; | ||
|
||
// State that must be reset when the surface is re-created. | ||
private final VideoPlayerOptions options; | ||
private long restoreVideoLocation = 0; | ||
private int restoreRepeatMode = 0; | ||
private float restoreVolume = 0; | ||
private PlaybackParameters restorePlaybackParameters; | ||
|
||
private DefaultHttpDataSource.Factory httpDataSourceFactory = new DefaultHttpDataSource.Factory(); | ||
|
||
VideoPlayer( | ||
Context context, | ||
EventChannel eventChannel, | ||
TextureRegistry.SurfaceTextureEntry textureEntry, | ||
TextureRegistry.SurfaceProducer surfaceProducer, | ||
String dataSource, | ||
String formatHint, | ||
@NonNull Map<String, String> httpHeaders, | ||
VideoPlayerOptions options) { | ||
this.eventChannel = eventChannel; | ||
this.textureEntry = textureEntry; | ||
this.surfaceProducer = surfaceProducer; | ||
this.options = options; | ||
|
||
ExoPlayer exoPlayer = new ExoPlayer.Builder(context).build(); | ||
|
@@ -83,7 +87,7 @@ final class VideoPlayer { | |
DataSource.Factory dataSourceFactory = | ||
new DefaultDataSource.Factory(context, httpDataSourceFactory); | ||
|
||
MediaSource mediaSource = buildMediaSource(uri, dataSourceFactory, formatHint); | ||
mediaSource = buildMediaSource(uri, dataSourceFactory, formatHint); | ||
|
||
exoPlayer.setMediaSource(mediaSource); | ||
exoPlayer.prepare(); | ||
|
@@ -96,12 +100,12 @@ final class VideoPlayer { | |
VideoPlayer( | ||
ExoPlayer exoPlayer, | ||
EventChannel eventChannel, | ||
TextureRegistry.SurfaceTextureEntry textureEntry, | ||
TextureRegistry.SurfaceProducer surfaceProducer, | ||
VideoPlayerOptions options, | ||
QueuingEventSink eventSink, | ||
DefaultHttpDataSource.Factory httpDataSourceFactory) { | ||
this.eventChannel = eventChannel; | ||
this.textureEntry = textureEntry; | ||
this.surfaceProducer = surfaceProducer; | ||
this.options = options; | ||
this.httpDataSourceFactory = httpDataSourceFactory; | ||
|
||
|
@@ -169,6 +173,40 @@ private MediaSource buildMediaSource( | |
} | ||
} | ||
|
||
public void recreateSurface(Context context) { | ||
ExoPlayer exoPlayer = new ExoPlayer.Builder(context).build(); | ||
|
||
exoPlayer.setMediaSource(mediaSource); | ||
exoPlayer.prepare(); | ||
|
||
setUpVideoPlayer(exoPlayer, new QueuingEventSink()); | ||
exoPlayer.setVideoSurface(surfaceProducer.getSurface()); | ||
exoPlayer.seekTo(restoreVideoLocation); | ||
exoPlayer.setRepeatMode(restoreRepeatMode); | ||
exoPlayer.setVolume(restoreVolume); | ||
if (restorePlaybackParameters != null) { | ||
exoPlayer.setPlaybackParameters(restorePlaybackParameters); | ||
} | ||
} | ||
|
||
public void pauseSurface() { | ||
if (!isInitialized) { | ||
return; | ||
} | ||
restoreVideoLocation = exoPlayer.getCurrentPosition(); | ||
restoreRepeatMode = exoPlayer.getRepeatMode(); | ||
restoreVolume = exoPlayer.getVolume(); | ||
restorePlaybackParameters = exoPlayer.getPlaybackParameters(); | ||
eventChannel.setStreamHandler(null); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried just calling exoPlayer.setSurface again with a new surface, however the old surface being disposed seems to break some internal state, so I have to recreate the exo instance. This might imply some loss of state. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree but I'm not sure because I'm not deeply familiar with ExoPlayer. Does the case where a video is playing and then the app is moved to the background and brought back get impacted by this, i.e. the video is no longer playing from the point it was stopped? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me investigate this . There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I looked at this and it seems like the video state is reset. I'm going to see if there is a way to restore it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added logic to restore all of the visible exo state when re-creating exo player. |
||
if (isInitialized) { | ||
exoPlayer.stop(); | ||
} | ||
if (exoPlayer != null) { | ||
exoPlayer.release(); | ||
} | ||
isInitialized = false; | ||
} | ||
|
||
private void setUpVideoPlayer(ExoPlayer exoPlayer, QueuingEventSink eventSink) { | ||
this.exoPlayer = exoPlayer; | ||
this.eventSink = eventSink; | ||
|
@@ -186,8 +224,7 @@ public void onCancel(Object o) { | |
} | ||
}); | ||
|
||
surface = new Surface(textureEntry.surfaceTexture()); | ||
exoPlayer.setVideoSurface(surface); | ||
exoPlayer.setVideoSurface(surfaceProducer.getSurface()); | ||
setAudioAttributes(exoPlayer, options.mixWithOthers); | ||
|
||
exoPlayer.addListener( | ||
|
@@ -334,11 +371,8 @@ void dispose() { | |
if (isInitialized) { | ||
exoPlayer.stop(); | ||
} | ||
textureEntry.release(); | ||
surfaceProducer.release(); | ||
eventChannel.setStreamHandler(null); | ||
if (surface != null) { | ||
surface.release(); | ||
} | ||
if (exoPlayer != null) { | ||
exoPlayer.release(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't need to cache surface.