Fix subtitle burn-in: Homebrew's ffmpeg formula lacks libass - #133
Fix subtitle burn-in: Homebrew's ffmpeg formula lacks libass#133businessadam wants to merge 1 commit into
Conversation
Plain `brew install ffmpeg` on macOS ships without libass, so the `subtitles` filter doesn't exist at all — Hard Rule 1 (captions burned in) fails deep into a render instead of at install time, where it's much cheaper to catch. `ffmpeg-full` includes libass. install.md and README.md now check for the `subtitles` filter first and only install/link ffmpeg-full if it's missing, plus a verification line at the end of install so this shows up immediately rather than during someone's first real render.
There was a problem hiding this comment.
2 issues found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:63">
P2: The manual-install path unconditionally runs `brew link --overwrite ffmpeg-full`, which replaces the global `ffmpeg`/`ffprobe` symlinks system-wide on every machine, even ones whose existing ffmpeg already has libass. This contradicts the PR's stated design — install.md (in the same PR) guards this with `if ! ffmpeg -h filter=subtitles 2>&1 | grep -q "Filter subtitles"` and only falls back to ffmpeg-full when the filter is missing, and notes the relink is a system-wide change to surface to the user. Make the README path match so a working libass-enabled ffmpeg isn't silently overwritten.</violation>
</file>
<file name="install.md">
<violation number="1" location="install.md:142">
P2: When the `subtitles` filter is missing, `grep -q` finds no match and the `&& echo` is skipped, so this final verify line prints nothing on failure. The agent sees the two preceding `` OK`` lines and no error, so the missing-libass install failure stays silent — the exact outcome this PR sets out to prevent. Make the failure explicit with a `||` branch that prints a clear message and, ideally, exits non-zero.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| cd ~/Developer/video-use | ||
| uv sync # or: pip install -e . | ||
| brew install ffmpeg # required | ||
| brew install ffmpeg-full # required — plain `ffmpeg` lacks libass, so |
There was a problem hiding this comment.
P2: The manual-install path unconditionally runs brew link --overwrite ffmpeg-full, which replaces the global ffmpeg/ffprobe symlinks system-wide on every machine, even ones whose existing ffmpeg already has libass. This contradicts the PR's stated design — install.md (in the same PR) guards this with if ! ffmpeg -h filter=subtitles 2>&1 | grep -q "Filter subtitles" and only falls back to ffmpeg-full when the filter is missing, and notes the relink is a system-wide change to surface to the user. Make the README path match so a working libass-enabled ffmpeg isn't silently overwritten.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At README.md, line 63:
<comment>The manual-install path unconditionally runs `brew link --overwrite ffmpeg-full`, which replaces the global `ffmpeg`/`ffprobe` symlinks system-wide on every machine, even ones whose existing ffmpeg already has libass. This contradicts the PR's stated design — install.md (in the same PR) guards this with `if ! ffmpeg -h filter=subtitles 2>&1 | grep -q "Filter subtitles"` and only falls back to ffmpeg-full when the filter is missing, and notes the relink is a system-wide change to surface to the user. Make the README path match so a working libass-enabled ffmpeg isn't silently overwritten.</comment>
<file context>
@@ -60,7 +60,8 @@ ln -sfn ~/Developer/video-use ~/.claude/skills/video-use # Claude Code
cd ~/Developer/video-use
uv sync # or: pip install -e .
-brew install ffmpeg # required
+brew install ffmpeg-full # required — plain `ffmpeg` lacks libass, so
+brew link --overwrite ffmpeg-full # subtitle burn-in (Hard Rule 1) silently breaks
brew install yt-dlp # optional, for downloading online sources
</file context>
| ```bash | ||
| python ~/Developer/video-use/helpers/timeline_view.py --help >/dev/null && echo "helpers OK" | ||
| ffprobe -version | head -1 | ||
| ffmpeg -h filter=subtitles 2>&1 | grep -q "Filter subtitles" && echo "libass OK (subtitles filter present)" |
There was a problem hiding this comment.
P2: When the subtitles filter is missing, grep -q finds no match and the && echo is skipped, so this final verify line prints nothing on failure. The agent sees the two preceding OK lines and no error, so the missing-libass install failure stays silent — the exact outcome this PR sets out to prevent. Make the failure explicit with a || branch that prints a clear message and, ideally, exits non-zero.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At install.md, line 142:
<comment>When the `subtitles` filter is missing, `grep -q` finds no match and the `&& echo` is skipped, so this final verify line prints nothing on failure. The agent sees the two preceding `` OK`` lines and no error, so the missing-libass install failure stays silent — the exact outcome this PR sets out to prevent. Make the failure explicit with a `||` branch that prints a clear message and, ideally, exits non-zero.</comment>
<file context>
@@ -132,6 +139,7 @@ Run one real thing. Prefer the lightest verification that still proves the pipel
```bash
python ~/Developer/video-use/helpers/timeline_view.py --help >/dev/null && echo "helpers OK"
ffprobe -version | head -1
+ffmpeg -h filter=subtitles 2>&1 | grep -q "Filter subtitles" && echo "libass OK (subtitles filter present)"
</file context>
</details>
```suggestion
ffmpeg -h filter=subtitles 2>&1 | grep -q "Filter subtitles" && echo "libass OK (subtitles filter present)" || { echo "ERROR: ffmpeg lacks the subtitles filter (no libass). Install ffmpeg-full."; exit 1; }
Summary
On macOS, plain
brew install ffmpeg(whatinstall.mdcurrently tells every agent to run) ships without libass, so thesubtitlesfilter doesn't exist in that build at all. Since Hard Rule 1 (subtitles burned in last, after every overlay) depends entirely on that filter, any render that burns captions fails — but only when it gets to that step, deep into a render, not at install time where it'd be cheap to catch.ffmpeg-full(also in homebrew-core) is a superset build that includes libass. This PR:subtitlesfilter first (ffmpeg -h filter=subtitles) before doing anything, so machines that already have a libass-enabledffmpeg(common on Linux — apt/pacman both build with libass by default) aren't affected.brew install ffmpeg-full && brew link --overwrite ffmpeg-fullonly when the filter is missing.install.md's end-to-end check so this surfaces immediately on install rather than during someone's first real render.README.mdto match.Found this the hard way while rendering vertical clips with burned captions —
ffmpegran without error but silently had nosubtitlesfilter registered.Test plan
brew install ffmpegon macOS (Homebrew core formula) has nolibass/subtitlesfilter (ffmpeg -h filter=subtitles→Unknown filter 'subtitles')ffmpeg-fullhas it (ffmpeg -h filter=subtitles→Filter subtitles / Render text subtitles onto input video using the libass library.)brew link --overwrite ffmpeg-fullcorrectly repoints the globalffmpeg/ffprobesymlinksSummary by cubic
Fixes subtitle burn-in on macOS by ensuring
ffmpegincludeslibass. Previously, Homebrew’s defaultffmpeglacked thesubtitlesfilter, so caption burn-in failed late in renders; we now detect this early and install/linkffmpeg-fullwhen needed.ffmpeg -h filter=subtitles; if missing, runsbrew install ffmpeg-fullandbrew link --overwrite ffmpeg-full.subtitlesfilter is present so issues surface at setup, not during a render.README.mdto usebrew install ffmpeg-fullplus a link step.libass, but we document how to verify.ffmpeg-fullupdates system-wideffmpeg/ffprobesymlinks; it’s a superset offfmpeg.ffmpegshould rerun the install step or manuallybrew install ffmpeg-full && brew link --overwrite ffmpeg-full.Written for commit e5824fa. Summary will update on new commits.