WIP libass options

This commit is contained in:
Damontecres 2026-03-30 13:55:27 -04:00
parent 08ecb5ad3a
commit 77062652fa
No known key found for this signature in database
8 changed files with 51 additions and 19 deletions

View file

@ -430,16 +430,18 @@ sealed interface AppPreference<Pref, T> {
summaryOn = R.string.enabled, summaryOn = R.string.enabled,
summaryOff = R.string.disabled, summaryOff = R.string.disabled,
) )
val DirectPlayAss = val AssSubtitleMode =
AppSwitchPreference<AppPreferences>( AppChoicePreference<AppPreferences, AssPlaybackMode>(
title = R.string.direct_play_ass, title = R.string.app_theme,
defaultValue = true, defaultValue = AssPlaybackMode.ASS_LIBASS,
getter = { it.playbackPreferences.overrides.directPlayAss }, getter = { it.playbackPreferences.overrides.assPlaybackMode },
setter = { prefs, value -> setter = { prefs, value ->
prefs.updatePlaybackOverrides { directPlayAss = value } prefs.updatePlaybackOverrides { assPlaybackMode = value }
}, },
summaryOn = R.string.enabled, displayValues = R.array.ass_subtitle_modes,
summaryOff = R.string.disabled, subtitles = R.array.ass_subtitle_modes_summary,
indexToValue = { AssPlaybackMode.forNumber(it) },
valueToIndex = { if (it != AssPlaybackMode.UNRECOGNIZED) it.number else AssPlaybackMode.ASS_LIBASS.number },
) )
val DirectPlayPgs = val DirectPlayPgs =
AppSwitchPreference<AppPreferences>( AppSwitchPreference<AppPreferences>(
@ -1097,7 +1099,7 @@ private val ExoPlayerSettings =
AppPreference.FfmpegPreference, AppPreference.FfmpegPreference,
AppPreference.DownMixStereo, AppPreference.DownMixStereo,
AppPreference.Ac3Supported, AppPreference.Ac3Supported,
AppPreference.DirectPlayAss, AppPreference.AssSubtitleMode,
AppPreference.DirectPlayPgs, AppPreference.DirectPlayPgs,
AppPreference.DirectPlayDoviProfile7, AppPreference.DirectPlayDoviProfile7,
AppPreference.DecodeAv1, AppPreference.DecodeAv1,

View file

@ -61,10 +61,12 @@ class AppPreferencesSerializer
.apply { .apply {
ac3Supported = AppPreference.Ac3Supported.defaultValue ac3Supported = AppPreference.Ac3Supported.defaultValue
downmixStereo = AppPreference.DownMixStereo.defaultValue downmixStereo = AppPreference.DownMixStereo.defaultValue
directPlayAss = AppPreference.DirectPlayAss.defaultValue // directPlayAss = AppPreference.DirectPlayAss.defaultValue
directPlayPgs = AppPreference.DirectPlayPgs.defaultValue directPlayPgs = AppPreference.DirectPlayPgs.defaultValue
mediaExtensionsEnabled = mediaExtensionsEnabled =
AppPreference.FfmpegPreference.defaultValue AppPreference.FfmpegPreference.defaultValue
assPlaybackMode =
AppPreference.AssSubtitleMode.defaultValue
}.build() }.build()
mpvOptions = mpvOptions =

View file

@ -131,7 +131,7 @@ class AppUpgradeHandler
it.updatePlaybackOverrides { it.updatePlaybackOverrides {
ac3Supported = AppPreference.Ac3Supported.defaultValue ac3Supported = AppPreference.Ac3Supported.defaultValue
downmixStereo = AppPreference.DownMixStereo.defaultValue downmixStereo = AppPreference.DownMixStereo.defaultValue
directPlayAss = AppPreference.DirectPlayAss.defaultValue // directPlayAss = AppPreference.DirectPlayAss.defaultValue
directPlayPgs = AppPreference.DirectPlayPgs.defaultValue directPlayPgs = AppPreference.DirectPlayPgs.defaultValue
} }
} }

View file

