Apply the subtitle delay on ExoPlayer #74
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fm/sub-offset-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The subtitle delay control (gear menu → Subtitle delay, −1 s … +1 s, saved per item and per subtitle track) now works on ExoPlayer, the default player. Until now it only showed and worked on MPV.
Commits
services/SubtitleDelayRenderer.kt.SubtitleDelayRendereris aForwardingRenderer. It gives the wrapped renderer the playback position minus the delay inenable,render,resetPosition,getDurationToProgressUsandsupportsResetPositionWithoutKeyFrameReset. A positive delay shows subtitles later, the same sign as mpvsub-delay. The delay changes only through aMSG_SET_SUBTITLE_DELAYrenderer message, which runs on the playback thread.TextRendererreads its end of stream only within 1 s of the period end. With a delay above +1 s,STATE_ENDEDwould arrive late by the delay minus 1 s, so next-up would come late. The wrapper reports ended once the real position passes the period end (worked out from the timeline andMediaPeriodId) while the delay is positive.SubtitleDelayRenderersFactorywraps the text renderer and libass'sAssRenderer.AssRendererdraws atpositionUs - 10^12, so the same shift also delays ASS/SSA under libass.SubtitleDelayRendererTest.PlayerFactorywraps the final renderers factory, after the libass wrap.Player.applySubtitleDelay(delay)setsMpvPlayer.subtitleDelay, or sends the message to everySubtitleDelayRendererof anExoPlayer.PlaybackPage: the apply effect now keys on(player, subtitleDelay). The gate is nowsubtitleDelaySupported(player, currentPlayback): always true for MPV, and true for ExoPlayer unless the selected subtitle stream hasDeliveryMethod = Encode(burned in by the server).SubtitleDelayControlTest:DeliveryMethodon every subtitle stream of a PlaybackInfo response (Jellyfin.Api/Helpers/MediaInfoHelper.cs:504-511). The fixtureexternal_subs.jsoncarries it (ExternalandEmbed), and the burned-in case swapsEmbedforEncode.media3-test-utilsandmedia3-test-utils-robolectric1.11.1 as test dependencies (Apache-2.0, same version as media3).SubtitleDelayPlaybackTestplays a generated 4 s WAV with a sideloaded SRT through a realExoPlayer(DefaultMediaSourceFactory,CapturingRenderersFactory, fake clock):STATE_ENDEDarrives after 4 s of playback (±100 ms).Resetting the delay when switching to a track with no saved value landed separately: "Reset subtitle delay when the new track has none saved", already on
fm/tv-round2.What it covers and what it does not
Covered:
All of them go through the same renderer shift, and a change applies while playing.
Not covered:
media3 internals: wrapping hides the renderer from two
instanceof TextRendererchecks inRendererHolder: the clipped-stream end position and server-side ad transitions. Wholphin uses neither.Tests
Run through
docker/gradle.sh debug :app:testDefaultDebugUnitTest --tests 'com.github.damontecres.wholphin.services.SubtitleDelay*' --tests 'com.github.damontecres.wholphin.ui.playback.SubtitleDelayControlTest':SubtitleDelayRendererTestSubtitleDelayControlTestSubtitleDelayPlaybackTestSTATE_ENDEDonly after 5010 ms of playback, at position 5010 > duration 4000. The committed test requires 4000 ± 100 ms, so it fails without the fix. The throwaway was not committed.5f5b5ffd. The branch was then rebased without conflicts onto709ca291, which only adds the reset-delay change inPlaybackViewModeland Discover changes. None of the files in this PR changed in that rebase.Manual check for later, on a real player
Play a title with an external SRT, set the delay to +2 s and let it run to the end of the film. It must reach the end and show the end screen or next-up straight away, without hanging or waiting at the end.
Review of the subtitle delay on ExoPlayer at head
0a7c059f241360bb76914ff53721237f2c4abd38(3 commits, basefm/tv-round2).Code verdict: APPROVE (
review/code-claude= success).Design verdict: PASS (
review/design-claude= success). No new UI: the existing "Subtitle delay" row and its steps now appear for ExoPlayer, with no new string, token or layout.Some media3-internal behaviour below rests on the lane's tests and the plan, not on my running media3. Those points are marked [INFERENCE].
Zero delay is identical to today.
positionUs - 0. Stream start and offset are untouched, and only the one custom message is intercepted.isEndedwidens only when the delay is positive.render, so it cannot stall or drop cues.Shift is exact.
enable,render,resetPosition,getDurationToProgressUs,supportsResetPositionWithoutKeyFrameReset) is shifted once, and nothing else shifts ExoPlayer text.End of stream (the lane's correction).
isEndedand passes with it.Change while playing.
Track kinds.
AssRenderer. Video, audio and metadata renderers are untouched.MPV.
Gate.
ENCODE. No stream, or no playback yet, is true. Other players are false. It recomputes on track switch.SubtitleDelayControlTestcovers these cases, the row appearing only when enabled, and "+250ms" reporting 250 ms.Merge and dependencies.
fm/tv-round2is clean.media3-test-utilsdependencies are test-only, at the existing version 1.11.1.Non-blocking notes:
instanceof TextRendererchecks (clipped streams, server-side ad insertion). Wholphin uses neither.Full report (review 12):
/root/.treehouse/firstmate-7bab20/2/firstmate/data/round2-review/report.md. Not run: Gradle/make, nothing on the box.