From 7ab39eba579ba1c89e3c4e4b026b440781286fbc Mon Sep 17 00:00:00 2001 From: damontecres <154766448+damontecres@users.noreply.github.com> Date: Sun, 14 Dec 2025 19:04:01 -0500 Subject: [PATCH] Improve trickplay image preview speed (#467) Moves the clipping of trickplay images from the image loading layer to the composition/graphics layer. Effectively, this PR loads and renders the entire trickplay image which is then moved around to the right position and finally is clipped so only a single tile is shown. Since moving the image around on screen plsu clipping is 1) very fast and 2) done during recompositions, this means it is _much_ faster at rendering each trickplay tile image and Coil only has to load the image once. Fixes #432 --- .../wholphin/ui/data/ItemDetailsDialogInfo.kt | 2 + .../wholphin/ui/playback/PlaybackOverlay.kt | 8 +- .../wholphin/ui/playback/PlaybackViewModel.kt | 12 +- .../wholphin/ui/playback/SeekPreviewImage.kt | 105 +++++++++++------- 4 files changed, 77 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt index 32dc213d..4947fda6 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/data/ItemDetailsDialogInfo.kt @@ -53,6 +53,7 @@ fun ItemDetailsDialog( val audioLabel = stringResource(R.string.audio) val subtitleLabel = stringResource(R.string.subtitle) val bitrateLabel = stringResource(R.string.bitrate) + val unknown = stringResource(R.string.unknown) ScrollableDialog( onDismissRequest = onDismissRequest, @@ -100,6 +101,7 @@ fun ItemDetailsDialog( source.container?.let { add(containerLabel to it) } if (showFilePath) { source.path?.let { add(pathLabel to it) } + add("ID" to (source.id ?: unknown)) } source.size?.let { add(fileSizeLabel to formatBytes(it)) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt index eefc176b..2200b954 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackOverlay.kt @@ -398,17 +398,13 @@ fun PlaybackOverlay( val tilesPerImage = trickplayInfo.tileWidth * trickplayInfo.tileHeight val index = (seekProgressMs / trickplayInfo.interval).toInt() / tilesPerImage - val imageUrl = trickplayUrlFor(index) + val imageUrl = remember(index) { trickplayUrlFor(index) } if (imageUrl != null) { SeekPreviewImage( - modifier = - Modifier, + modifier = Modifier, previewImageUrl = imageUrl, - duration = playerControls.duration, seekProgressMs = seekProgressMs, - videoWidth = trickplayInfo.width, - videoHeight = trickplayInfo.height, trickPlayInfo = trickplayInfo, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt index 524bcf03..88536176 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt @@ -411,7 +411,11 @@ class PlaybackViewModel trickPlayInfo?.let { trickplayInfo -> mediaSource.runTimeTicks?.ticks?.let { duration -> viewModelScope.launchIO { - prefetchTrickplay(duration, trickplayInfo) + prefetchTrickplay( + duration, + trickplayInfo, + mediaSource.id?.toUUIDOrNull(), + ) } } } @@ -737,16 +741,18 @@ class PlaybackViewModel private suspend fun prefetchTrickplay( duration: Duration, trickplayInfo: TrickplayInfo, + mediaSourceId: UUID?, ) { val tilesPerImage = trickplayInfo.tileWidth * trickplayInfo.tileHeight val totalCount = (duration.inWholeMilliseconds / trickplayInfo.interval).toInt() / tilesPerImage + 1 (0..