mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-11-07 16:06:35 +01:00
Fix issues with external subtitles & transcoding (#1790)
## Description Fixes a bug where the external subtitle track would not be activated if playback is transcoded Also fixes a bug where external subtitles would cause MPV to incorrectly switch to transcoding ### Related issues Fixes #1778 ### Testing Emulator with files that have a variety of external SRT, embedded SRT & ASS, & embedded PGS ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
7581b189aa
commit
454c0212b6
2 changed files with 93 additions and 41 deletions
|
|
@ -184,6 +184,7 @@ class PlaybackViewModel
|
||||||
internal lateinit var currentItem: PlaylistItem
|
internal lateinit var currentItem: PlaylistItem
|
||||||
internal var forceTranscoding: Boolean = false
|
internal var forceTranscoding: Boolean = false
|
||||||
private var activityListener: TrackActivityPlaybackListener? = null
|
private var activityListener: TrackActivityPlaybackListener? = null
|
||||||
|
private var trackChangeListener: TracksChangedListener? = null
|
||||||
private val jobs = mutableListOf<Job>()
|
private val jobs = mutableListOf<Job>()
|
||||||
|
|
||||||
private val isPlaylist = destination is Destination.PlaybackList
|
private val isPlaylist = destination is Destination.PlaybackList
|
||||||
|
|
@ -215,6 +216,9 @@ class PlaybackViewModel
|
||||||
it.release()
|
it.release()
|
||||||
player.removeListener(it)
|
player.removeListener(it)
|
||||||
}
|
}
|
||||||
|
this@PlaybackViewModel.trackChangeListener?.let {
|
||||||
|
player.removeListener(it)
|
||||||
|
}
|
||||||
player.release()
|
player.release()
|
||||||
mediaSession?.release()
|
mediaSession?.release()
|
||||||
}
|
}
|
||||||
|
|
@ -604,6 +608,9 @@ class PlaybackViewModel
|
||||||
withContext(WholphinDispatchers.IO) {
|
withContext(WholphinDispatchers.IO) {
|
||||||
val itemId = item.id
|
val itemId = item.id
|
||||||
|
|
||||||
|
trackChangeListener?.let { onMain { player.removeListener(it) } }
|
||||||
|
trackChangeListener = null
|
||||||
|
|
||||||
state.value.currentPlayback?.let { currentPlayback ->
|
state.value.currentPlayback?.let { currentPlayback ->
|
||||||
if (currentPlayback.item.id == item.id &&
|
if (currentPlayback.item.id == item.id &&
|
||||||
currentPlayback.playMethod == PlayMethod.DIRECT_PLAY &&
|
currentPlayback.playMethod == PlayMethod.DIRECT_PLAY &&
|
||||||
|
|
@ -715,6 +722,7 @@ class PlaybackViewModel
|
||||||
|
|
||||||
val externalSubtitle =
|
val externalSubtitle =
|
||||||
source.findExternalSubtitle(subtitleIndex)?.let {
|
source.findExternalSubtitle(subtitleIndex)?.let {
|
||||||
|
Timber.v("Using externally delivered subtitle tracks %s", subtitleIndex)
|
||||||
it.deliveryUrl?.let { deliveryUrl ->
|
it.deliveryUrl?.let { deliveryUrl ->
|
||||||
var flags = 0
|
var flags = 0
|
||||||
if (it.isForced) flags = flags.or(C.SELECTION_FLAG_FORCED)
|
if (it.isForced) flags = flags.or(C.SELECTION_FLAG_FORCED)
|
||||||
|
|
@ -807,48 +815,51 @@ class PlaybackViewModel
|
||||||
mediaItem,
|
mediaItem,
|
||||||
positionMs,
|
positionMs,
|
||||||
)
|
)
|
||||||
if (transcodeType == PlayMethod.DIRECT_PLAY && (audioIndex != null || subtitleIndex != null)) {
|
val onFailure: () -> Unit = {
|
||||||
val onTracksChangedListener =
|
if (player is MpvPlayer && externalSubtitle != null) {
|
||||||
object : Player.Listener {
|
// MpvPlayer may change tracks more than once to add external subtitles
|
||||||
override fun onTracksChanged(tracks: Tracks) {
|
trackChangeListener?.let { player.addListener(it) }
|
||||||
Timber.v("onTracksChanged: $tracks")
|
} else {
|
||||||
if (tracks.groups.isNotEmpty()) {
|
viewModelScope.launchIO {
|
||||||
val result =
|
changeStreams(
|
||||||
TrackSelectionUtils.createTrackSelections(
|
item = item,
|
||||||
player.trackSelectionParameters,
|
sourceId = sourceId,
|
||||||
player.currentTracks,
|
audioIndex = audioIndex,
|
||||||
audioIndex,
|
subtitleIndex = subtitleIndex,
|
||||||
subtitleIndex,
|
positionMs = positionMs,
|
||||||
source,
|
enableDirectPlay = false,
|
||||||
)
|
enableDirectStream = true,
|
||||||
Timber.v("onTracksChanged: %s", result)
|
)
|
||||||
player.removeListener(this)
|
|
||||||
if (result.bothSelected) {
|
|
||||||
player.trackSelectionParameters =
|
|
||||||
result.trackSelectionParameters
|
|
||||||
} else {
|
|
||||||
// Fall back to transcoding
|
|
||||||
Timber.w(
|
|
||||||
"Failed to select tracks, falling back to transcoding: %s",
|
|
||||||
result,
|
|
||||||
)
|
|
||||||
viewModelScope.launchIO {
|
|
||||||
changeStreams(
|
|
||||||
item = item,
|
|
||||||
sourceId = sourceId,
|
|
||||||
audioIndex = audioIndex,
|
|
||||||
subtitleIndex = subtitleIndex,
|
|
||||||
positionMs = positionMs,
|
|
||||||
enableDirectPlay = false,
|
|
||||||
enableDirectStream = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewModelScope.launchIO { loadSubtitleDelay() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
player.addListener(onTracksChangedListener)
|
}
|
||||||
|
}
|
||||||
|
val onTracksChangedListener =
|
||||||
|
if (transcodeType == PlayMethod.DIRECT_PLAY && (audioIndex != null || subtitleIndex != null)) {
|
||||||
|
TracksChangedListener(
|
||||||
|
player = player,
|
||||||
|
audioIndex = audioIndex,
|
||||||
|
subtitleIndex = subtitleIndex,
|
||||||
|
source = source,
|
||||||
|
onFailure = onFailure,
|
||||||
|
)
|
||||||
|
} else if (externalSubtitle != null) {
|
||||||
|
TracksChangedListener(
|
||||||
|
player = player,
|
||||||
|
audioIndex = null, // Do not manually activate audio
|
||||||
|
subtitleIndex = subtitleIndex,
|
||||||
|
source = source,
|
||||||
|
onFailure = onFailure,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
onTracksChangedListener?.let {
|
||||||
|
player.addListener(it)
|
||||||
|
this@PlaybackViewModel.trackChangeListener = it
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subtitleIndex != null) {
|
||||||
|
viewModelScope.launchIO { loadSubtitleDelay() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.github.damontecres.wholphin.ui.playback
|
||||||
|
|
||||||
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.Tracks
|
||||||
|
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class TracksChangedListener(
|
||||||
|
val player: Player,
|
||||||
|
val audioIndex: Int?,
|
||||||
|
val subtitleIndex: Int?,
|
||||||
|
val source: MediaSourceInfo,
|
||||||
|
val onFailure: () -> Unit,
|
||||||
|
) : Player.Listener {
|
||||||
|
override fun onTracksChanged(tracks: Tracks) {
|
||||||
|
Timber.v("onTracksChanged: $tracks")
|
||||||
|
if (tracks.groups.isNotEmpty()) {
|
||||||
|
val result =
|
||||||
|
TrackSelectionUtils.createTrackSelections(
|
||||||
|
player.trackSelectionParameters,
|
||||||
|
player.currentTracks,
|
||||||
|
audioIndex,
|
||||||
|
subtitleIndex,
|
||||||
|
source,
|
||||||
|
)
|
||||||
|
Timber.v("onTracksChanged: %s", result)
|
||||||
|
player.removeListener(this)
|
||||||
|
if (result.bothSelected) {
|
||||||
|
player.trackSelectionParameters =
|
||||||
|
result.trackSelectionParameters
|
||||||
|
} else {
|
||||||
|
// Fall back to transcoding
|
||||||
|
Timber.w(
|
||||||
|
"Failed to select tracks, falling back to transcoding: %s",
|
||||||
|
result,
|
||||||
|
)
|
||||||
|
onFailure.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue