Upgrade ExoPlayer to 2.16.1 (#115)

* Upgrade ExoPlayer to 2.26.1 and fix mpv player

* Re-enable ffmpeg extension
This commit is contained in:
Jarne Demeulemeester 2022-05-02 21:44:22 +02:00 committed by GitHub
parent 0b0bdab9d3
commit a785d6d3f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 133 additions and 133 deletions

View file

@ -113,7 +113,7 @@ dependencies {
kapt("com.google.dagger:hilt-compiler:$hiltVersion")
// ExoPlayer
val exoplayerVersion = "2.15.1"
val exoplayerVersion = "2.16.1"
implementation("com.google.android.exoplayer:exoplayer-core:$exoplayerVersion")
implementation("com.google.android.exoplayer:exoplayer-ui:$exoplayerVersion")
implementation(files("libs/extension-ffmpeg-release.aar"))

View file

@ -17,15 +17,13 @@ import androidx.core.content.getSystemService
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.Player.Commands
import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.device.DeviceInfo
import com.google.android.exoplayer2.metadata.Metadata
import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.source.TrackGroup
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.text.Cue
import com.google.android.exoplayer2.trackselection.TrackSelection
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.util.*
import com.google.android.exoplayer2.video.VideoSize
@ -61,7 +59,8 @@ class MPVPlayer(
val file = File(mpvDir, fileName)
Log.i("mpv", "File ${file.absolutePath}")
if (!file.exists()) {
context.assets.open(fileName, AssetManager.ACCESS_STREAMING).copyTo(FileOutputStream(file))
context.assets.open(fileName, AssetManager.ACCESS_STREAMING)
.copyTo(FileOutputStream(file))
}
}
MPVLib.create(context)
@ -144,26 +143,26 @@ class MPVPlayer(
}
// Listeners and notification.
@Suppress("DEPRECATION")
private val listeners: ListenerSet<Player.EventListener> = ListenerSet(
private val listeners: ListenerSet<Player.Listener> = ListenerSet(
context.mainLooper,
Clock.DEFAULT
) { listener: Player.EventListener, flags: FlagSet ->
) { listener: Player.Listener, flags: FlagSet ->
listener.onEvents( /* player= */this, Player.Events(flags))
}
@Suppress("DEPRECATION")
private val videoListeners = CopyOnWriteArraySet<com.google.android.exoplayer2.video.VideoListener>()
private val videoListeners =
CopyOnWriteArraySet<Player.Listener>()
// Internal state.
private var internalMediaItems: List<MediaItem>? = null
private var internalMediaItem: MediaItem? = null
@Player.State
private var playbackState: Int = Player.STATE_IDLE
private var currentPlayWhenReady: Boolean = false
@Player.RepeatMode
private val repeatMode: Int = REPEAT_MODE_OFF
private var trackGroupArray: TrackGroupArray = TrackGroupArray.EMPTY
private var trackSelectionArray: TrackSelectionArray = TrackSelectionArray()
private var tracksInfo: TracksInfo = TracksInfo.EMPTY
private var playbackParameters: PlaybackParameters = PlaybackParameters.DEFAULT
// MPV Custom
@ -185,20 +184,18 @@ class MPVPlayer(
handler.post {
when (property) {
"track-list" -> {
val (tracks, newTrackGroupArray, newTrackSelectionArray) = getMPVTracks(value)
val (tracks, newTracksInfo) = getMPVTracks(value)
tracks.forEach { Log.i("mpv", "${it.ffIndex} ${it.type} ${it.codec}") }
currentTracks = tracks
if (isPlayerReady) {
if (newTrackGroupArray != trackGroupArray || newTrackSelectionArray != trackSelectionArray) {
trackGroupArray = newTrackGroupArray
trackSelectionArray = newTrackSelectionArray
if (newTracksInfo != tracksInfo) {
tracksInfo = newTracksInfo
listeners.sendEvent(Player.EVENT_TRACKS_CHANGED) { listener ->
listener.onTracksChanged(currentTrackGroups, currentTrackSelections)
listener.onTracksInfoChanged(currentTracksInfo)
}
}
} else {
trackGroupArray = newTrackGroupArray
trackSelectionArray = newTrackSelectionArray
tracksInfo = newTracksInfo
}
}
}
@ -237,7 +234,10 @@ class MPVPlayer(
if (isSeekable != value) {
isSeekable = value
listeners.sendEvent(Player.EVENT_TIMELINE_CHANGED) { listener ->
listener.onTimelineChanged(timeline, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE)
listener.onTimelineChanged(
timeline,
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE
)
}
}
}
@ -253,7 +253,10 @@ class MPVPlayer(
if (currentDurationMs != value * C.MILLIS_PER_SECOND) {
currentDurationMs = value * C.MILLIS_PER_SECOND
listeners.sendEvent(Player.EVENT_TIMELINE_CHANGED) { listener ->
listener.onTimelineChanged(timeline, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE)
listener.onTimelineChanged(
timeline,
Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE
)
}
}
}
@ -267,7 +270,7 @@ class MPVPlayer(
when (property) {
"speed" -> {
playbackParameters = getPlaybackParameters().withSpeed(value.toFloat())
listeners.sendEvent(Player.EVENT_PLAYBACK_PARAMETERS_CHANGED) {listener ->
listeners.sendEvent(Player.EVENT_PLAYBACK_PARAMETERS_CHANGED) { listener ->
listener.onPlaybackParametersChanged(getPlaybackParameters())
}
}
@ -297,7 +300,8 @@ class MPVPlayer(
if (!isPlayerReady) {
isPlayerReady = true
listeners.sendEvent(Player.EVENT_TRACKS_CHANGED) { listener ->
listener.onTracksChanged(currentTrackGroups, currentTrackSelections)
//listener.onTracksChanged(currentTrackGroups, currentTrackSelections)
listener.onTracksInfoChanged(currentTracksInfo)
}
seekTo(C.TIME_UNSET)
if (playWhenReady) {
@ -364,7 +368,11 @@ class MPVPlayer(
* @param index Index to select or [C.INDEX_UNSET] to disable [TrackType]
* @return true if the track is or was already selected
*/
fun selectTrack(@TrackType trackType: String, isExternal: Boolean = false, index: Int): Boolean {
fun selectTrack(
@TrackType trackType: String,
isExternal: Boolean = false,
index: Int
): Boolean {
if (index != C.INDEX_UNSET) {
Log.i("mpv", "${currentTracks.size}")
currentTracks.firstOrNull {
@ -405,7 +413,11 @@ class MPVPlayer(
* default start position should be projected.
* @return The populated [com.google.android.exoplayer2.Timeline.Window], for convenience.
*/
override fun getWindow(windowIndex: Int, window: Window, defaultPositionProjectionUs: Long): Window {
override fun getWindow(
windowIndex: Int,
window: Window,
defaultPositionProjectionUs: Long
): Window {
val currentMediaItem =
internalMediaItems?.get(windowIndex) ?: MediaItem.Builder().build()
return window.set(
@ -419,7 +431,7 @@ class MPVPlayer(
/* isDynamic= */ !isSeekable,
/* liveConfiguration= */ currentMediaItem.liveConfiguration,
/* defaultPositionUs= */ C.TIME_UNSET,
/* durationUs= */ C.msToUs(currentDurationMs ?: C.TIME_UNSET),
/* durationUs= */ Util.msToUs(currentDurationMs ?: C.TIME_UNSET),
/* firstPeriodIndex= */ windowIndex,
/* lastPeriodIndex= */ windowIndex,
/* positionInFirstPeriodUs= */ C.TIME_UNSET
@ -448,7 +460,7 @@ class MPVPlayer(
/* id= */ periodIndex,
/* uid= */ periodIndex,
/* windowIndex= */ periodIndex,
/* durationUs= */ C.msToUs(currentDurationMs ?: C.TIME_UNSET),
/* durationUs= */ Util.msToUs(currentDurationMs ?: C.TIME_UNSET),
/* positionInWindowUs= */ 0
)
}
@ -507,7 +519,7 @@ class MPVPlayer(
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> {
MPVLib.command(arrayOf("multiply", "volume", "$AUDIO_FOCUS_DUCKING"))
audioFocusCallback = {
MPVLib.command(arrayOf("multiply", "volume", "${1f/AUDIO_FOCUS_DUCKING}"))
MPVLib.command(arrayOf("multiply", "volume", "${1f / AUDIO_FOCUS_DUCKING}"))
}
}
AudioManager.AUDIOFOCUS_GAIN -> {
@ -527,18 +539,6 @@ class MPVPlayer(
return handler.looper
}
/**
* Registers a listener to receive events from the player. The listener's methods will be called
* on the thread that was used to construct the player. However, if the thread used to construct
* the player does not have a [Looper], then the listener will be called on the main thread.
*
* @param listener The listener to register.
*/
@Suppress("DEPRECATION")
override fun addListener(listener: Player.EventListener) {
listeners.add(listener)
}
/**
* Registers a listener to receive all events from the player.
*
@ -549,17 +549,6 @@ class MPVPlayer(
videoListeners.add(listener)
}
/**
* Unregister a listener registered through [.addListener]. The listener will
* no longer receive events from the player.
*
* @param listener The listener to unregister.
*/
@Suppress("DEPRECATION")
override fun removeListener(listener: Player.EventListener) {
listeners.remove(listener)
}
/**
* Unregister a listener registered through [.addListener]. The listener will no
* longer receive events.
@ -595,7 +584,11 @@ class MPVPlayer(
* @throws com.google.android.exoplayer2.IllegalSeekPositionException If the provided `startWindowIndex` is not within the
* bounds of the list of media items.
*/
override fun setMediaItems(mediaItems: MutableList<MediaItem>, startWindowIndex: Int, startPositionMs: Long) {
override fun setMediaItems(
mediaItems: MutableList<MediaItem>,
startWindowIndex: Int,
startPositionMs: Long
) {
internalMediaItems = mediaItems
currentIndex = startWindowIndex
initialSeekTo = startPositionMs / 1000
@ -654,30 +647,31 @@ class MPVPlayer(
* @return The currently available [com.google.android.exoplayer2.Player.Commands].
* @see com.google.android.exoplayer2.Player.Listener.onAvailableCommandsChanged
*/
override fun getAvailableCommands(): Player.Commands {
override fun getAvailableCommands(): Commands {
return Commands.Builder()
.addAll(permanentAvailableCommands)
.addIf(COMMAND_SEEK_TO_DEFAULT_POSITION, !isPlayingAd)
.addIf(COMMAND_SEEK_IN_CURRENT_WINDOW, isCurrentWindowSeekable && !isPlayingAd)
.addIf(COMMAND_SEEK_TO_PREVIOUS_WINDOW, hasPreviousWindow() && !isPlayingAd)
.addIf(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, isCurrentMediaItemSeekable && !isPlayingAd)
.addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPreviousMediaItem() && !isPlayingAd)
.addIf(
COMMAND_SEEK_TO_PREVIOUS,
!currentTimeline.isEmpty
&& (hasPreviousWindow() || !isCurrentWindowLive || isCurrentWindowSeekable)
&& (hasPreviousMediaItem() || !isCurrentMediaItemLive || isCurrentMediaItemSeekable)
&& !isPlayingAd
)
.addIf(COMMAND_SEEK_TO_NEXT_WINDOW, hasNextWindow() && !isPlayingAd)
.addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNextMediaItem() && !isPlayingAd)
.addIf(
COMMAND_SEEK_TO_NEXT,
!currentTimeline.isEmpty()
&& (hasNextWindow() || (isCurrentWindowLive && isCurrentWindowDynamic()))
!currentTimeline.isEmpty
&& (hasNextMediaItem() || (isCurrentMediaItemLive && isCurrentMediaItemDynamic))
&& !isPlayingAd
)
.addIf(COMMAND_SEEK_TO_WINDOW, !isPlayingAd)
.addIf(COMMAND_SEEK_BACK, isCurrentWindowSeekable && !isPlayingAd)
.addIf(COMMAND_SEEK_FORWARD, isCurrentWindowSeekable && !isPlayingAd)
.addIf(COMMAND_SEEK_TO_MEDIA_ITEM, !isPlayingAd)
.addIf(COMMAND_SEEK_BACK, isCurrentMediaItemSeekable && !isPlayingAd)
.addIf(COMMAND_SEEK_FORWARD, isCurrentMediaItemSeekable && !isPlayingAd)
.build()
}
private fun resetInternalState() {
isPlayerReady = false
isSeekable = false
@ -686,8 +680,7 @@ class MPVPlayer(
currentPositionMs = null
currentDurationMs = null
currentCacheDurationMs = null
trackGroupArray = TrackGroupArray.EMPTY
trackSelectionArray = TrackSelectionArray()
tracksInfo = TracksInfo.EMPTY
playbackParameters = PlaybackParameters.DEFAULT
initialCommands.clear()
//initialSeekTo = 0L
@ -699,7 +692,7 @@ class MPVPlayer(
MPVLib.command(
arrayOf(
"loadfile",
"${mediaItem.playbackProperties?.uri}",
"${mediaItem.localConfiguration?.uri}",
"append"
)
)
@ -830,7 +823,7 @@ class MPVPlayer(
* `windowIndex` is not within the bounds of the current timeline.
*/
override fun seekTo(windowIndex: Int, positionMs: Long) {
if (windowIndex == currentWindowIndex) {
if (windowIndex == currentMediaItemIndex) {
val seekTo =
if (positionMs != C.TIME_UNSET) positionMs / C.MILLIS_PER_SECOND else initialSeekTo
initialSeekTo = if (isPlayerReady) {
@ -849,7 +842,7 @@ class MPVPlayer(
internalMediaItems?.get(index)?.let { mediaItem ->
internalMediaItem = mediaItem
resetInternalState()
mediaItem.playbackProperties?.subtitles?.forEach { subtitle ->
mediaItem.localConfiguration?.subtitleConfigurations?.forEach { subtitle ->
initialCommands.add(
arrayOf(
/* command= */ "sub-add",
@ -877,14 +870,14 @@ class MPVPlayer(
}
override fun getSeekBackIncrement(): Long {
return 5000
return C.DEFAULT_SEEK_BACK_INCREMENT_MS
}
override fun getSeekForwardIncrement(): Long {
return 15000
return C.DEFAULT_SEEK_FORWARD_INCREMENT_MS
}
override fun getMaxSeekToPreviousPosition(): Int {
override fun getMaxSeekToPreviousPosition(): Long {
return C.DEFAULT_MAX_SEEK_TO_PREVIOUS_POSITION_MS
}
@ -913,6 +906,11 @@ class MPVPlayer(
return playbackParameters
}
override fun stop() {
MPVLib.command(arrayOf("stop", "keep-playlist"))
}
@Deprecated("Deprecated in Java")
override fun stop(reset: Boolean) {
MPVLib.command(arrayOf("stop", "keep-playlist"))
}
@ -936,8 +934,9 @@ class MPVPlayer(
*
* @see com.google.android.exoplayer2.Player.Listener.onTracksChanged
*/
@Deprecated("Deprecated in Java")
override fun getCurrentTrackGroups(): TrackGroupArray {
return trackGroupArray
return TrackGroupArray.EMPTY
}
/**
@ -950,27 +949,21 @@ class MPVPlayer(
*
* @see com.google.android.exoplayer2.Player.Listener.onTracksChanged
*/
@Deprecated("Deprecated in Java")
override fun getCurrentTrackSelections(): TrackSelectionArray {
return trackSelectionArray
return TrackSelectionArray()
}
/**
* Returns the current static metadata for the track selections.
*
*
* The returned `metadataList` is an immutable list of [Metadata] instances, where
* the elements correspond to the [current track selections][.getCurrentTrackSelections],
* or an empty list if there are no track selections or the selected tracks contain no static
* metadata.
*
*
* This metadata is considered static in that it comes from the tracks' declared Formats,
* rather than being timed (or dynamic) metadata, which is represented within a metadata track.
*
* @see com.google.android.exoplayer2.Player.Listener.onStaticMetadataChanged
*/
override fun getCurrentStaticMetadata(): List<Metadata> {
return emptyList()
override fun getCurrentTracksInfo(): TracksInfo {
return tracksInfo
}
override fun getTrackSelectionParameters(): TrackSelectionParameters {
TODO("Not yet implemented")
}
override fun setTrackSelectionParameters(parameters: TrackSelectionParameters) {
TODO("Not yet implemented")
}
/**
@ -979,7 +972,7 @@ class MPVPlayer(
*
*
* This [MediaMetadata] is a combination of the [MediaItem.mediaMetadata] and the
* static and dynamic metadata sourced from [com.google.android.exoplayer2.Player.Listener.onStaticMetadataChanged] and
* static and dynamic metadata sourced from [com.google.android.exoplayer2.Player.Listener.onMediaMetadataChanged] and
* [com.google.android.exoplayer2.metadata.MetadataOutput.onMetadata].
*/
override fun getMediaMetadata(): MediaMetadata {
@ -1005,14 +998,10 @@ class MPVPlayer(
/** Returns the index of the period currently being played. */
override fun getCurrentPeriodIndex(): Int {
return currentWindowIndex
return currentMediaItemIndex
}
/**
* Returns the index of the current [window][Timeline.Window] in the [ ][.getCurrentTimeline], or the prospective window index if the [ ][.getCurrentTimeline] is empty.
*/
override fun getCurrentWindowIndex(): Int {
override fun getCurrentMediaItemIndex(): Int {
return currentIndex
}
@ -1020,7 +1009,7 @@ class MPVPlayer(
* Returns the duration of the current content window or ad in milliseconds, or [ ][com.google.android.exoplayer2.C.TIME_UNSET] if the duration is not known.
*/
override fun getDuration(): Long {
return timeline.getWindow(currentWindowIndex, window).durationMs
return timeline.getWindow(currentMediaItemIndex, window).durationMs
}
/**
@ -1272,7 +1261,7 @@ class MPVPlayer(
throw IllegalArgumentException("You should use global volume controls. Check out AUDIO_SERVICE.")
}
private class CurrentTrackSelection(
/*private class CurrentTrackSelection(
private val currentTrackGroup: TrackGroup,
private val index: Int
) : TrackSelection {
@ -1342,7 +1331,7 @@ class MPVPlayer(
override fun indexOf(indexInTrackGroup: Int): Int {
return indexInTrackGroup
}
}
}*/
companion object {
/**
@ -1350,10 +1339,9 @@ class MPVPlayer(
*/
private const val AUDIO_FOCUS_DUCKING = 0.5f
private val permanentAvailableCommands: Player.Commands = Player.Commands.Builder()
private val permanentAvailableCommands: Commands = Commands.Builder()
.addAll(
COMMAND_PLAY_PAUSE,
COMMAND_PREPARE_STOP,
COMMAND_SET_SPEED_AND_PITCH,
COMMAND_GET_CURRENT_MEDIA_ITEM,
COMMAND_GET_MEDIA_ITEMS_METADATA,
@ -1389,7 +1377,12 @@ class MPVPlayer(
* @param width The new width of the surface.
* @param height The new height of the surface.
*/
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
MPVLib.setPropertyString("android-surface-size", "${width}x$height")
}
@ -1429,7 +1422,7 @@ class MPVPlayer(
val width: Int?,
val height: Int?
) : Parcelable {
fun toFormat() : Format {
fun toFormat(): Format {
return Format.Builder()
.setId(id)
.setContainerMimeType("$mimeType/$codec")
@ -1439,6 +1432,7 @@ class MPVPlayer(
.setHeight(height ?: Format.NO_VALUE)
.build()
}
companion object {
fun fromJSON(json: JSONObject): Track {
return Track(
@ -1458,10 +1452,10 @@ class MPVPlayer(
}
}
private fun getMPVTracks(trackList: String) : Triple<List<Track> ,TrackGroupArray, TrackSelectionArray> {
private fun getMPVTracks(trackList: String): Pair<List<Track>, TracksInfo> {
val tracks = mutableListOf<Track>()
var trackGroupArray = TrackGroupArray.EMPTY
var trackSelectionArray = TrackSelectionArray()
var tracksInfo = TracksInfo.EMPTY
val trackGroupInfos = mutableListOf<TracksInfo.TrackGroupInfo>()
val trackListVideo = mutableListOf<Format>()
val trackListAudio = mutableListOf<Format>()
@ -1519,32 +1513,42 @@ class MPVPlayer(
tracks.remove(emptyTrack)
trackListText.removeFirst()
}
val trackGroups = mutableListOf<TrackGroup>()
val trackSelections = mutableListOf<TrackSelection>()
if (trackListVideo.isNotEmpty()) {
with(TrackGroup(*trackListVideo.toTypedArray())) {
trackGroups.add(this)
trackSelections.add(CurrentTrackSelection(this, indexCurrentVideo))
TracksInfo.TrackGroupInfo(
this,
intArrayOf(C.FORMAT_HANDLED),
C.TRACK_TYPE_VIDEO,
BooleanArray(this.length) { it == indexCurrentVideo }
)
}
}
if (trackListAudio.isNotEmpty()) {
with(TrackGroup(*trackListAudio.toTypedArray())) {
trackGroups.add(this)
trackSelections.add(CurrentTrackSelection(this, indexCurrentAudio))
TracksInfo.TrackGroupInfo(
this,
IntArray(this.length) { C.FORMAT_HANDLED },
C.TRACK_TYPE_AUDIO,
BooleanArray(this.length) { it == indexCurrentAudio }
)
}
}
if (trackListText.isNotEmpty()) {
with(TrackGroup(*trackListText.toTypedArray())) {
trackGroups.add(this)
trackSelections.add(CurrentTrackSelection(this, indexCurrentText))
TracksInfo.TrackGroupInfo(
this,
IntArray(this.length) { C.FORMAT_HANDLED },
C.TRACK_TYPE_TEXT,
BooleanArray(this.length) { it == indexCurrentText }
)
}
}
if (trackGroups.isNotEmpty()) {
trackGroupArray = TrackGroupArray(*trackGroups.toTypedArray())
trackSelectionArray = TrackSelectionArray(*trackSelections.toTypedArray())
if (trackGroupInfos.isNotEmpty()) {
tracksInfo = TracksInfo(trackGroupInfos)
}
} catch (e: JSONException) {}
return Triple(tracks, trackGroupArray, trackSelectionArray)
} catch (e: JSONException) {
}
return Pair(tracks, tracksInfo)
}
/**
@ -1558,16 +1562,16 @@ class MPVPlayer(
return when {
subtitleSources.isEmpty() -> videoSource
else -> {
val subtitles = mutableListOf<MediaItem.Subtitle>()
val subtitleConfigurations = mutableListOf<MediaItem.SubtitleConfiguration>()
subtitleSources.forEach { subtitleSource ->
subtitleSource.mediaItem.playbackProperties?.subtitles?.forEach { subtitle ->
subtitles.add(subtitle)
subtitleSource.mediaItem.localConfiguration?.subtitleConfigurations?.forEach { subtitle ->
subtitleConfigurations.add(subtitle)
}
}
ProgressiveMediaSource.Factory(dataSource)
.createMediaSource(
videoSource.mediaItem.buildUpon()
.setSubtitles(subtitles).build()
.setSubtitleConfigurations(subtitleConfigurations).build()
)
}
}

View file

@ -8,12 +8,10 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import com.google.android.exoplayer2.BasePlayer
import com.google.android.exoplayer2.DefaultRenderersFactory
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.jdtech.jellyfin.database.DownloadDatabaseDao
@ -36,7 +34,7 @@ constructor(
private val jellyfinRepository: JellyfinRepository,
private val downloadDatabase: DownloadDatabaseDao
) : ViewModel(), Player.Listener {
val player: BasePlayer
val player: Player
private val _navigateBack = MutableLiveData<Boolean>()
val navigateBack: LiveData<Boolean> = _navigateBack
@ -55,7 +53,7 @@ constructor(
val trackSelector = DefaultTrackSelector(application)
var playWhenReady = true
private var playFromDownloads = false
private var currentWindow = 0
private var currentMediaItemIndex = 0
private var playbackPosition: Long = 0
var playbackSpeed: Float = 1f
@ -90,7 +88,7 @@ constructor(
.setPreferredAudioLanguage(preferredAudioLanguage)
.setPreferredTextLanguage(preferredSubtitleLanguage)
)
player = SimpleExoPlayer.Builder(application, renderersFactory)
player = ExoPlayer.Builder(application, renderersFactory)
.setTrackSelector(trackSelector)
.build()
}
@ -124,7 +122,7 @@ constructor(
Timber.e(e)
}
player.setMediaItems(mediaItems, currentWindow, items[0].playbackPosition)
player.setMediaItems(mediaItems, currentMediaItemIndex, items[0].playbackPosition)
val useMpv = sp.getBoolean("mpv_player", false)
if(!useMpv || !playFromDownloads)
player.prepare() //TODO: This line causes a crash when playing from downloads with MPV
@ -149,12 +147,12 @@ constructor(
playWhenReady = player.playWhenReady
playbackPosition = player.currentPosition
currentWindow = player.currentWindowIndex
currentMediaItemIndex = player.currentMediaItemIndex
player.removeListener(this)
player.release()
}
private fun pollPosition(player: BasePlayer) {
private fun pollPosition(player: Player) {
val handler = Handler(Looper.getMainLooper())
val runnable = object : Runnable {
override fun run() {

View file

@ -9,10 +9,8 @@ import dev.jdtech.jellyfin.models.PlayerItem
import dev.jdtech.jellyfin.repository.JellyfinRepository
import dev.jdtech.jellyfin.utils.getDownloadPlayerItem
import dev.jdtech.jellyfin.utils.isItemAvailable
import dev.jdtech.jellyfin.utils.isItemDownloaded
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.ItemFields