Skip to content

Build FFmpeg from a current release (n7.1) instead of the 2020 fork - #81

Merged
mormegil6 merged 1 commit into
EnvelopSound:masterfrom
mormegil6:build-ffmpeg-from-current-release
Aug 20, 2026
Merged

Build FFmpeg from a current release (n7.1) instead of the 2020 fork#81
mormegil6 merged 1 commit into
EnvelopSound:masterfrom
mormegil6:build-ffmpeg-from-current-release

Conversation

@mormegil6

Copy link
Copy Markdown
Collaborator

Two lines in the Dockerfile: build ffmpeg from the upstream n7.1 release tag instead of EnvelopSound/ffmpeg at earshot-v0.1, which reports ffmpeg version 4.3.git ... Copyright (c) 2000-2020 and is frozen around 2021-04, roughly 26k commits behind upstream.

The fork exists for one thing: PCE-aware AAC, so a 16-channel (hexadecagonal) OBS Music Edition contribution survives the RTMP leg. Six years on, that is no longer a reason to carry a fork, and both halves check out against real builds rather than assumption:

  • Decode of 16-ch PCE AAC is upstream. Earshot's actual job, decode the contribution AAC and re-encode to 16-ch Opus for DASH, runs unmodified on stock ffmpeg.
  • Encode of 16-ch AAC is native in n7.1. libavcodec/aacenc.c's aac_pce_configs[] carries AV_CHANNEL_LAYOUT_HEXADECAGONAL at the n7.1 tag. It was dropped from master around c92c6cbf during the channel-layout API rework, which is a separate upstream regression and the reason this targets the n7.1 release specifically rather than a newer one.

What the move buys, beyond retiring a third-party fork last touched in 2022: it closes roughly six years of CVE and hardening work on exactly the demuxer and decoder paths that meet contribution bytes (aacdec, flvdec, mpegts), and it gains modern muxer behaviour. The one that matters in practice is Opus-in-fMP4 for DASH: under -dash_segment_type mp4 the audio and the copied-through H.264 video share a single fMP4 container, rather than the mixed fMP4-video / WebM-audio manifest the 2020 muxer forces, which FFmpeg-based players cannot demux without stuttering.

The one local patch this Dockerfile carries, the DASH suggestedPresentationDelay floor sed on libavformat/dashenc.c, applies to n7.1 with no change: the target line and its c->last_duration / AV_TIME_BASE expression are byte-identical at the tag, and the build-time post-check that guards it still passes.

Verified on real builds of this image, amd64 and a native arm64 build on a Raspberry Pi 4: ffmpeg reports 7.1; it encodes 16-ch hexadecagonal AAC and decodes it back; it decodes 16-ch AAC to 16-ch Opus (the live transcode); it produces Opus-in-fMP4 DASH under -dash_segment_type mp4; the SPD floor works, with a live manifest showing PT30S; a full synthetic RTMP contribution to 16-ch Opus DASH pipeline passes with all sixteen channels in their correct slots; and the Opus-in-fMP4 output plays in-browser on Chrome and Firefox through dash.js/MSE with all sixteen channels decoding.

… 2020 fork

The image builds ffmpeg from EnvelopSound/ffmpeg @ earshot-v0.1, which reports
"ffmpeg version 4.3.git ... Copyright (c) 2000-2020" - frozen around 2021-04 and
26k+ commits behind upstream. That fork exists for one thing: PCE-aware AAC so a
16-channel (hexadecagonal) OBS Music Edition contribution survives the RTMP leg.
Six years on, that no longer needs a fork:

- DECODE of 16ch PCE AAC is upstream. earshot's core job - decode the contribution
  AAC and re-encode to 16ch Opus for DASH - runs unmodified on stock ffmpeg.
- ENCODE of 16ch AAC is native in the 7.1 release: libavcodec/aacenc.c's
  aac_pce_configs[] table includes AV_CHANNEL_LAYOUT_HEXADECAGONAL at n7.1. (It was
  dropped from master around c92c6cbf during the channel-layout API rework, so
  n7.1 is the right target; a separate upstream report covers that regression.)

So switching FFMPEG_VERSION to the upstream n7.1 tag closes six years of
CVE/hardening on the demuxer and decoder paths that meet contribution bytes
(aacdec, flvdec, mpegts), drops a 6-year-old third-party fork dependency, and
gains modern muxer behaviour - notably Opus-in-fMP4 for DASH, so audio and
copied-through H.264 video can share one fMP4 container instead of a mixed
fMP4-video / WebM-audio manifest that FFmpeg-based players cannot demux cleanly.

The one local patch this Dockerfile carries - the DASH suggestedPresentationDelay
floor sed on libavformat/dashenc.c - applies to n7.1 verbatim (the target line and
its `c->last_duration / AV_TIME_BASE` expression are unchanged), and its build-time
post-check still passes.

Verified on a build of this image: ffmpeg 7.1; encodes 16ch (hexadecagonal) AAC
and decodes it back; decodes 16ch AAC -> 16ch Opus; produces Opus-in-fMP4 DASH
under -dash_segment_type mp4; the DASH SPD floor works (live manifest shows PT30S);
and a full synthetic RTMP contribution -> 16-ch Opus DASH pipeline passes with all
16 channels in their correct slots. Browser playback of the Opus-in-fMP4 output
confirmed on Chrome and Firefox (dash.js/MSE), all 16 channels decoding.
Copilot AI lite review requested due to automatic review settings August 20, 2026 14:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Updates the container build to use an upstream FFmpeg release tag (n7.1) rather than a long-stale third-party fork, aligning the image with modern upstream fixes and behavior while keeping the existing local DASH muxer patch flow.

