Skip to content

Commit

Permalink
Add thumbnail demo
Browse files Browse the repository at this point in the history
  • Loading branch information
StaehliJ committed Oct 31, 2024
1 parent bba7709 commit bd0560e
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,7 @@ sealed interface NavigationRoutes {

@Serializable
data object CountdownShowcase : NavigationRoutes

@Serializable
data object ThumbnailShowcase : NavigationRoutes
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ fun ShowcasesHome(navController: NavController) {
modifier = itemModifier,
onClick = { navController.navigate(NavigationRoutes.Chapters) }
)
HorizontalDivider()

DemoListItemView(
title = stringResource(R.string.thumbnails),
modifier = itemModifier,
onClick = { navController.navigate(NavigationRoutes.ThumbnailShowcase) }
)
}

DemoListHeaderView(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ch.srgssr.pillarbox.demo.ui.showcases.integrations.ExoPlayerShowcase
import ch.srgssr.pillarbox.demo.ui.showcases.layouts.ChapterShowcase
import ch.srgssr.pillarbox.demo.ui.showcases.layouts.SimpleLayoutShowcase
import ch.srgssr.pillarbox.demo.ui.showcases.layouts.StoryLayoutShowcase
import ch.srgssr.pillarbox.demo.ui.showcases.layouts.thumbnail.ThumbnailView
import ch.srgssr.pillarbox.demo.ui.showcases.misc.ContentNotYetAvailable
import ch.srgssr.pillarbox.demo.ui.showcases.misc.MultiPlayerShowcase
import ch.srgssr.pillarbox.demo.ui.showcases.misc.ResizablePlayerShowcase
Expand Down Expand Up @@ -67,10 +68,12 @@ fun NavGraphBuilder.showcasesNavGraph(navController: NavController) {
composable<NavigationRoutes.Chapters>(DemoPageView("Chapters", Levels)) {
ChapterShowcase()
}

composable<NavigationRoutes.CountdownShowcase>(DemoPageView("CountdownShowcase", Levels)) {
ContentNotYetAvailable()
}
composable<NavigationRoutes.ThumbnailShowcase>(DemoPageView("CountdownShowcase", Levels)) {
ThumbnailView()
}
}

private val Levels = listOf("app", "pillarbox", "showcase")
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) SRG SSR. All rights reserved.
* License information is available from the LICENSE file.
*/
package ch.srgssr.pillarbox.demo.ui.showcases.layouts.thumbnail

import android.graphics.Bitmap
import androidx.compose.foundation.Image
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.viewmodel.compose.viewModel
import ch.srgssr.pillarbox.demo.ui.player.controls.PlayerControls
import ch.srgssr.pillarbox.ui.widget.player.PlayerSurface

/**
* Thumbnail view
*/
@Composable
fun ThumbnailView() {
val thumbnailViewModel = viewModel<ThumbnailViewModel>()
val player = thumbnailViewModel.player
LifecycleResumeEffect(Unit) {
player.play()
onPauseOrDispose {
player.pause()
}
}

Box {
PlayerSurface(player) {
val thumbnail: Bitmap? by thumbnailViewModel.thumbnail
thumbnail?.let {
Image(bitmap = it.asImageBitmap(), contentDescription = null, modifier = Modifier.fillMaxSize())
}
}
val interactionSource = remember { MutableInteractionSource() }
PlayerControls(
modifier = Modifier.matchParentSize(),
player = player,
progressTracker = thumbnailViewModel.progressTrackerState,
interactionSource = interactionSource
) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright (c) SRG SSR. All rights reserved.
* License information is available from the LICENSE file.
*/
package ch.srgssr.pillarbox.demo.ui.showcases.layouts.thumbnail

import android.app.Application
import android.graphics.Bitmap
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

/**
* A ViewModel to demonstrate how to work with Image track.
*
* @param application The [Application].
*/
class ThumbnailViewModel(application: Application) : AndroidViewModel(application), ImageOutput {
/**
* Player
*/
val player = PillarboxExoPlayer(application)
private val _thumbnail = mutableStateOf<Bitmap?>(null)

/**
* Thumbnail
*/
val thumbnail: State<Bitmap?> = _thumbnail

/**
* Progress tracker state
*/
val progressTrackerState: ProgressTrackerState = ThumbnailProgressTracker(player, viewModelScope, this)

init {
player.prepare()
player.addMediaItem(SRGMediaItem("urn:srf:video:881be9c2-65ec-4fa9-ba4a-926d15d046ef"))
player.addMediaItem(DemoItem.OnDemandHorizontalVideo.toMediaItem())
player.addMediaItem(DemoItem.UnifiedStreamingOnDemand_Dash_TiledThumbnails.toMediaItem())
player.addMediaItem(DemoItem.UnifiedStreamingOnDemand_Dash_TrickPlay.toMediaItem())
}

override fun onCleared() {
player.release()
}

override fun onImageAvailable(presentationTimeUs: Long, bitmap: Bitmap) {
_thumbnail.value = bitmap
}

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)
}
}
}
1 change: 1 addition & 0 deletions pillarbox-demo/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<string name="repeat_mode_all">all</string>
<string name="pause_end_media_items">Pause at end of media items</string>
<string name="chapters">Chapters</string>
<string name="thumbnails">Thumbnail</string>
<string name="settings_library_version">Library version</string>
<string name="settings_choose_text_color">Choose text color</string>
<string name="settings_choose_text_size">Choose text size</string>
Expand Down

0 comments on commit bd0560e

Please sign in to comment.