Skip to content

feat(playback): jump to live for Embedded MPV MPEG-TS streams - #2211

Open
larsemig wants to merge 2 commits into
4gray:masterfrom
larsemig:feat/embedded-mpv-jump-to-live
Open

larsemig wants to merge 2 commits into
4gray:masterfrom
larsemig:feat/embedded-mpv-jump-to-live

Conversation

@larsemig

@larsemig larsemig commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds a jump to live button (⏩ fast_forward) to Embedded MPV, right of play/pause, for live MPEG-TS streams only. One click skips the backlog mpv has buffered and leaves 3 s of buffer, so you watch a few seconds behind the broadcast instead of 20–30 s. That matters most for sports.

This is a proposal. Feel free to iterate on placement, the 3 s target or naming.

Screenshots

Before the jump: a long buffer right after opening a live .ts channel.

Bildschirmfoto 2026-11-12 um 17 10 30

After the jump: a short buffer.

Bildschirmfoto 2026-11-12 um 17 10 45

The control bar: the button right of play, which stays centred.

Bildschirmfoto 2026-11-12 um 16 13 20

Why live latency is high with .ts

An Xtream .ts live stream is one endless HTTP response. Many panels answer a new connection with a burst of their own backlog (measured: ~23–29 s of video within 2.5 s) and then send at real-time speed. mpv starts playing at the beginning of that burst, so you stay ~23 s behind live for the whole session. Every channel change or reconnect repeats the burst.

mpv reports these streams as "not seekable", but it can seek inside what it has already buffered. Jumping to "buffer end − 3 s" took the measured delay from ~23 s down to ~3 s. TS then heals itself: after at most one short stall right after the jump, data keeps arriving continuously and the buffer stays stable. 3 s covers normal delivery jitter; smaller targets brought no lasting gain.

Why the button is TS-only (and not for m3u8)

HLS (.m3u8) does not deliver a continuous stream. It delivers whole segments, often ~10 s each, and mpv's buffer ends at the newest complete segment.

  • Jumping to "buffer end − 3 s" on HLS leaves 3 s of buffer, but the next data only arrives when the next ~10 s segment is finished.
  • The buffer runs dry before every new segment. I reproduced the same situation with live_start_index=-1: a stall on every segment, each followed by an audio restart and an audio/video resync that drops frames. Visually, the picture jumps and stutters.
  • Unlike TS it does not heal itself, because mpv's 1 s post-stall wait is used up long before the next segment arrives.

Making HLS safe would require the provider's segment length (to keep about one segment in reserve). The player can't know it reliably without heuristics, so the button simply doesn't exist for HLS. The Auto stream format still prefers m3u8; users who want low latency can switch to ts.

What changed

  • Controls contract: a new liveEdge capability and a jumpToLiveEdge() command. Web adapters keep it off.
  • Embedded MPV (EmbeddedMpvLiveEdge): the button shows only for live playback whose mpv file-format is mpegts, so it works for Xtream, M3U and Stalker alike. A click seeks by bufferedAheadSeconds − 3 through the existing relative seekBy; with ≤ 3 s buffered it does nothing. Repeats are ignored for 2 s, because the snapshot that answers the seek can still carry the old buffer value.
  • UI: the button is always enabled while shown. A disabled state that followed the buffer flickered, because a live buffer swings by a second or more. It appears in the shared controls (frame-copy engine) and in the native-view legacy dock, and every click flashes "LIVE".
  • Layout: the shared transport row is now a 1fr auto 1fr grid, so play stays centred when the button appears.
  • Refactor: the ±10 s seek and the jump moved into ControlsTransport, because PlayerControlsComponent was at the line limit.
  • i18n: EMBEDDED_MPV.PLAYER.JUMP_TO_LIVE in all locales.
  • Docs: player-controls contract, embedded-mpv-native.md (new "Jump to live (MPEG-TS)" section) and an Xtream compatibility note.
  • Release note: .changes/playback-embedded-mpv-jump-to-live.md.