Changes:

  • Switch FFMPEG_VERSION from earshot-v0.1 to upstream n7.1.
  • Update the FFmpeg source download URL to pull the upstream tag archive (and name the tarball deterministically).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Dockerfile
Comment on lines +89 to 90
wget -O ${FFMPEG_VERSION}.tar.gz https://github.com/FFmpeg/FFmpeg/archive/refs/tags/${FFMPEG_VERSION}.tar.gz && \
tar zxf ${FFMPEG_VERSION}.tar.gz && rm ${FFMPEG_VERSION}.tar.gz

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.

Fair point, and worth doing properly rather than quickly. Two notes on scope: this PR doesn't introduce the gap - the line it replaces fetched a tag archive with no verification either - and it actually improves the source trust by moving from a stale third-party fork to the official FFmpeg repository.

On the fix itself: pinning a sha256 of a GitHub auto-generated archive is unfortunately fragile, since GitHub has changed archive compression before and broken such checksums. The robust version is to pull ffmpeg.org's signed release tarball (ffmpeg-7.1.tar.xz with its published .sha256 and GPG signature), which is a larger change to the build stage (different URL and extracted directory name). I'd rather do that as a focused follow-up than bolt a brittle checksum onto this one.

@mormegil6
mormegil6 merged commit 3a0a7a2 into EnvelopSound:master Aug 20, 2026
4 checks passed
mormegil6 added a commit to mormegil6/Earshot that referenced this pull request Aug 20, 2026
@mormegil6
mormegil6 deleted the build-ffmpeg-from-current-release branch August 20, 2026 14:17
mormegil6 added a commit to mormegil6/ambisonic-box that referenced this pull request Aug 20, 2026
The FFMPEG_FLAGS fallback gains -dash_segment_type mp4, so the committed
H.264 passthrough path now packages BOTH tracks as fMP4 .m4s (video/mp4
avc1 plus audio/mp4 Opus) rather than fMP4 video alongside WebM audio.

The rule this adopts: the segment container follows the video codec's
native container, and audio follows video, so a manifest is never
mixed-container. Passthrough gives all-fMP4; the VP9 opt-in in
.env.example already carried -dash_segment_type webm and gives all-WebM.

The old mixed output was self-inconsistent: the manifest advertised an
ISO-BMFF profile while serving WebM audio. Browsers and VLC tolerate it,
but it is not a shape worth defending, and unifying it is what the
ffmpeg upgrade in EnvelopSound/Earshot#81 made possible at all: the 2020
fork's DASH muxer could not put Opus in fMP4.

Three test scripts read the audio init segment by a hardcoded .webm name
and would have failed against a perfectly healthy stack, reporting the
stream as absent. They now glob init-stream1.* so they survive the
container changing again, which is exactly what caught them here.

The browser capability page accepted WebM Opus only, so it would have
reported a false negative on the default path; it now accepts Opus in
either container. tests/av-sync/avmeter.js reads EBML and cannot work on
fMP4 at all, so it now checks the magic and aborts rather than scanning
MP4 bytes and returning a plausible wrong offset. telemetry already
globbed .m4s and needed only its comment corrected.

Verified on the committed default: test-pipeline.sh passes with all 16
tones in their own channels, test-srt-ingest.sh passes all six stages,
the manifest reads mimeType video/mp4 + audio/mp4 with 16 channels, and
Opus-in-fMP4 appends cleanly through MSE in a headless browser.
mormegil6 added a commit that referenced this pull request Aug 20, 2026
Follow-up to #81. That PR built from the upstream n7.1 source but fetched
it from GitHub's /archive/refs/tags/ URL, a tarball generated on demand
whose bytes are not stable (GitHub has changed archive compression
before), so there is nothing a checksum can meaningfully pin against.
Switch the source to the ffmpeg.org release artifact and verify it against
a pinned SHA-256 before extracting or compiling.

- Source: ffmpeg.org/releases/ffmpeg-7.1.tar.xz, the signed immutable
  release tarball, in place of the GitHub archive URL.
- Verify: sha256sum -c against a pinned hash aborts the build on mismatch
  rather than compiling unexpected source. The hash is the one FFmpeg's
  release signing key (FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8)
  signs for 7.1.
- Container: the release is .tar.xz, so add xz to the build deps and
  decompress with xz -dc | tar. The extract dir is lowercase ffmpeg-7.1
  (the release convention), updated in its references.

FFMPEG_VERSION goes n7.1 -> 7.1 to match the release naming; a
FFMPEG_SHA256 arg holds the pin. The DASH suggestedPresentationDelay floor
sed and everything downstream are unchanged: same 7.1 source, fetched from
the release channel and verified.
mormegil6 added a commit to mormegil6/ambisonic-box that referenced this pull request Aug 21, 2026
The previous version said this investigation 'started from a mixed-
container bug report', but that bug (Keven Ma's report, fixed as
EnvelopSound/Earshot#81) drove the separate ffmpeg-modernization work,
not this one. The iOS/Safari investigation was requested directly.
Named the two real, adjacent bug reports (Earshot#81, Chromium
547065816) instead of implying a causal link that did not exist.
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