Fixes MPV crash when playing next up (#772)

## Description
Ensure that MPV is always destroyed before being initialized again.
Also, now creating a new player is only done when switching backends
which means faster, more efficient playing the next up.

### Related issues
Fixes #766
This commit is contained in:
Ray 2026-01-25 21:38:41 -05:00 committed by GitHub
parent 7b8f5c3e63
commit 03871579f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 29 additions and 28 deletions

View file

@ -219,18 +219,22 @@ class PlaybackViewModel
PlayerBackend.PREFER_MPV -> if (isHdr) PlayerBackend.EXO_PLAYER else PlayerBackend.MPV PlayerBackend.PREFER_MPV -> if (isHdr) PlayerBackend.EXO_PLAYER else PlayerBackend.MPV
} }
Timber.i("Selected backend: %s", playerBackend) Timber.d("Selected backend: %s", playerBackend)
withContext(Dispatchers.Main) { if (currentPlayer.value?.backend != playerBackend) {
disconnectPlayer() Timber.i("Switching player backend to %s", playerBackend)
} withContext(Dispatchers.Main) {
disconnectPlayer()
}
player = player =
playerFactory.createVideoPlayer( playerFactory.createVideoPlayer(
playerBackend, playerBackend,
preferences.appPreferences.playbackPreferences, preferences.appPreferences.playbackPreferences,
) )
currentPlayer.update { currentPlayer.update {
PlayerState(player, playerBackend) PlayerState(player, playerBackend)
}
configurePlayer()
} }
} }
@ -429,7 +433,6 @@ class PlaybackViewModel
// Create the correct player for the media // Create the correct player for the media
createPlayer(videoStream?.hdr == true) createPlayer(videoStream?.hdr == true)
configurePlayer()
val subtitleStreams = val subtitleStreams =
mediaSource.mediaStreams mediaSource.mediaStreams

View file

@ -39,17 +39,9 @@ object MPVLib {
external fun create(appctx: Context) external fun create(appctx: Context)
fun initialize() { external fun init()
synchronized(this) { init() }
}
private external fun init() external fun destroy()
fun tearDown() {
synchronized(this) { destroy() }
}
private external fun destroy()
external fun attachSurface(surface: Surface) external fun attachSurface(surface: Surface)

View file

@ -74,6 +74,8 @@ class MpvPlayer(
SurfaceHolder.Callback { SurfaceHolder.Callback {
companion object { companion object {
private const val DEBUG = false private const val DEBUG = false
private val initLock = Any()
} }
private var surface: Surface? = null private var surface: Surface? = null
@ -131,7 +133,7 @@ class MpvPlayer(
MPVLib.setOptionString("demuxer-max-back-bytes", "${cacheMegs * 1024 * 1024}") MPVLib.setOptionString("demuxer-max-back-bytes", "${cacheMegs * 1024 * 1024}")
Timber.v("Initializing MPVLib") Timber.v("Initializing MPVLib")
MPVLib.initialize() MPVLib.init()
MPVLib.setOptionString("force-window", "no") MPVLib.setOptionString("force-window", "no")
MPVLib.setOptionString("idle", "yes") MPVLib.setOptionString("idle", "yes")
@ -1086,14 +1088,18 @@ class MpvPlayer(
} }
MpvCommand.INITIALIZE -> { MpvCommand.INITIALIZE -> {
init() synchronized(initLock) {
init()
}
} }
MpvCommand.DESTROY -> { MpvCommand.DESTROY -> {
clearVideoSurfaceView(null) synchronized(initLock) {
MPVLib.removeLogObserver(mpvLogger) MPVLib.setPropertyBoolean("pause", true)
MPVLib.tearDown() MPVLib.removeLogObserver(mpvLogger)
Timber.d("MPVLib destroyed") MPVLib.destroy()
Timber.d("MPVLib destroyed")
}
} }
} }
} }