feat(web-ui): add lightweight HLS MSE playback and refactor mpegts#524
Conversation
Replace native HLS fallback with worker-side playlist parsing, segment scheduling, and fMP4 passthrough while trimming unused demux/remux code. Co-authored-by: Cursor <cursoragent@cursor.com>
…cancels Reuse playlist text from content-type detection and gate pause between discrete segments instead of aborting in-flight fetches. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
1 similar comment
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
There was a problem hiding this comment.
Pull request overview
This PR adds an application-layer HLS playback path (playlist parsing + refresh + optional fMP4 passthrough) inside the existing transmux worker and simplifies/downsizes the mpegts stack by removing legacy HLS fallback code and a large amount of unused demux/metadata functionality.
Changes:
- Add lightweight HLS support in the worker via new
HlsSource+ minimalm3u8parser, routed through the unified MSE player. - Refactor the transmux pipeline around a
SegmentSourceabstraction and add worker-side seek support for HLS VOD. - Remove legacy/unused utilities and demux metadata paths (SCTE35/KLV/PGS/etc.), and simplify browser detection.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| web-ui/src/mpegts/worker/transmux-worker.ts | Switch worker events to hls-info and add seek command wiring. |
| web-ui/src/mpegts/worker/segment-source.ts | Introduce SegmentSource + StaticSegmentSource abstraction for segment iteration. |
| web-ui/src/mpegts/worker/pipeline.ts | Major refactor: segment-driven load loop, HLS integration, fMP4 passthrough path, and seek/reset handling. |
| web-ui/src/mpegts/worker/messages.ts | Update worker command/event union types (add seek, replace hls detection event). |
| web-ui/src/mpegts/utils/utf8-conv.ts | Remove unused UTF-8 conversion helper. |
| web-ui/src/mpegts/utils/typedarray-equality.ts | Remove unused typedarray equality helper. |
| web-ui/src/mpegts/utils/browser.ts | Replace heavyweight browser-detection object with isSafari/isFirefox. |
| web-ui/src/mpegts/types.ts | Remove onHLSDetected from internal player interface. |
| web-ui/src/mpegts/remux/mp4-remuxer.ts | Simplify old browser workarounds and add setDtsBaseOffset() for timeline anchoring. |
| web-ui/src/mpegts/remux/mp4-generator.ts | Trim unsupported/unused codec/container box generation paths. |
| web-ui/src/mpegts/player/mse.ts | Add setDuration() and buffer-availability signaling; simplify codec handling. |
| web-ui/src/mpegts/player/mpegts-player.ts | Handle hls-info, add VOD forward-buffer throttling and HLS VOD worker seek path. |
| web-ui/src/mpegts/player/hls-player.ts | Remove native HLS fallback player implementation. |
| web-ui/src/mpegts/io/fetch-loader.ts | Improve HLS content-type detection (reuse fetched playlist text) and simplify abort logic. |
| web-ui/src/mpegts/index.ts | Remove impl switching; always use unified mpegts/MSE player path. |
| web-ui/src/mpegts/hls/m3u8.ts | Add minimal media/multivariant m3u8 parsing. |
| web-ui/src/mpegts/hls/hls-source.ts | Add playlist-driven SegmentSource with live refresh and variant selection. |
| web-ui/src/mpegts/hls/fmp4.ts | Add minimal BMFF probing + init parsing for fMP4 passthrough. |
| web-ui/src/mpegts/demux/ts-demuxer.ts | Large demux simplification: remove BaseDemuxer/MediaInfo + metadata side paths, keep core A/V parsing. |
| web-ui/src/mpegts/demux/smpte2038.ts | Remove SMPTE2038 parsing/types. |
| web-ui/src/mpegts/demux/scte35.ts | Remove SCTE35 parsing/types. |
| web-ui/src/mpegts/demux/pgs-data.ts | Remove PGS data types. |
| web-ui/src/mpegts/demux/pes-private-data.ts | Remove PES private data types. |
| web-ui/src/mpegts/demux/pat-pmt-pes.ts | Remove stream-type/constants and PMT fields for removed metadata paths. |
| web-ui/src/mpegts/demux/klv.ts | Remove KLV parsing/types. |
| web-ui/src/mpegts/demux/base-demuxer.ts | Remove BaseDemuxer abstraction (callbacks now directly on TSDemuxer). |
| web-ui/src/mpegts/core/media-info.ts | Remove MediaInfo model (no longer surfaced from worker). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e597b7ffb9
ℹ️ 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".
Flush pending segments on startstreaming, append first init segments immediately, and wire worker pause/resume to MMS streaming hints. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
- quote codec lists in MSE mimeType (muxed fMP4 with comma-separated codecs) - resume worker on HLS VOD seek while watermark-paused; measure forward buffer within the range containing currentTime - guard _loadFmp4Init against superseded runs (stale init segment append) - correct m3u8 parser doc: EXT-X-PLAYLIST-TYPE is ignored, not parsed Co-authored-by: Cursor <cursoragent@cursor.com>
|
Azure Static Web Apps: Your stage site is ready! Visit it here: https://thankful-water-0a297bf00-524.eastasia.1.azurestaticapps.net |
…eation from racing media engine init
Each worker message is delivered in its own event-loop task. Appending the
video init segment and then yielding lets the UA finish parsing it and lock
the SourceBuffer set, so the audio addSourceBuffer that arrives in the next
task throws QuotaExceededError ("reached the limit of SourceBuffer objects")
and the stream plays without sound. Reproduced 100% on Chrome with any
TS audio+video stream since the worker-based pipeline (#524).
The player now stashes init-segment messages and flushes them together right
before the first non-init message, creating all SourceBuffers in a single
task — the buffer append algorithm runs as a queued task, so no init segment
parse can complete in between.
Also switch mid-stream codec changes to SourceBuffer.changeType(): calling
addSourceBuffer for an existing track always throws once the media engine
has initialized.
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Application-layer HLS playback
hls-playerfallback and trim unused mpegts demux/remux/metadata code (~2.9k lines removed, player bundle ~15 kB smaller).SegmentSourceabstraction so static catchup and HLS share the same transmux pipeline.iOS / ManagedMediaSource reliability
ManagedMediaSource: gate appends on thestreamingproperty, flush pending init/media segments onstartstreaming, attach viaURL.createObjectURL.updateend(iOS does not reliably fireprogress/stalled), fixing playback stuck on "Loading" after the first frame.waitingimmediately resets playback rate to 1x, breaking the catch-up → rebuffer loop.MediaSourceclose (iOS reclaims media resources in background) withoutInvalidStateErrorstorms, pause the worker, and on return to foreground auto-resume or reload the stream at the live edge / last position.Review feedback (Copilot / Codex)
Test plan
pnpm run type-check:tscandpnpm run web-ui:build(embedded header rebuild)Made with Cursor using Fable 5