Skip to content

Commit

Permalink
Add simple api to setup the thumbnail seeking
Browse files Browse the repository at this point in the history
  • Loading branch information
StaehliJ committed Nov 1, 2024
1 parent a65fb70 commit e83acb8
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,13 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import androidx.media3.common.C
import androidx.media3.exoplayer.image.ImageOutput
import ch.srgssr.pillarbox.core.business.PillarboxExoPlayer
import ch.srgssr.pillarbox.core.business.SRGMediaItem
import ch.srgssr.pillarbox.demo.shared.data.DemoItem
import ch.srgssr.pillarbox.player.PillarboxExoPlayer
import ch.srgssr.pillarbox.ui.ProgressTrackerState
import ch.srgssr.pillarbox.ui.SimpleProgressTrackerState
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
import kotlin.time.Duration
import ch.srgssr.pillarbox.ui.SmoothProgressTrackerState

/**
* A ViewModel to demonstrate how to work with Image track.
Expand All @@ -42,7 +38,7 @@ class ThumbnailViewModel(application: Application) : AndroidViewModel(applicatio
/**
* Progress tracker state
*/
val progressTrackerState: ProgressTrackerState = ThumbnailProgressTracker(player, viewModelScope, this)
val progressTrackerState: ProgressTrackerState = SmoothProgressTrackerState(player, viewModelScope, this)

init {
player.prepare()
Expand All @@ -63,54 +59,4 @@ class ThumbnailViewModel(application: Application) : AndroidViewModel(applicatio
override fun onDisabled() {
_thumbnail.value = null
}

/**
* Thumbnail progress tracker
* FIXME create a real progress tracker in pillarbox-ui
*/
internal class ThumbnailProgressTracker(
private val player: PillarboxExoPlayer,
coroutineScope: CoroutineScope,
private val imageOutput: ImageOutput,
) : ProgressTrackerState {
private var storedSeekParameters = player.seekParameters
private var storedPlayWhenReady = player.playWhenReady
private var storedSmoothSeeking = player.smoothSeekingEnabled
private var storedTrackSelectionParameters = player.trackSelectionParameters
private val simpleProgressTrackerState = SimpleProgressTrackerState(player, coroutineScope)
private var startChanging = false
override val progress: StateFlow<Duration> = simpleProgressTrackerState.progress

override fun onChanged(progress: Duration) {
simpleProgressTrackerState.onChanged(progress)
if (!startChanging) {
startChanging = true
storedPlayWhenReady = player.playWhenReady
storedSmoothSeeking = player.smoothSeekingEnabled
storedSeekParameters = player.seekParameters
storedTrackSelectionParameters = player.trackSelectionParameters
player.smoothSeekingEnabled = true
player.playWhenReady = false
player.trackSelectionParameters = player.trackSelectionParameters.buildUpon()
.setPreferredVideoRoleFlags(C.ROLE_FLAG_TRICK_PLAY)
.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true)
.setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, true)
.setTrackTypeDisabled(C.TRACK_TYPE_METADATA, true)
.setPrioritizeImageOverVideoEnabled(true)
.build()
player.setImageOutput(imageOutput)
}
player.seekTo(progress.inWholeMilliseconds)
}

override fun onFinished() {
startChanging = false
simpleProgressTrackerState.onFinished()
player.trackSelectionParameters = storedTrackSelectionParameters
player.smoothSeekingEnabled = storedSmoothSeeking
player.setSeekParameters(storedSeekParameters)
player.playWhenReady = storedPlayWhenReady
player.setImageOutput(null)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
package ch.srgssr.pillarbox.player.extension

import androidx.media3.common.C
import androidx.media3.common.Tracks
import ch.srgssr.pillarbox.player.asset.timeRange.BlockedTimeRange
import ch.srgssr.pillarbox.player.source.PillarboxMediaSource
Expand All @@ -27,3 +28,12 @@ fun Tracks.getBlockedTimeRangeOrNull(): List<BlockedTimeRange>? {
it.type == PillarboxMediaSource.TRACK_TYPE_PILLARBOX_BLOCKED
}?.getTrackFormat(0)?.customData as? List<BlockedTimeRange>
}

/**
* Contains image track
*
* @return true if there is a track of type [C.TRACK_TYPE_IMAGE], false otherwise
*/
fun Tracks.containsImageTrack(): Boolean {
return containsType(C.TRACK_TYPE_IMAGE)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import kotlin.time.Duration.Companion.milliseconds
* [Player] progress tracker that only updated the player's actual progress when [onFinished] is called.
*
* @param player The [Player] whose current position must be tracked.
* @param coroutineScope
* @param coroutineScope The [CoroutineScope] to state in the current progress.
*/
class SimpleProgressTrackerState(
private val player: Player,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ package ch.srgssr.pillarbox.ui
import androidx.media3.common.C
import androidx.media3.common.Player
import androidx.media3.exoplayer.SeekParameters
import androidx.media3.exoplayer.image.ImageOutput
import ch.srgssr.pillarbox.player.PillarboxExoPlayer
import ch.srgssr.pillarbox.player.extension.containsImageTrack
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
import kotlin.time.Duration
Expand All @@ -16,11 +18,13 @@ import kotlin.time.Duration
* [Player] progress tracker that updates the player's actual progress everytime that [onChanged] is called.
*
* @param player The [Player] whose current position must be tracked.
* @param coroutineScope
* @param coroutineScope The [CoroutineScope] to state in the current progress.
* @param imageOutput The [ImageOutput] to render the image track.
*/
class SmoothProgressTrackerState(
private val player: PillarboxExoPlayer,
coroutineScope: CoroutineScope
coroutineScope: CoroutineScope,
private val imageOutput: ImageOutput = ImageOutput.NO_OP,
) : ProgressTrackerState {
private var storedSeekParameters = player.seekParameters
private var storedPlayWhenReady = player.playWhenReady
Expand All @@ -41,13 +45,18 @@ class SmoothProgressTrackerState(
player.setSeekParameters(SeekParameters.CLOSEST_SYNC)
player.smoothSeekingEnabled = true
player.playWhenReady = false
player.trackSelectionParameters = player.trackSelectionParameters.buildUpon()
.setPreferredVideoRoleFlags(C.ROLE_FLAG_TRICK_PLAY)
.setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true)
.setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, true)
.setTrackTypeDisabled(C.TRACK_TYPE_METADATA, true)
.setTrackTypeDisabled(C.TRACK_TYPE_IMAGE, true)
.build()
player.trackSelectionParameters = player.trackSelectionParameters.buildUpon().apply {
setPreferredVideoRoleFlags(C.ROLE_FLAG_TRICK_PLAY)
setTrackTypeDisabled(C.TRACK_TYPE_TEXT, true)
setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, true)
setTrackTypeDisabled(C.TRACK_TYPE_METADATA, true)
if (player.currentTracks.containsImageTrack() && imageOutput != ImageOutput.NO_OP) {
setPrioritizeImageOverVideoEnabled(true)
} else {
setTrackTypeDisabled(C.TRACK_TYPE_IMAGE, true)
}
}.build()
player.setImageOutput(imageOutput)
}
player.seekTo(progress.inWholeMilliseconds)
}
Expand All @@ -59,5 +68,6 @@ class SmoothProgressTrackerState(
player.smoothSeekingEnabled = storedSmoothSeeking
player.setSeekParameters(storedSeekParameters)
player.playWhenReady = storedPlayWhenReady
player.setImageOutput(null)
}
}

0 comments on commit e83acb8

Please sign in to comment.