Add settings to switch player backends

This commit is contained in:
Damontecres 2025-11-05 16:04:10 -05:00
parent 4bd6672a8c
commit 5563935a51
No known key found for this signature in database
8 changed files with 106 additions and 22 deletions

View file

@ -654,6 +654,30 @@ sealed interface AppPreference<T> {
summaryOn = R.string.enabled,
summaryOff = R.string.disabled,
)
val PlayerBackendPref =
AppChoicePreference<PlayerBackend>(
title = R.string.player_backend,
defaultValue = PlayerBackend.EXO_PLAYER,
getter = { it.playbackPreferences.playerBackend },
setter = { prefs, value ->
prefs.updatePlaybackPreferences { playerBackend = value }
},
displayValues = R.array.player_backend_options,
indexToValue = { PlayerBackend.forNumber(it) },
valueToIndex = { it.number },
)
val MpvHardwareDecoding =
AppSwitchPreference(
title = R.string.mpv_hardware_decoding,
defaultValue = true,
getter = { it.playbackPreferences.mpvOptions.enableHardwareDecoding },
setter = { prefs, value ->
prefs.updateMpvOptions { enableHardwareDecoding = value }
},
summary = R.string.disable_if_crash,
)
}
}
@ -739,6 +763,8 @@ val advancedPreferences =
AppPreference.SkipRecaps,
AppPreference.MaxBitrate,
AppPreference.PlaybackDebugInfo,
AppPreference.PlayerBackendPref,
AppPreference.MpvHardwareDecoding,
),
),
PreferenceGroup(

View file

@ -44,6 +44,7 @@ class AppPreferencesSerializer
passOutProtectionMs =
AppPreference.PassOutProtection.defaultValue.hours.inWholeMilliseconds
showNextUpWhen = AppPreference.ShowNextUpTiming.defaultValue
playerBackend = AppPreference.PlayerBackendPref.defaultValue
overrides =
PlaybackOverrides
@ -56,6 +57,14 @@ class AppPreferencesSerializer
mediaExtensionsEnabled =
AppPreference.FfmpegPreference.defaultValue
}.build()
mpvOptions =
MpvOptions
.newBuilder()
.apply {
enableHardwareDecoding =
AppPreference.MpvHardwareDecoding.defaultValue
}.build()
}.build()
homePagePreferences =
HomePagePreferences
@ -103,6 +112,11 @@ inline fun AppPreferences.updatePlaybackOverrides(block: PlaybackOverrides.Build
overrides = overrides.toBuilder().apply(block).build()
}
inline fun AppPreferences.updateMpvOptions(block: MpvOptions.Builder.() -> Unit): AppPreferences =
updatePlaybackPreferences {
mpvOptions = mpvOptions.toBuilder().apply(block).build()
}
inline fun AppPreferences.updateHomePagePreferences(block: HomePagePreferences.Builder.() -> Unit): AppPreferences =
update {
homePagePreferences = homePagePreferences.toBuilder().apply(block).build()

View file

@ -390,6 +390,12 @@ fun PlaybackOverlay(
.padding(16.dp)
.background(AppColors.TransparentBlack50),
) {
Text(
text = "Backend: ${currentPlayback?.backend}",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(start = 8.dp),
)
Text(
text = "Play method: ${currentPlayback?.playMethod?.serialName}",
style = MaterialTheme.typography.bodySmall,

View file

@ -18,6 +18,7 @@ import androidx.media3.common.TrackSelectionOverride
import androidx.media3.common.Tracks
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.DefaultRenderersFactory
import androidx.media3.exoplayer.ExoPlayer
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ItemPlaybackDao
import com.github.damontecres.wholphin.data.ItemPlaybackRepository
@ -33,6 +34,7 @@ import com.github.damontecres.wholphin.data.model.chooseStream
import com.github.damontecres.wholphin.preferences.AppPreference
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.MediaExtensionStatus
import com.github.damontecres.wholphin.preferences.PlayerBackend
import com.github.damontecres.wholphin.preferences.ShowNextUpWhen
import com.github.damontecres.wholphin.preferences.SkipSegmentBehavior
import com.github.damontecres.wholphin.preferences.UserPreferences
@ -121,8 +123,24 @@ class PlaybackViewModel
) : ViewModel(),
Player.Listener {
val player by lazy {
val extensions =
runBlocking { appPreferences.data.firstOrNull() }?.playbackPreferences?.overrides?.mediaExtensionsEnabled
val prefs = runBlocking { appPreferences.data.firstOrNull()?.playbackPreferences }
val backend = prefs?.playerBackend ?: AppPreference.PlayerBackendPref.defaultValue
when (backend) {
PlayerBackend.MPV -> {
val enableHardwareDecoding =
prefs?.mpvOptions?.enableHardwareDecoding
?: AppPreference.MpvHardwareDecoding.defaultValue
MpvPlayer(context, enableHardwareDecoding)
.apply {
playWhenReady = true
}
}
PlayerBackend.EXO_PLAYER,
PlayerBackend.UNRECOGNIZED,
-> {
val extensions = prefs?.overrides?.mediaExtensionsEnabled
Timber.v("extensions=$extensions")
val rendererMode =
when (extensions) {
@ -131,17 +149,14 @@ class PlaybackViewModel
MediaExtensionStatus.MES_DISABLED -> DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF
else -> DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON
}
// ExoPlayer
// .Builder(context)
// .setRenderersFactory(
// DefaultRenderersFactory(context)
// .setEnableDecoderFallback(true)
// .setExtensionRendererMode(rendererMode),
// ).build()
// TODO add settings for enabling HW decoding
MpvPlayer(context, false)
.apply {
playWhenReady = true
ExoPlayer
.Builder(context)
.setRenderersFactory(
DefaultRenderersFactory(context)
.setEnableDecoderFallback(true)
.setExtensionRendererMode(rendererMode),
).build()
}
}
}
@ -518,7 +533,8 @@ class PlaybackViewModel
val playback =
CurrentPlayback(
listOf(),
backend = preferences.appPreferences.playbackPreferences.playerBackend,
tracks = listOf(),
playMethod = transcodeType,
playSessionId = response.playSessionId,
liveStreamId = source.liveStreamId,
@ -1029,6 +1045,7 @@ class PlaybackViewModel
}
data class CurrentPlayback(
val backend: PlayerBackend,
val tracks: List<TrackSupport>,
val playMethod: PlayMethod,
val playSessionId: String?,

View file

@ -293,8 +293,10 @@ class MpvPlayer(
}
override fun getDuration(): Long {
throwIfReleased()
if (DEBUG) Timber.v("getDuration")
if (isReleased) {
return durationMs
}
val duration =
MPVLib.getPropertyDouble("duration/full")?.seconds?.inWholeMilliseconds
?: durationMs

View file

@ -29,6 +29,15 @@ enum MediaExtensionStatus{
MES_DISABLED = 2;
}
enum PlayerBackend{
EXO_PLAYER = 0;
MPV = 1;
}
message MpvOptions{
bool enable_hardware_decoding = 1;
}
message PlaybackOverrides{
bool ac3_supported = 1;
bool downmix_stereo = 2;
@ -58,6 +67,8 @@ message PlaybackPreferences {
int64 pass_out_protection_ms = 16;
PrefContentScale global_content_scale = 17;
ShowNextUpWhen show_next_up_when = 18;
PlayerBackend player_backend = 19;
MpvOptions mpv_options = 20;
}
message HomePagePreferences{

View file

@ -90,4 +90,9 @@
<item>During end credits/outro</item>
</string-array>
<string-array name="player_backend_options">
<item>ExoPlayer (default)</item>
<item>MPV (Experimental)</item>
</string-array>
</resources>

View file

@ -142,6 +142,9 @@
<string name="aired_episode_order">Aired Episode Order</string>
<string name="create_playlist">Create new playlist</string>
<string name="add_to_playlist">Add to playlist</string>
<string name="player_backend">Playback Backend</string>
<string name="mpv_hardware_decoding">MPV: Use hardware decoding</string>
<string name="disable_if_crash">Disable if you experience crashes</string>
<plurals name="downloads">
<item quantity="zero">%d downloads</item>