diff --git a/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt b/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt index 9a5ad6385..52a451ea1 100644 --- a/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt +++ b/modules/mpv-player/android/src/main/java/expo/modules/mpvplayer/MPVLayerRenderer.kt @@ -125,6 +125,14 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { private var currentUrl: String? = null private var currentHeaders: Map? = null private var pendingExternalSubtitles: List = emptyList() + // Persistent record of the external subtitle URLs attached to the + // current item. pendingExternalSubtitles above is a one-shot staging + // list: load() fills it and the FILE_LOADED handler drains it via + // sub-add, so it is always empty by the time a resume-recovery reload + // runs. This copy survives that drain so recoverVideoOutput() can hand + // the same sidecar URLs back to load() and the tracks re-attach after + // the decoder reset. + private var activeExternalSubtitles: List = emptyList() private var initialSubtitleId: Int? = null private var initialAudioId: Int? = null @@ -159,13 +167,6 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { this.mpv = mpv mpv.addObserver(this) - // Resolved once — TV gets the memory-pressure customizations - // (SCUDO_OPTIONS, hwdec/profile, demuxer-seekable-cache, larger - // audio-buffer) that would be counterproductive on higher-RAM - // mobile devices. Demuxer cache sizes are NOT included here — - // those come from user settings via load(). - val isTV = isTvDevice() - // mpv config directory — used by the config-dir option below and // as XDG_CONFIG_HOME for fontconfig. val mpvDir = File(context.getExternalFilesDir(null) ?: context.filesDir, "mpv") @@ -219,7 +220,7 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { // - Real phone: `mediacodec-copy` (broadest compatibility). when { isEmulator() -> mpv?.setOptionString("hwdec", "no") - isTV -> { + isTv -> { mpv?.setOptionString("hwdec", "mediacodec") mpv?.setOptionString("profile", "fast") // Don't retain already-played content for backward @@ -277,6 +278,7 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { currentUrl = null currentHeaders = null pendingExternalSubtitles = emptyList() + activeExternalSubtitles = emptyList() initialSubtitleId = null initialAudioId = null cachedPosition = 0.0 @@ -438,7 +440,8 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { headers = currentHeaders, startPosition = cachedPosition, initialAudioId = savedAid, - initialSubtitleId = savedSid + initialSubtitleId = savedSid, + externalSubtitles = activeExternalSubtitles ) // Hold the paused state explicitly — we only get here while paused, @@ -461,6 +464,7 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { currentUrl = url currentHeaders = headers pendingExternalSubtitles = externalSubtitles ?: emptyList() + activeExternalSubtitles = pendingExternalSubtitles this.initialSubtitleId = initialSubtitleId this.initialAudioId = initialAudioId @@ -620,6 +624,11 @@ class MPVLayerRenderer(private val context: Context) : MPVLib.EventObserver { fun addSubtitleFile(url: String, select: Boolean = true) { val flag = if (select) "select" else "cached" mpv?.command(arrayOf("sub-add", url, flag)) + // Track runtime side-loads too, so they survive a resume-recovery + // reload just like external subs passed to load(). + if (url.isNotEmpty() && url !in activeExternalSubtitles) { + activeExternalSubtitles = activeExternalSubtitles + url + } } // MARK: - Subtitle Positioning