Testing

  • ui-playback unit tests: 1723 passed, including new tests for:
    • the TS/HLS/VOD gating;
    • the jump amount and the 2 s lockout;
    • button placement, the centred play column and the legacy dock.
  • Web app and spec type checks, ESLint (no errors), i18n checks, release-note validation.
  • Manual testing on macOS (frame-copy engine) with a real provider during development. The flicker and play-centring fixes came out of that.
  • Not covered: an Electron E2E with a synthetic bursting TS server, which would need a native build. The Linux out-of-process native-view backend reports no stream stats, so the button never appears there.

Possible follow-ups (out of scope)

  • A keyboard shortcut.
  • An optional automatic jump after the initial burst.
  • A hint suggesting ts for lower latency.

🤖 Generated with Claude Code

Live MPEG-TS from Xtream-style panels starts with a server-side backlog
burst (~20-30 s), so viewers watch far behind live. mpv can seek inside
its demuxer cache on these non-seekable streams; a jump to cache end
minus 3 s cut measured latency from ~23 s to ~3 s, and TS self-heals
after at most one short stall because data keeps arriving at 1x.

The button is TS-only on purpose: HLS delivers whole segments and its
cache ends at the newest complete segment. Leaving 3 s there reproduced
the live_start_index=-1 behaviour (a stall plus A/V resync with dropped
frames on every segment). Making HLS safe needs the provider's segment
length, which the player cannot know reliably.

- PlayerController contract: `liveEdge` capability and
  `jumpToLiveEdge()` command; web adapters keep them off.
- EmbeddedMpvLiveEdge gates on live + mpv `file-format` mpegts, seeks by
  bufferedAheadSeconds - 3 via the relative seekBy (no-op at <= 3 s) and
  ignores repeats for 2 s, since the reply snapshot can still carry the
  pre-seek buffer.
- fast_forward button right of play, always enabled, in the shared
  controls (frame-copy) and the native-view legacy dock. The shared
  transport row becomes a `1fr auto 1fr` grid so play stays centred
  when the button appears.
- ControlsTransport takes the +-10 s seek and the jump out of
  PlayerControlsComponent (max-lines).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issue was found.

Summary

Adds “Jump to live” to Embedded MPV for live MPEG-TS streams.

  • Live MPEG-TS playback can skip its buffered backlog.

Review checks were based on source and supplied tests; no runtime or visual verification was performed.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Shared controls or legacy dock] --> B{Live MPEG-TS?}
    B -->|No| C[No jump]
    B -->|Yes| D{Playing or paused, no reconnect?}
    D -->|No| C
    D -->|Yes| E{Buffer above 3 seconds and lockout expired?}
    E -->|No| C
    E -->|Yes| F[Seek forward by buffer minus 3 seconds]
    F --> G[Ignore repeat jumps for 2 seconds]
Loading

Reviews (1) · Last reviewed commit: "feat(playback): jump to live for Embedde..." · Reviewed by Greptile

@codecov

codecov Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.88%. Comparing base (ab5c81b) to head (2190ffa).
⚠️ Report is 22 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...back/src/lib/player-controls/controls-transport.ts 87.50% 1 Missing and 1 partial ⚠️
.../lib/player-controls/web-video-controls.adapter.ts 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2211      +/-   ##
==========================================
+ Coverage   81.63%   81.88%   +0.25%     
==========================================
  Files        1884     1907      +23     
  Lines       98631   101684    +3053     
  Branches    23005    24861    +1856     
==========================================
+ Hits        80514    83266    +2752     
- Misses      11085    11130      +45     
- Partials     7032     7288     +256     
Flag Coverage Δ
unit 81.88% <95.00%> (+0.25%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@4gray

4gray commented Nov 14, 2026

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-14T15:44:44.099024Z e98eeb5 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: e98eeb5f6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants