diff --git a/app/src/main/java/com/fluxa/app/ui/catalog/NativeLibassSubtitleOverlay.kt b/app/src/main/java/com/fluxa/app/ui/catalog/NativeLibassSubtitleOverlay.kt index fbaea01..46e5806 100644 --- a/app/src/main/java/com/fluxa/app/ui/catalog/NativeLibassSubtitleOverlay.kt +++ b/app/src/main/java/com/fluxa/app/ui/catalog/NativeLibassSubtitleOverlay.kt @@ -4,6 +4,7 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.Canvas import android.net.Uri +import android.os.SystemClock import android.util.Log import android.view.View import androidx.compose.runtime.Composable @@ -19,6 +20,7 @@ import androidx.media3.common.Player import androidx.media3.exoplayer.ExoPlayer import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.fluxa.app.player.ExternalSubtitleTrack +import com.fluxa.app.player.LibassDebugLog import com.fluxa.app.player.MediaPlayerController import com.fluxa.app.player.MediaTrack import com.fluxa.app.player.MkvNativeAssExtractor @@ -72,6 +74,10 @@ internal fun NativeLibassSubtitleOverlay( var localRenderer by remember { mutableStateOf(null) } LaunchedEffect(externalSubtitle?.url, embeddedSubtitle?.id) { + LibassDebugLog.d( + "overlay selection external=${externalSubtitle?.let { "${LibassDebugLog.urlSummary(it.url)} label=${it.label} lang=${it.language}" } ?: ""} " + + "embedded=${embeddedSubtitle?.let { "id=${it.id} label=${it.label} lang=${it.language} bytes=${it.assData.size} fonts=${it.fonts.size}" } ?: ""}" + ) val previous = localRenderer localRenderer = null previous?.close() @@ -83,19 +89,29 @@ internal fun NativeLibassSubtitleOverlay( fonts = embedded.fonts, fontsDir = context.filesDir.resolve("fonts").absolutePath ) - }.onFailure { e -> Log.w("NativeLibassOverlay", "Embedded renderer failed", e) }.getOrNull() + }.onFailure { e -> + Log.w("NativeLibassOverlay", "Embedded renderer failed", e) + LibassDebugLog.w("overlay embedded renderer failed id=${embedded.id}", e) + }.getOrNull() + LibassDebugLog.d("overlay embedded renderer ${if (localRenderer != null) "ready" else "not ready"} id=${embedded.id}") return@LaunchedEffect } val url = externalSubtitle?.url ?: return@LaunchedEffect localRenderer = runCatching { val data = fetchSubtitleBytes(context, url) + LibassDebugLog.d("overlay fetched external ASS bytes=${data.size} url=${LibassDebugLog.urlSummary(url)}") val fonts = MkvNativeAssExtractor.extractExternalFontHints(url) + LibassDebugLog.d("overlay external font hints fonts=${fonts.size} url=${LibassDebugLog.urlSummary(url)}") NativeLibassRenderer.create( assData = data, fonts = fonts, fontsDir = context.filesDir.resolve("fonts").absolutePath ) - }.onFailure { e -> Log.w("NativeLibassOverlay", "External renderer failed", e) }.getOrNull() + }.onFailure { e -> + Log.w("NativeLibassOverlay", "External renderer failed", e) + LibassDebugLog.w("overlay external renderer failed url=${LibassDebugLog.urlSummary(url)}", e) + }.getOrNull() + LibassDebugLog.d("overlay external renderer ${if (localRenderer != null) "ready" else "not ready"} url=${LibassDebugLog.urlSummary(url)}") } DisposableEffect(Unit) { @@ -106,9 +122,14 @@ internal fun NativeLibassSubtitleOverlay( } val activeRenderer = when { - embeddedSubtitle != null -> relayRenderer ?: localRenderer externalSubtitle != null -> localRenderer - else -> null + else -> relayRenderer ?: localRenderer + } + LaunchedEffect(activeRenderer, relayRenderer, localRenderer, externalSubtitle?.url, embeddedSubtitle?.id) { + LibassDebugLog.d( + "overlay activeRenderer=${activeRenderer != null} relayRenderer=${relayRenderer != null} localRenderer=${localRenderer != null} " + + "external=${externalSubtitle != null} embedded=${embeddedSubtitle != null}" + ) } AndroidView( @@ -133,6 +154,9 @@ private class NativeLibassSubtitleView(context: Context) : View(context) { var renderer: NativeLibassRenderer? = null set(value) { + if (field !== value) { + LibassDebugLog.d("overlay view renderer changed active=${value != null} view=${width}x$height attached=$isAttachedToWindow") + } field = value if (isAttachedToWindow) postInvalidateOnAnimation() } @@ -144,6 +168,8 @@ private class NativeLibassSubtitleView(context: Context) : View(context) { } private var bitmap: Bitmap? = null + private var lastDrawLogMs = 0L + private var lastDrawHadPixels: Boolean? = null private val playerListener = object : Player.Listener { override fun onIsPlayingChanged(isPlaying: Boolean) { @@ -161,12 +187,14 @@ private class NativeLibassSubtitleView(context: Context) : View(context) { override fun onAttachedToWindow() { super.onAttachedToWindow() + LibassDebugLog.d("overlay view attached size=${width}x$height") player?.addListener(playerListener) postInvalidateOnAnimation() } override fun onDetachedFromWindow() { super.onDetachedFromWindow() + LibassDebugLog.d("overlay view detached") player?.removeListener(playerListener) bitmap?.recycle() bitmap = null @@ -186,6 +214,15 @@ private class NativeLibassSubtitleView(context: Context) : View(context) { val result = activeRenderer.render(activePlayer.currentPosition + subtitleDelayMs, targetBitmap) if (result > 0) canvas.drawBitmap(targetBitmap, 0f, 0f, null) + val hasPixels = result > 0 + val now = SystemClock.elapsedRealtime() + if (lastDrawHadPixels != hasPixels || now - lastDrawLogMs > 1_500L) { + LibassDebugLog.d( + "overlay draw positionMs=${activePlayer.currentPosition} delayMs=$subtitleDelayMs size=${width}x$height result=$result hasPixels=$hasPixels playing=${activePlayer.isPlaying} playWhenReady=${activePlayer.playWhenReady}" + ) + lastDrawHadPixels = hasPixels + lastDrawLogMs = now + } if (activePlayer.isPlaying || activePlayer.playWhenReady) { if (result == 0) postInvalidateDelayed(100) else postInvalidateOnAnimation()