Skip to content

feat(build): ST 5.1.10 cores (full + 2.6 MB copy) with non-COI vetting lane - #3

Merged
asoulliereHT merged 6 commits into
chore/ffmpeg-8.1-upgradefrom
feat/st-5.1.10-core
Aug 14, 2026
Merged

asoulliereHT merged 6 commits into
chore/ffmpeg-8.1-upgradefrom
feat/st-5.1.10-core

Conversation

@asoulliereHT

Copy link
Copy Markdown
Collaborator

Summary

Adds single-threaded FFmpeg 5.1.10 cores to the fork, built from the same hardened dependency pins as the MT 8.1.2 cores. The driver: cross-origin isolation (COOP/COEP) required by the MT core breaks popup-based auth (Facebook login) in the consumer, and clipping-tool-ui already forces -threads 1 to dodge an emscripten pthread-layer deadlock, so MT parallelism was not being used.

Why 5.1: fftools requires threads from FFmpeg 6.0 onward (ffmpeg_deps gains threads at n6.0 configure; pthread_create is unconditional in ffmpeg_demux.c/ffmpeg_mux.c), so the 5.1 LTS branch (5.1.10, 2026-06-21, still receiving backports) is the last single-thread-capable frontend.

What's in here

  • src/fftools-5.1/: the pre-scheduler 5.1-era vendored fftools, resurrected from the chore/phase-0-baseline tree.
  • Version-parameterized build: FFMPEG_VERSION flows Makefile → Dockerfile → ffmpeg-wasm.sh, selecting the FFmpeg tag and the fftools generation. The ARG is scoped to the ffmpeg-base stage so MT and ST builds share the dependency-builder cache.
  • copy variant (make prd-st-copy → packages/core-copy): --disable-everything plus mov/mpegts/concat demuxers, mp4 muxer, h264/aac parsers+decoders, and the copy-path bsfs. No encoders, no external libs, no GPL. 2.6 MB wasm (full ST is 22.8 MB), sized to clipping-tool-ui's two -c copy commands.
  • Non-COI test lane: scripts/serve.js --no-coi on port 3001; the ST pages assert crossOriginIsolated === false so the lane cannot silently run isolated. The inert COOP/COEP <meta> tags are removed.
  • Vetting suites:
    • npm run test:cliptool / test:cliptool:copy: clipping-tool-ui's runClipExport and runClipStitch argv verbatim (including ffconcat + option ignore_editlist 1, -avoid_negative_ts make_zero, +negative_cts_offsets+faststart) against synthesized short-GOP H.264+AAC TS segments, with stream-presence assertions.
    • npm run test:st:probe: multi-input filtergraphs (overlay, xfade, concat filter) complete on ST 5.1 — the 8.x deadlock is scheduler-specific, confirming FORK.md's hypothesis; capability map updated per engine.
    • npm run test:perf:st / test:perf:mt: 1080p60 2s x264 re-encode: MT default 5.7s, MT -threads 1 20.9s, ST 22.9s.

Test results

  • ST full core: 13/13 browser tests passing, non-isolated.
  • ST copy core (2.6 MB): both verbatim production commands passing, non-isolated, outputs stream-verified (h264+aac).
  • MT suites untouched and unaffected (test:all unchanged on port 3000).

Notes for review

  • A vetting lesson is baked into the suite: the repo's single-keyframe 1s fixture plus size-only assertions let an audio-only export pass silently (input -ss past the only keyframe drops all non-key packets under -c copy). The cliptool suite synthesizes keyint=15 segments and asserts stream presence.
  • ADR 0001 (MT-only) is not superseded by this PR; this is the evidence-gathering build. ADR 0002 should accompany the consumer cutover (release the copy core, bump fetch-ffmpeg-core.mjs, drop COOP/COEP, thread: false).
  • Known cost to keep on the record: 5.1 gives up three majors of mov/mpegts demuxer/muxer fixes; recommend one vetting pass against a real archive segment before flipping the vendor pin.

Vetting record: ~/vault/docs/ffmpeg.wasm/plans/2026-08-13 st-5.1.10-core.md

🤖 Generated with Claude Code

