Skip to content

fix(ffmpeg): fail fast when ffmpeg lacks the drawtext filter - #44

Merged
yultyyev merged 3 commits into
fix/ffmpeg-path-escapingfrom
fix/drawtext-filter-check
Oct 29, 2026
Merged

yultyyev merged 3 commits into
fix/ffmpeg-path-escapingfrom
fix/drawtext-filter-check

Conversation

@yultyyev

@yultyyev yultyyev commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #43. Base is fix/ffmpeg-path-escaping, so both land on main together in a single v0.3.1 release.

What

  • src/ffmpeg/run.ts gains listFilters(), which runs ffmpeg -hide_banner -filters once per process (a failed listing isn't cached). It also gains requireDrawtext(), which throws a typed MissingFilterError (with filter and ffmpegPath) before any text render.
  • add_text, add_title_card and runPlan (only for plans that carry text files) call it first. add_captions goes through add_text for each cue, so the first cue stops it.
  • MissingFilterError is exported from the package entry.
  • The error names the binary and the fix: set MAKEMYCLIP_FFMPEG_PATH to an FFmpeg with drawtext (for example apt install ffmpeg, then /usr/bin/ffmpeg), and for clip mcp, set it in the MCP client config's env.
  • tests/integration/filter-escape.test.ts reuses listFilters() and adds a CI case: without drawtext, add_text throws MissingFilterError. The drawtext escaping cases still run only where the filter exists.
  • docs/backlog/drawtext-on-linux.md is narrowed to the open binary-source decision.

Why

On Linux, ffmpeg-static 5.3.0 downloads John Van Sickle's FFmpeg 7.0.2 build. That build has libfreetype but no libharfbuzz, and since FFmpeg 6.1 drawtext requires both (drawtext_filter_deps="libfreetype libharfbuzz" in FFmpeg's configure). So every text path died with FFmpeg's raw No such filter: 'drawtext'. The bundled macOS binary (FFmpeg 6.0) and the Windows build have drawtext. Upstream tracks this as eugeneware/ffmpeg-static#147. Its fix, eugeneware/ffmpeg-static#158, moves Linux x64 to BtbN builds; it has been open since 2026-07-16 with no maintainer reply, and the last release was 5.3.0 on 2025-11-14.

This PR doesn't make text render on Linux by default. Doing that means changing the binary source; see the decision below.

Decision: keep option A for now

The owner picked A on 2026-10-29: keep ffmpeg-static plus this check, and don't swap the binary source. The backlog note records it, to revisit when ffmpeg-static ships a Linux build with drawtext. The options considered:

Option What it fixes Cost / risk License
A. Keep ffmpeg-static plus this fail-fast check Clear error; Linux users set MAKEMYCLIP_FFMPEG_PATH Text doesn't work out of the box on Linux unchanged (GPL binary)
B. Wait for ffmpeg-static 6 (#158) Linux x64 by default, no code from us Upstream silent since July; arm64 not covered GPL-3.0-or-later
C. Download BtbN FFmpeg-Builds for Linux ourselves x64 and arm64, with freetype, harfbuzz, fontconfig and libass Our own installer code; the n8.1 linux64 tarball is about 150 MB GPL or LGPL variants
D. Switch to an MIT wrapper (@radically-straightforward/ffmpeg uses BtbN 7.1.1 on Linux; node-av ships jellyfin-ffmpeg 8.1) All platforms in one dependency Low adoption (16 downloads a week), or a heavy native-binding package MIT wrapper, GPL binary
E. Burn text through libass (ass filter), which the current Linux binary has Works with today's binary Rewrites all four text paths and changes output on every platform unchanged

Any real fix should also pass fontfile=. drawtext without it falls back to fontconfig's default font, and slim containers have none. DejaVu Sans (Bitstream Vera license, 757 KB) is a candidate to bundle.

Checks

  • pnpm lint: pass (7 warnings, none in changed files)
  • pnpm type-check: pass
  • pnpm test (macOS arm64, bundled FFmpeg 6.0): 575 passed, 8 skipped
  • CI=true integration tests on macOS: 16 passed, 1 skipped (the drawtext cases run; the no-drawtext case skips)
  • pnpm build: pass
  • Linux amd64 (Docker, node:24-bookworm, bundled FFmpeg 7.0.2 without drawtext):
    • CI=true pnpm test: 583 passed, 5 skipped; add_text stops with MissingFilterError ran and passed
    • clip add_text: exits 1 with the new message instead of No such filter
  • Same container with apt install ffmpeg (5.1.9, has drawtext) and MAKEMYCLIP_FFMPEG_PATH=/usr/bin/ffmpeg:
    • clip add_text: renders the output file
    • all 5 drawtext escaping cases: pass
  • apt install ffmpeg (amd64) gives an FFmpeg with drawtext on Ubuntu 24.04 (6.1.1) and Ubuntu 26.04 (8.0.1), so the error message's advice holds there too
  • GitHub CI (ubuntu-latest): pass
  • Codex review (codex review --base origin/fix/ffmpeg-path-escaping, gpt-6.1-sol): "No actionable regressions were found." Nothing to fix or rebut. The gstack gate reads UNVERIFIED only because the review has no severity tags.

yultyyev and others added 3 commits October 29, 2026 10:57
Since FFmpeg 6.1, drawtext needs libharfbuzz as well as libfreetype, and
the Linux FFmpeg 7.0.2 build that ffmpeg-static 5.3.0 installs has no
harfbuzz. add_text, add_captions, add_title_card and timeline text clips
died there with FFmpeg's raw "No such filter: 'drawtext'". List the
resolved FFmpeg's filters once per process and throw MissingFilterError
before any text render, naming the binary and how to point
MAKEMYCLIP_FFMPEG_PATH at a build that has drawtext.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hoice

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yultyyev
yultyyev merged commit fc79352 into fix/ffmpeg-path-escaping Oct 29, 2026
1 check passed
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.3.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant