mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-28 03:43:02 +00:00
test: libass overlay test
This commit is contained in:
parent
10b0f634f0
commit
88226ba127
3 changed files with 79 additions and 5 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
4
composeApp/src/androidMain/res/values/ids.xml
Normal file
4
composeApp/src/androidMain/res/values/ids.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<item name="libass_overlay_bound_player" type="id" />
|
||||
</resources>
|
||||
Loading…
Reference in a new issue