asoulliereHT and others added 2 commits July 7, 2026 21:55
Capture why this fork ships an MT-only @ffmpeg/core-mt and rejects the
single-threaded @ffmpeg/core: FFmpeg 8.x's fftools frontend is thread-based,
so "switch to ST" means downgrading the engine to upstream 5.1.4 (losing the
zlib/x264/lame CVE patches and slim allowlist). ST would not fix the
multi-input filtergraph deadlock (a wasm-scheduler limit) and is ~2x+ slower.
Cross-origin isolation is handled at the serving layer instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fftools requires threads from FFmpeg 6.0 onward (ffmpeg_deps gains
threads; pthread_create is unconditional in demux/mux), so 5.1 is the
last single-thread-capable frontend. This adds ST 5.1.10 cores built
from the fork's hardened dep pins, needing no COOP/COEP:

- Resurrect the 5.1-era vendored fftools (pre-scheduler, 8 files) from
  the phase-0 baseline into src/fftools-5.1/.
- Parameterize the build by FFMPEG_VERSION (Makefile, Dockerfile,
  ffmpeg-wasm.sh); the ARG is scoped to ffmpeg-base so the dep-builder
  cache stays shared between MT and ST builds.
- New `copy` variant: --disable-everything + mov/mpegts/concat demuxers,
  mp4 muxer, h264/aac parsers+decoders, copy-path bsfs. No encoders, no
  external libs, no GPL. 2.6 MB wasm (full ST is 22.8 MB), sized to
  clipping-tool-ui's two `-c copy` commands.
- Non-COI test lane: serve.js --no-coi mode on port 3001; the ST page
  asserts crossOriginIsolated === false (COOP/COEP <meta> tags were
  inert and are removed).
- Vetting suites: clipping-tool-ui's runClipExport/runClipStitch argv
  verbatim against synthesized short-GOP H.264+AAC TS segments, with
  stream-presence assertions (a single-keyframe fixture + size-only
  asserts had let an audio-only export pass); multi-input probe showing
  overlay/xfade/concat-filter complete on ST 5.1 (the 8.x deadlock is
  scheduler-specific); perf probe (MT default 5.7s / MT -threads 1
  20.9s / ST 22.9s on a 1080p60 2s x264 re-encode).

Vetting record: ~/vault/docs/ffmpeg.wasm/plans/2026-08-13 st-5.1.10-core.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@asoulliereHT asoulliereHT left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Panel review (Danny/streaming, Keanu/build+CI, Bruce/QA, Jet/docs — Liam and Harrison excluded: no auth/input-surface or ABI/contract changes in this diff). 16 raw findings, deduplicated to 11 threads below; all verified against the working tree before posting.

Two findings could not anchor (lines outside the PR diff):

  • [correctness] Jet (Docs): FORK.md's H1 (# FloSports fork — FFmpeg 8.1.2 (MT-only)) and opening paragraph still assert MT-only while the body now documents two ST 5.1.10 cores. Anyone who reads the first two lines and stops walks away with the wrong model of the fork. Fix the title and lede.
  • [cleanup] Jet (Docs): The "Release variants" section still says "Each release ships two MT cores" and the vendoring section lists only MT tarballs — true, but a reader who just learned about the 2.6 MB copy core will go looking for a release asset that does not exist. State plainly that the ST cores are local-build/vetting-only until CI attaches them.

Convergence worth noting: three reviewers independently flagged the zero-CI-coverage gap, and two independently flagged the missing duration/start assertions — both are the load-bearing threads in this review.

Comment thread Dockerfile
Comment thread Makefile
Comment thread package.json Outdated
Comment thread build/ffmpeg-wasm.sh Outdated
Comment thread tests/ffmpeg-cliptool.test.js Outdated
Comment thread tests/ffmpeg-cliptool.test.js Outdated
Comment thread tests/ffmpeg-perf-st.test.html
Comment thread docs/adr/0001-mt-only-core.md Outdated
Comment thread FORK.md Outdated
Comment thread build/ffmpeg.sh
asoulliereHT and others added 4 commits August 13, 2026 19:18
- Dockerfile: move FFMPEG_VERSION ARG/ENV below the embuilder layer so a
  version switch invalidates only the FFmpeg source ADD (Keanu)
