test: libass overlay test

This commit is contained in:
tapframe 2026-04-10 14:31:36 +05:30
parent 10b0f634f0
commit 88226ba127
3 changed files with 79 additions and 5 deletions

View file

@ -45,6 +45,9 @@ import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import androidx.media3.ui.SubtitleView
import androidx.media3.ui.CaptionStyleCompat
import com.nuvio.app.R
import io.github.peerless2012.ass.media.kt.withAssSupport
import io.github.peerless2012.ass.media.widget.AssSubtitleView
import kotlinx.coroutines.delay
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -90,6 +93,10 @@ actual fun PlatformPlayerSurface(
val sanitizedSourceResponseHeaders = remember(sourceResponseHeaders) {
sanitizePlaybackResponseHeaders(sourceResponseHeaders)
}
val useLibass = playerSettings.useLibass
val libassRenderType = runCatching {
LibassRenderType.valueOf(playerSettings.libassRenderType)
}.getOrDefault(LibassRenderType.CUES)
val exoPlayer = remember(sourceUrl, sourceAudioUrl, sanitizedSourceHeaders, sanitizedSourceResponseHeaders) {
val renderersFactory = DefaultRenderersFactory(context)
@ -126,11 +133,6 @@ actual fun PlatformPlayerSurface(
useYoutubeChunkedPlayback = useYoutubeChunkedPlayback,
)
val useLibass = playerSettings.useLibass
val libassRenderType = runCatching {
LibassRenderType.valueOf(playerSettings.libassRenderType)
}.getOrDefault(LibassRenderType.CUES)
val player = if (useLibass) {
ExoPlayer.Builder(context)
.setTrackSelector(trackSelector)
@ -418,6 +420,11 @@ actual fun PlatformPlayerSurface(
this.resizeMode = resizeMode.toExoResizeMode()
setShutterBackgroundColor(android.graphics.Color.BLACK)
playerViewRef = this
syncLibassOverlay(
player = exoPlayer,
enabled = useLibass,
renderType = libassRenderType,
)
applySubtitleStyle(currentSubtitleStyle)
}
},
@ -426,6 +433,11 @@ actual fun PlatformPlayerSurface(
playerView.useController = useNativeController
playerView.resizeMode = resizeMode.toExoResizeMode()
playerViewRef = playerView
playerView.syncLibassOverlay(
player = exoPlayer,
enabled = useLibass,
renderType = libassRenderType,
)
playerView.applySubtitleStyle(currentSubtitleStyle)
},
)
@ -456,6 +468,56 @@ private fun PlayerResizeMode.toExoResizeMode(): Int =
PlayerResizeMode.Zoom -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM
}
private fun PlayerView.syncLibassOverlay(
player: ExoPlayer,
enabled: Boolean,
renderType: LibassRenderType,
) {
val subtitleView = subtitleView ?: return
val needsOverlay = enabled && renderType.usesOverlaySubtitleView()
val boundPlayer = getTag(R.id.libass_overlay_bound_player) as? ExoPlayer
val hasOverlayChild = subtitleView.hasAssOverlayChild()
if (!needsOverlay) {
if (hasOverlayChild) {
subtitleView.removeAssOverlayChildren()
}
if (boundPlayer != null) {
setTag(R.id.libass_overlay_bound_player, null)
}
return
}
val assHandler = player.getAssHandlerCompat() ?: return
if (boundPlayer === player && hasOverlayChild) {
return
}
subtitleView.removeAssOverlayChildren()
subtitleView.withAssSupport(assHandler)
setTag(R.id.libass_overlay_bound_player, player)
}
private fun LibassRenderType.usesOverlaySubtitleView(): Boolean =
this == LibassRenderType.OVERLAY_CANVAS || this == LibassRenderType.OVERLAY_OPEN_GL
private fun SubtitleView.hasAssOverlayChild(): Boolean {
for (index in 0 until childCount) {
if (getChildAt(index) is AssSubtitleView) {
return true
}
}
return false
}
private fun SubtitleView.removeAssOverlayChildren() {
for (index in childCount - 1 downTo 0) {
if (getChildAt(index) is AssSubtitleView) {
removeViewAt(index)
}
}
}
private fun PlayerView.applySubtitleStyle(style: SubtitleStyleState) {
subtitleView?.apply {
val baseBottomPaddingFraction = SubtitleView.DEFAULT_BOTTOM_PADDING_FRACTION * 2f / 3f

View file

@ -20,6 +20,10 @@ import io.github.peerless2012.ass.media.extractor.AssMatroskaExtractor
import io.github.peerless2012.ass.media.kt.withAssSupport
import io.github.peerless2012.ass.media.parser.AssSubtitleParserFactory
import io.github.peerless2012.ass.media.type.AssRenderType
import java.util.Collections
import java.util.WeakHashMap
private val assHandlersByPlayer = Collections.synchronizedMap(WeakHashMap<ExoPlayer, AssHandler>())
@OptIn(UnstableApi::class)
internal fun ExoPlayer.Builder.buildWithAssSupportCompat(
@ -47,10 +51,14 @@ internal fun ExoPlayer.Builder.buildWithAssSupportCompat(
.setRenderersFactory(renderersFactory.withAssSupport(assHandler))
.build()
assHandlersByPlayer[player] = assHandler
assHandler.init(player)
return player
}
internal fun ExoPlayer.getAssHandlerCompat(): AssHandler? = assHandlersByPlayer[this]
@OptIn(UnstableApi::class)
private class CompatAssSubtitleParserFactory(
private val assHandler: AssHandler

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="libass_overlay_bound_player" type="id" />
</resources>