@ -1,6 +1,7 @@
package com.github.damontecres.wholphin.services package com.github.damontecres.wholphin.services
import android.content.Context import android.content.Context
import com.github.damontecres.wholphin.preferences.AssPlaybackMode
import com.github.damontecres.wholphin.preferences.PlaybackPreferences import com.github.damontecres.wholphin.preferences.PlaybackPreferences
import com.github.damontecres.wholphin.util.profile.MediaCodecCapabilitiesTest import com.github.damontecres.wholphin.util.profile.MediaCodecCapabilitiesTest
import com.github.damontecres.wholphin.util.profile.createDeviceProfile import com.github.damontecres.wholphin.util.profile.createDeviceProfile
@ -43,7 +44,7 @@ class DeviceProfileService
maxBitrate = prefs.maxBitrate.toInt(), maxBitrate = prefs.maxBitrate.toInt(),
isAC3Enabled = prefs.overrides.ac3Supported, isAC3Enabled = prefs.overrides.ac3Supported,
downMixAudio = prefs.overrides.downmixStereo, downMixAudio = prefs.overrides.downmixStereo,
assDirectPlay = prefs.overrides.directPlayAss, assPlaybackMode = prefs.overrides.assPlaybackMode,
pgsDirectPlay = prefs.overrides.directPlayPgs, pgsDirectPlay = prefs.overrides.directPlayPgs,
dolbyVisionELDirectPlay = prefs.overrides.directPlayDolbyVisionEL, dolbyVisionELDirectPlay = prefs.overrides.directPlayDolbyVisionEL,
decodeAv1 = prefs.overrides.decodeAv1, decodeAv1 = prefs.overrides.decodeAv1,
@ -58,7 +59,7 @@ class DeviceProfileService
maxBitrate = newConfig.maxBitrate, maxBitrate = newConfig.maxBitrate,
isAC3Enabled = newConfig.isAC3Enabled, isAC3Enabled = newConfig.isAC3Enabled,
downMixAudio = newConfig.downMixAudio, downMixAudio = newConfig.downMixAudio,
assDirectPlay = newConfig.assDirectPlay, assDirectPlay = newConfig.assPlaybackMode != AssPlaybackMode.ASS_TRANSCODE,
pgsDirectPlay = newConfig.pgsDirectPlay, pgsDirectPlay = newConfig.pgsDirectPlay,
dolbyVisionELDirectPlay = newConfig.dolbyVisionELDirectPlay, dolbyVisionELDirectPlay = newConfig.dolbyVisionELDirectPlay,
decodeAv1 = prefs.overrides.decodeAv1, decodeAv1 = prefs.overrides.decodeAv1,
@ -77,7 +78,7 @@ data class DeviceProfileConfiguration(
val maxBitrate: Int, val maxBitrate: Int,
val isAC3Enabled: Boolean, val isAC3Enabled: Boolean,
val downMixAudio: Boolean, val downMixAudio: Boolean,
val assDirectPlay: Boolean, val assPlaybackMode: AssPlaybackMode,
val pgsDirectPlay: Boolean, val pgsDirectPlay: Boolean,
val dolbyVisionELDirectPlay: Boolean, val dolbyVisionELDirectPlay: Boolean,
val decodeAv1: Boolean, val decodeAv1: Boolean,

View file

@ -21,6 +21,7 @@ import androidx.media3.exoplayer.video.MediaCodecVideoRenderer
import androidx.media3.exoplayer.video.VideoRendererEventListener import androidx.media3.exoplayer.video.VideoRendererEventListener
import androidx.media3.extractor.DefaultExtractorsFactory import androidx.media3.extractor.DefaultExtractorsFactory
import com.github.damontecres.wholphin.preferences.AppPreferences import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.AssPlaybackMode
import com.github.damontecres.wholphin.preferences.MediaExtensionStatus import com.github.damontecres.wholphin.preferences.MediaExtensionStatus
import com.github.damontecres.wholphin.preferences.PlaybackPreferences import com.github.damontecres.wholphin.preferences.PlaybackPreferences
import com.github.damontecres.wholphin.preferences.PlayerBackend import com.github.damontecres.wholphin.preferences.PlayerBackend
@ -77,9 +78,14 @@ class PlayerFactory
PlayerBackend.UNRECOGNIZED, PlayerBackend.UNRECOGNIZED,
-> { -> {
val extensions = prefs.overrides.mediaExtensionsEnabled val extensions = prefs.overrides.mediaExtensionsEnabled
val directPlayAss = prefs.overrides.directPlayAss val useLibAss =
prefs.overrides.assPlaybackMode == AssPlaybackMode.ASS_LIBASS
val decodeAv1 = prefs.overrides.decodeAv1 val decodeAv1 = prefs.overrides.decodeAv1
Timber.v("extensions=$extensions, directPlayAss=$directPlayAss") Timber.v(
"extensions=%s, assPlaybackMode=%s",
extensions,
prefs.overrides.assPlaybackMode,
)
val rendererMode = val rendererMode =
when (extensions) { when (extensions) {
MediaExtensionStatus.MES_FALLBACK -> DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON MediaExtensionStatus.MES_FALLBACK -> DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON
@ -94,7 +100,7 @@ class PlayerFactory
.setEnableDecoderFallback(true) .setEnableDecoderFallback(true)
.setExtensionRendererMode(rendererMode) .setExtensionRendererMode(rendererMode)
val mediaSourceFactory = val mediaSourceFactory =
if (directPlayAss) { if (useLibAss) {
assHandler = AssHandler(AssRenderType.OVERLAY_OPEN_GL) assHandler = AssHandler(AssRenderType.OVERLAY_OPEN_GL)
val assSubtitleParserFactory = AssSubtitleParserFactory(assHandler) val assSubtitleParserFactory = AssSubtitleParserFactory(assHandler)
renderersFactory = AssRenderersFactory(assHandler, renderersFactory) renderersFactory = AssRenderersFactory(assHandler, renderersFactory)

View file

@ -66,6 +66,7 @@ import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.surfaceColorAtElevation import androidx.tv.material3.surfaceColorAtElevation
import com.github.damontecres.wholphin.data.model.ItemPlayback import com.github.damontecres.wholphin.data.model.ItemPlayback
import com.github.damontecres.wholphin.data.model.Playlist import com.github.damontecres.wholphin.data.model.Playlist
import com.github.damontecres.wholphin.preferences.AssPlaybackMode
import com.github.damontecres.wholphin.preferences.PlayerBackend import com.github.damontecres.wholphin.preferences.PlayerBackend
import com.github.damontecres.wholphin.preferences.UserPreferences import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.preferences.skipBackOnResume import com.github.damontecres.wholphin.preferences.skipBackOnResume
@ -440,7 +441,7 @@ fun PlaybackPageContent(
setBottomPaddingFraction(it.margin.toFloat() / 100f) setBottomPaddingFraction(it.margin.toFloat() / 100f)
} }
playerState.assHandler?.let { assHandler -> playerState.assHandler?.let { assHandler ->
if (prefs.overrides.directPlayAss) { if (prefs.overrides.assPlaybackMode == AssPlaybackMode.ASS_LIBASS) {
Timber.v("Adding AssSubtitleView") Timber.v("Adding AssSubtitleView")
addView( addView(
AssSubtitleView(context, assHandler).apply { AssSubtitleView(context, assHandler).apply {

View file

@ -40,14 +40,21 @@ message MpvOptions{
bool use_gpu_next = 2; bool use_gpu_next = 2;
} }
enum AssPlaybackMode{
ASS_LIBASS = 0;
ASS_EXO_PLAYER = 1;
ASS_TRANSCODE = 2;
}
message PlaybackOverrides{ message PlaybackOverrides{
bool ac3_supported = 1; bool ac3_supported = 1;
bool downmix_stereo = 2; bool downmix_stereo = 2;
bool direct_play_ass = 3; bool direct_play_ass = 3 [deprecated = true];
bool direct_play_pgs = 4; bool direct_play_pgs = 4;
MediaExtensionStatus media_extensions_enabled = 5; MediaExtensionStatus media_extensions_enabled = 5;
bool direct_play_dolby_vision_e_l = 6; bool direct_play_dolby_vision_e_l = 6;
bool decode_av1 = 7; bool decode_av1 = 7;
AssPlaybackMode ass_playback_mode = 8;
} }
message PlaybackPreferences { message PlaybackPreferences {

View file

@ -749,4 +749,17 @@
<string name="separate_types">Separate types</string> <string name="separate_types">Separate types</string>
<string name="prefer_logos">Prefer showing logos for titles</string> <string name="prefer_logos">Prefer showing logos for titles</string>
<string name="ass_subtitle_mode_libass">Direct play with libass</string>
<string name="ass_subtitle_mode_exoplayer">Direct play with ExoPlayer built-in</string>
<string name="ass_subtitle_mode_transcode">Burn in/transcode on server</string>
<array name="ass_subtitle_modes">
<item>@string/ass_subtitle_mode_libass</item>
<item>@string/ass_subtitle_mode_exoplayer</item>
<item>@string/ass_subtitle_mode_transcode</item>
</array>
<array name="ass_subtitle_modes_summary">
<item>@string/default_track</item>
<item></item><!-- Intentionally blank -->
<item></item><!-- Intentionally blank -->
</array>
</resources> </resources>