- Makefile: fail loudly on empty FFMPEG_VERSION (would silently fetch
  FFmpeg's default branch); ffmpeg-wasm.sh now requires it via :? (Keanu)
- cliptool suite: probe() returns Duration/start and the tests assert the
  clip window (duration within [0.9,1.6] with keyframe pre-roll, start~0)
  and stitch ratio ~2x member (Bruce, Danny)
- add MT A/B lane (ffmpeg-cliptool-mt.test.html, test:cliptool:mt): the
  identical verbatim commands on the 8.1.2 MT core; reuse one instance
  when synth==DUT (two-instance reload trips the emsdk pthread-pool leak)
  and run synth encodes with -threads 1 — the unthrottled synth
  reproduced the production MT deadlock deterministically (Danny)
- perf pages: assert crossOriginIsolated false (ST) / true (MT) (Bruce)
- remove tests/ffmpeg-core-st.test.html + its script: instantiates the
  worker-built core in a document, which cannot work (sync-XHR abort);
  superseded by the ffmpeg-st suite (Keanu)
- soften cliptool header overclaim: synthesized inputs, not real packager
  segments (Bruce)
- FORK.md: title/lede no longer claim MT-only; release-variants notes ST
  is local-build only; vetting references now point in-repo (Jet)
- ADR 0001: status amendment recording the two falsified bullets and the
  re-evaluation, pending a superseding ADR if ST ships (Jet)
- build/ffmpeg.sh: WHY comment for the null muxer/bsf entries (Jet)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v0.15.0 shipped MT-only bytes under new names because the release job was
never told about ST: the branch added build-st/prd/prd-st-copy but CI.yml
still invoked only prd-mt/prd-mt-slim, so GHA layer caching replayed
v0.14.0's layers and uploaded them under v0.15.0 asset names.

- st-build-and-test job: builds the full ST core (the cliptool suite's
  input synthesizer) + the copy core, runs the ST suite and the verbatim
  clipping-tool-ui commands on the non-COI server, uploads core-copy
- release job: needs st-build-and-test, builds prd-st-copy, and attaches
  ffmpeg-core-st-copy-<tag>.tgz (no "-mt-" in the name)
- FORK.md: release-variants table gains the st-copy row (from v0.15.1);
  the "not built by CI" note is gone

The bad tag stays: v0.15.0 is immutable per the consumer fetch-script
contract (a re-pointed tag is indistinguishable from tampering and the
SHA pin rejects it). Ship the ST asset as v0.15.1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v0.15.0 rerun failed in st-build-and-test: testdata/ is a git
submodule and actions/checkout does not fetch submodules by default, so
the cliptool suite's fetch of audio-1s.wav 404'd and the 404 body fed to
ffmpeg produced a cryptic "TS segment synthesis failed (ret=1)". The MT
jobs never noticed because they use only embedded base64 fixtures.

Also guard the fixture fetches (cliptool + perf) with res.ok so an
unpopulated submodule fails with a named error instead of an ffmpeg exit
code three steps downstream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The st-copy artifact is LGPL: no --enable-gpl, no libx264, no
libpostproc, no external libs at all. Assert it at runtime from the
core's own -version banner in the copy lane (EXPECT_GPL_FREE) so a
future allowlist change can't silently re-introduce a GPL component.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@asoulliereHT

Copy link
Copy Markdown
Collaborator Author

Review (from the consuming app's side)

Approve. The st-build-and-test lane is the strongest consumer guarantee in the stack: it runs clipping-tool-ui's verbatim commands (TS+m4a window export, video-only, stitch via ffconcat with ignore_editlist) against the copy core on a non-isolated server asserting crossOriginIsolated === false, and the release job now needs it — the v0.15.0 MT-only-release failure mode is structurally closed. LGPL gate on the copy core and the honest ADR annotation (falsified bullets named with evidence) are both appreciated.

Findings:

  1. FORK.md says the ST asset ships "from v0.15.1", but it actually shipped via the re-pointed v0.15.0. Recommend cutting v0.15.1 from the branch head: matches the doc and repairs the immutable-tags producer contract (the consumer's fetch script pins tag+SHA and now documents the re-point as a one-time exception). clipping-tool-ui's pin bump is a three-line change on our side.
  2. This PR states fftools require threads from 6.0; clipping-tool-ui's comments say 7.0 (sourced from a stale branch comment). Yours is the researched claim — the correction lands on the consumer side.
  3. Nit: the copy core's trim enables h264,aac decoders in a -c copy-purpose build. If they're load-bearing (probing?), a one-line comment would protect them from the next trimmer; if not, they're free size.

🤖 Generated with Claude Code

@asoulliereHT
asoulliereHT merged commit c021267 into chore/ffmpeg-8.1-upgrade Aug 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant