Improves performance of video loading and playback.

This commit is contained in:
Vitor Pamplona
2023-04-20 10:06:12 -04:00
parent 585bb57f64
commit 7ee3b8a196
3 changed files with 43 additions and 23 deletions

View File

@@ -18,7 +18,7 @@ object VideoCache {
lateinit var cacheDataSourceFactory: CacheDataSource.Factory lateinit var cacheDataSourceFactory: CacheDataSource.Factory
fun get(context: Context): CacheDataSource.Factory { fun init(context: Context) {
if (!this::simpleCache.isInitialized) { if (!this::simpleCache.isInitialized) {
exoDatabaseProvider = StandaloneDatabaseProvider(context) exoDatabaseProvider = StandaloneDatabaseProvider(context)
@@ -35,7 +35,9 @@ object VideoCache {
) )
.setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR) .setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
} }
}
fun get(): CacheDataSource.Factory {
return cacheDataSourceFactory return cacheDataSourceFactory
} }
} }

View File

@@ -19,6 +19,7 @@ import coil.decode.ImageDecoderDecoder
import coil.decode.SvgDecoder import coil.decode.SvgDecoder
import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.ServiceManager
import com.vitorpamplona.amethyst.VideoCache
import com.vitorpamplona.amethyst.service.nip19.Nip19 import com.vitorpamplona.amethyst.service.nip19.Nip19
import com.vitorpamplona.amethyst.service.relays.Client import com.vitorpamplona.amethyst.service.relays.Client
import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.navigation.Route
@@ -54,6 +55,9 @@ class MainActivity : FragmentActivity() {
null null
} }
// Initializes video cache.
VideoCache.init(this.applicationContext)
Coil.setImageLoader { Coil.setImageLoader {
ImageLoader.Builder(this).components { ImageLoader.Builder(this).components {
if (SDK_INT >= 28) { if (SDK_INT >= 28) {

View File

@@ -6,9 +6,13 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import com.google.android.exoplayer2.C import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.MediaItem import com.google.android.exoplayer2.MediaItem
@@ -21,19 +25,23 @@ import com.vitorpamplona.amethyst.VideoCache
@Composable @Composable
fun VideoView(videoUri: String, onDialog: ((Boolean) -> Unit)? = null) { fun VideoView(videoUri: String, onDialog: ((Boolean) -> Unit)? = null) {
val context = LocalContext.current val context = LocalContext.current
val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current)
val exoPlayer = remember { val exoPlayer = remember(videoUri) {
ExoPlayer.Builder(context).build().apply { ExoPlayer.Builder(context).build().apply {
repeatMode = Player.REPEAT_MODE_ALL repeatMode = Player.REPEAT_MODE_ALL
videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING videoScalingMode = C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING
setMediaSource( setMediaSource(
ProgressiveMediaSource.Factory(VideoCache.get(context.applicationContext)).createMediaSource(MediaItem.fromUri(videoUri)) ProgressiveMediaSource.Factory(VideoCache.get()).createMediaSource(MediaItem.fromUri(videoUri))
) )
prepare() prepare()
} }
} }
val playerView = remember { DisposableEffect(
AndroidView(
modifier = Modifier.fillMaxWidth(),
factory = {
StyledPlayerView(context).apply { StyledPlayerView(context).apply {
player = exoPlayer player = exoPlayer
layoutParams = FrameLayout.LayoutParams( layoutParams = FrameLayout.LayoutParams(
@@ -43,22 +51,28 @@ fun VideoView(videoUri: String, onDialog: ((Boolean) -> Unit)? = null) {
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH
onDialog?.let { innerOnDialog -> onDialog?.let { innerOnDialog ->
setFullscreenButtonClickListener { setFullscreenButtonClickListener {
exoPlayer.pause()
innerOnDialog(it) innerOnDialog(it)
} }
} }
} }
} }
)
) {
val observer = LifecycleEventObserver { _, event ->
when (event) {
Lifecycle.Event.ON_PAUSE -> {
exoPlayer.pause()
}
else -> {}
}
}
val lifecycle = lifecycleOwner.value.lifecycle
lifecycle.addObserver(observer)
DisposableEffect(exoPlayer) {
onDispose { onDispose {
exoPlayer.release() exoPlayer.release()
lifecycle.removeObserver(observer)
} }
} }
AndroidView(
modifier = Modifier.fillMaxWidth(),
factory = {
playerView
}
)
} }