Add experimental libMPV player
This commit is contained in:
parent
88b5d38ffc
commit
c9d0d6ab17
7 changed files with 1543 additions and 14 deletions
|
@ -103,6 +103,8 @@ dependencies {
|
||||||
implementation("com.google.android.exoplayer:exoplayer-ui:$exoplayerVersion")
|
implementation("com.google.android.exoplayer:exoplayer-ui:$exoplayerVersion")
|
||||||
implementation(files("libs/extension-ffmpeg-release.aar"))
|
implementation(files("libs/extension-ffmpeg-release.aar"))
|
||||||
|
|
||||||
|
implementation(files("libs/libmpv/app-release.aar"))
|
||||||
|
|
||||||
// Timber
|
// Timber
|
||||||
val timberVersion = "5.0.1"
|
val timberVersion = "5.0.1"
|
||||||
implementation("com.jakewharton.timber:timber:$timberVersion")
|
implementation("com.jakewharton.timber:timber:$timberVersion")
|
||||||
|
|
BIN
app/libs/libmpv/app-release.aar
Executable file
BIN
app/libs/libmpv/app-release.aar
Executable file
Binary file not shown.
14
app/src/main/assets/mpv.conf
Executable file
14
app/src/main/assets/mpv.conf
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#vo=mediacodec_embed
|
||||||
|
# hwdec: try to use hardware decoding
|
||||||
|
hwdec=mediacodec-copy
|
||||||
|
hwdec-codecs="h264,hevc,mpeg4,mpeg2video,vp8,vp9,av1"
|
||||||
|
gpu-dumb-mode=auto
|
||||||
|
# tls: allow self signed certificate
|
||||||
|
tls-verify=no
|
||||||
|
tls-ca-file=""
|
||||||
|
# demuxer: limit cache to 32 MiB, the default is too high for mobile devices
|
||||||
|
demuxer-max-bytes=32MiB
|
||||||
|
demuxer-max-back-bytes=32MiB
|
||||||
|
# sub: scale subtitles with video
|
||||||
|
sub-scale-with-window=no
|
||||||
|
sub-use-margins=no
|
1473
app/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt
Normal file
1473
app/src/main/java/dev/jdtech/jellyfin/mpv/MPVPlayer.kt
Normal file
File diff suppressed because it is too large
Load diff
14
app/src/main/java/dev/jdtech/jellyfin/mpv/TrackType.java
Normal file
14
app/src/main/java/dev/jdtech/jellyfin/mpv/TrackType.java
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package dev.jdtech.jellyfin.mpv;
|
||||||
|
|
||||||
|
import androidx.annotation.StringDef;
|
||||||
|
|
||||||
|
@StringDef({
|
||||||
|
TrackType.VIDEO,
|
||||||
|
TrackType.AUDIO,
|
||||||
|
TrackType.SUBTITLE,
|
||||||
|
})
|
||||||
|
public @interface TrackType {
|
||||||
|
String VIDEO = "video";
|
||||||
|
String AUDIO = "audio";
|
||||||
|
String SUBTITLE = "sub";
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import com.google.android.exoplayer2.*
|
||||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.jdtech.jellyfin.models.PlayerItem
|
import dev.jdtech.jellyfin.models.PlayerItem
|
||||||
|
import dev.jdtech.jellyfin.mpv.MPVPlayer
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -26,7 +27,7 @@ constructor(
|
||||||
application: Application,
|
application: Application,
|
||||||
private val jellyfinRepository: JellyfinRepository
|
private val jellyfinRepository: JellyfinRepository
|
||||||
) : ViewModel(), Player.Listener {
|
) : ViewModel(), Player.Listener {
|
||||||
var player: SimpleExoPlayer
|
var player: BasePlayer
|
||||||
|
|
||||||
private val _navigateBack = MutableLiveData<Boolean>()
|
private val _navigateBack = MutableLiveData<Boolean>()
|
||||||
val navigateBack: LiveData<Boolean> = _navigateBack
|
val navigateBack: LiveData<Boolean> = _navigateBack
|
||||||
|
@ -38,18 +39,24 @@ constructor(
|
||||||
private val sp = PreferenceManager.getDefaultSharedPreferences(application)
|
private val sp = PreferenceManager.getDefaultSharedPreferences(application)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val renderersFactory =
|
val useMpv = sp.getBoolean("mpv_player", false)
|
||||||
DefaultRenderersFactory(application).setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
|
|
||||||
val trackSelector = DefaultTrackSelector(application)
|
if (useMpv) {
|
||||||
trackSelector.setParameters(
|
player = MPVPlayer(application, false)
|
||||||
trackSelector.buildUponParameters()
|
} else {
|
||||||
.setTunnelingEnabled(true)
|
val renderersFactory =
|
||||||
.setPreferredAudioLanguage(sp.getString("audio_language", null))
|
DefaultRenderersFactory(application).setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON)
|
||||||
.setPreferredTextLanguage(sp.getString("subtitle_language", null))
|
val trackSelector = DefaultTrackSelector(application)
|
||||||
)
|
trackSelector.setParameters(
|
||||||
|
trackSelector.buildUponParameters()
|
||||||
|
.setTunnelingEnabled(true)
|
||||||
|
.setPreferredAudioLanguage(sp.getString("audio_language", null))
|
||||||
|
.setPreferredTextLanguage(sp.getString("subtitle_language", null))
|
||||||
|
)
|
||||||
player = SimpleExoPlayer.Builder(application, renderersFactory)
|
player = SimpleExoPlayer.Builder(application, renderersFactory)
|
||||||
.setTrackSelector(trackSelector)
|
.setTrackSelector(trackSelector)
|
||||||
.build()
|
.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initializePlayer(
|
fun initializePlayer(
|
||||||
|
@ -75,9 +82,17 @@ constructor(
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
player.setMediaItems(mediaItems, currentWindow, items[0].playbackPosition)
|
val useMpv = sp.getBoolean("mpv_player", false)
|
||||||
player.playWhenReady = playWhenReady
|
|
||||||
player.prepare()
|
if (useMpv) {
|
||||||
|
player.setMediaItem(mediaItems[0])
|
||||||
|
player.prepare()
|
||||||
|
player.play()
|
||||||
|
} else {
|
||||||
|
player.setMediaItems(mediaItems, currentWindow, items[0].playbackPosition)
|
||||||
|
player.playWhenReady = playWhenReady
|
||||||
|
player.prepare()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pollPosition(player)
|
pollPosition(player)
|
||||||
|
@ -104,7 +119,7 @@ constructor(
|
||||||
player.release()
|
player.release()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pollPosition(player: SimpleExoPlayer) {
|
private fun pollPosition(player: BasePlayer) {
|
||||||
val handler = Handler(Looper.getMainLooper())
|
val handler = Handler(Looper.getMainLooper())
|
||||||
val runnable = object : Runnable {
|
val runnable = object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
|
|
@ -39,6 +39,17 @@
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:useSimpleSummaryProvider="true" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory app:title="Player">
|
||||||
|
<SwitchPreference
|
||||||
|
app:key="mpv_player"
|
||||||
|
app:title="MPV Player"
|
||||||
|
app:summary="Use the experimental MPV Player to play videos. MPV has support for more video, audio and subtitle codecs."/>
|
||||||
|
<SwitchPreference
|
||||||
|
app:dependency="mpv_player"
|
||||||
|
app:title="Force software decoding"
|
||||||
|
app:summary="Disable hardware decoding and use software decoding. Can be useful if hardware decoding gives weird artifacts."/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory app:title="@string/about">
|
<PreferenceCategory app:title="@string/about">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
|
Loading…
Reference in a new issue