From 81bac6ee9b618807371c60e317fc7c8107133470 Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:01:40 +0200 Subject: [PATCH] fix(exoplayer): libass performance --- android/app/build.gradle.kts | 2 +- .../edde746/plezy/exoplayer/ExoPlayerCore.kt | 34 +++++++++++++------ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 541d66be..21ce0bb6 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -23,7 +23,7 @@ val downloadLibmpv by tasks.registering { } } -val assVersion = "safety-2" +val assVersion = "fp-2" val assDir = layout.buildDirectory.dir("libass").get().asFile val assAars = listOf("lib_ass-release.aar", "lib_ass_kt-release.aar", "lib_ass_media-release.aar") diff --git a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt index 62cc1147..0327714b 100644 --- a/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt +++ b/android/app/src/main/kotlin/com/edde746/plezy/exoplayer/ExoPlayerCore.kt @@ -57,10 +57,9 @@ import com.edde746.plezy.shared.FlutterOverlayHelper import com.edde746.plezy.shared.FrameRateManager import io.github.peerless2012.ass.media.AssHandler -import io.github.peerless2012.ass.media.factory.AssRenderersFactory import io.github.peerless2012.ass.media.parser.AssSubtitleParserFactory import io.github.peerless2012.ass.media.type.AssRenderType -import io.github.peerless2012.ass.media.widget.AssSubtitleView +import io.github.peerless2012.ass.media.widget.AssSubtitleSurfaceView interface ExoPlayerDelegate : com.edde746.plezy.shared.PlayerDelegate { @@ -426,12 +425,10 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener { val mediaSourceFactory = DefaultMediaSourceFactory(dataSourceFactory!!, wrappedExtractorsFactory) .setSubtitleParserFactory(assParserFactory) - val assRenderersFactory = AssRenderersFactory(handler, renderersFactory) - // Wrap text renderers with subtitle delay support val wrappedRenderersFactory = RenderersFactory { eventHandler, videoListener, audioListener, textOutput, metadataOutput -> - assRenderersFactory.createRenderers(eventHandler, videoListener, audioListener, textOutput, metadataOutput) + renderersFactory.createRenderers(eventHandler, videoListener, audioListener, textOutput, metadataOutput) .map { if (it.trackType == C.TRACK_TYPE_TEXT) SubtitleDelayRenderer(it, subtitleDelayUs) else it } .toTypedArray() } @@ -474,13 +471,29 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener { .setRenderersFactory(wrappedRenderersFactory) .build() - // Add ASS overlay view to SubtitleView for OVERLAY modes + // Add ASS overlay view to SubtitleView for OVERLAY modes. + // We use AssSubtitleSurfaceView directly (not AssSubtitleView) so we get a + // SurfaceFlinger-layer-backed overlay that eglPresentationTimeANDROID can + // vsync-pin. Z-order: default video SurfaceView < this MediaOverlay-flagged + // SurfaceView < Flutter TextureView in the window. + var assSubtitleSurfaceView: AssSubtitleSurfaceView? = null subtitleView?.let { sv -> - val assView = AssSubtitleView(sv.context, handler) - sv.addView(assView) + val assView = AssSubtitleSurfaceView(sv.context, handler) + assSubtitleSurfaceView = assView + sv.addView( + assView, + FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ) + ) } - // Initialize handler (registers as Player.Listener, creates Handler) + // Initialize handler (registers as Player.Listener, creates Handler). + // AssHandler.init calls player.setVideoFrameMetadataListener internally, but + // our own setVideoFrameMetadataListener below would overwrite it (ExoPlayer + // only keeps one listener). Skip AssHandler's wiring and invoke + // assView.requestRender directly from the listener below. handler.init(exoPlayer!!) // Suppress ass-media GL thread crash when EGL init partially fails (e.g. Tegra). @@ -502,7 +515,8 @@ class ExoPlayerCore(private val activity: Activity) : Player.Listener { exoPlayer!!.addListener(this) exoPlayer!!.addAnalyticsListener(decoderHangListener) - exoPlayer!!.setVideoFrameMetadataListener { presentationTimeUs, _, _, _ -> + exoPlayer!!.setVideoFrameMetadataListener { presentationTimeUs, releaseTimeNs, _, _ -> + assSubtitleSurfaceView?.requestRender(presentationTimeUs, releaseTimeNs) val count = fpsTimestampCount if (count < FPS_SAMPLE_COUNT) { fpsTimestamps[count] = presentationTimeUs