Fix wrong embedded subtitle track selected when ASS tracks are present (#5862)

* Fix wrong embedded subtitle track selected when ASS tracks are present

The local index of an embedded subtitle was computed among the streams
with an EMBED or HLS delivery method, then used to pick a text track group
in ExoPlayer. ExoPlayer however exposes every subtitle track of the
container, including ASS/SSA tracks that the server burns in when libass
is disabled. Each such track placed before the selected one shifted the
lookup, so a different track, often in another language, was displayed.

Count all non-external subtitle streams for embedded delivery so both
lists match.

* Keep the requested subtitle when restoring the saved language

Restoring the last played subtitle language picked the first subtitle
stream in that language on every playback start, including the restart
used to switch between baked and non-baked subtitles. Switching from a
baked ASS track to an SRT track in the same language therefore selected
the ASS track again and went back to transcoding.

Keep the requested stream when it matches the saved language and only
fall back to the first matching stream otherwise.
This commit is contained in:
Sebastien Villanueva authored and GitHub committed 2026-10-15 17:23:58 +02:00
1 parent b411f95c91
commit 7e41e2c925
2 files changed
+17 -4

No files matched your search

@@ -650,12 +650,17 @@ public class PlaybackController implements PlaybackControllerNotifiable {
// User explicitly disabled subtitles
mCurrentOptions.setSubtitleStreamIndex(null);
} else if (response.getMediaSource().getMediaStreams() != null) {
// Find subtitle stream matching saved language
// Find subtitle stream matching saved language, keeping the requested stream if it matches
// (e.g. when playback restarts to switch between baked and non-baked subtitles)
Integer requestedIndex = mCurrentOptions.getSubtitleStreamIndex();
Integer matchingIndex = null;
for (MediaStream stream : response.getMediaSource().getMediaStreams()) {
if (stream.getType() == MediaStreamType.SUBTITLE && lastSubtitleLanguage.equals(stream.getLanguage())) {
matchingIndex = stream.getIndex();
break;
if (matchingIndex == null) matchingIndex = stream.getIndex();
if (requestedIndex != null && requestedIndex == stream.getIndex()) {
matchingIndex = requestedIndex;
break;
}
}
}
mCurrentOptions.setSubtitleStreamIndex(matchingIndex);
@@ -124,7 +124,15 @@ fun PlaybackController.setSubtitleIndex(index: Int, force: Boolean = false) {
// The server does not send a reliable index in all cases, so calculate it manually
val localIndex = mediaSource.mediaStreams.orEmpty()
.filter { it.type == MediaStreamType.SUBTITLE }
.filter { it.deliveryMethod == SubtitleDeliveryMethod.EMBED || it.deliveryMethod == SubtitleDeliveryMethod.HLS }
.filter {
if (stream.deliveryMethod == SubtitleDeliveryMethod.EMBED) {
// ExoPlayer exposes every subtitle track of the container, including the ones the server
// would burn in (ASS/SSA without libass), so they must be counted to match its track groups
!it.isExternal
} else {
it.deliveryMethod == SubtitleDeliveryMethod.EMBED || it.deliveryMethod == SubtitleDeliveryMethod.HLS
}
}
.indexOf(stream)
.takeIf { it != -1 }