fix(skills): caption burn works on FFmpeg 9 and silent takes - #556
Open
TobiOnabolu wants to merge 1 commit into
Open
TobiOnabolu wants to merge 1 commit into
TobiOnabolu wants to merge 1 commit into
Conversation
`caption_burn.py` from the `ugc-talking-head-video` skill could not complete a single render on a current machine, for two independent reasons. Both are fixed, and both are pinned by tests so they cannot regress silently. FFmpeg 9 removed `-filter_complex_script`, so every burn died with "Unrecognized option" before a frame was encoded. The release's replacement, `-/filter_complex`, does not appear in `ffmpeg -h full` — a capability probe has to execute ffmpeg to find it, and a naive substring probe matches `-filter_complex` inside it and picks the wrong flag. The graph is passed inline instead, which every version accepts, needs no escaping (the argv list goes straight to exec), and is far under ARG_MAX at caption-graph sizes. The render also mapped `0:a` unconditionally. A silent take has no audio stream, and the skill's own silent mode emits exactly that video-only file — so captions could not be burned onto the output that mode produces: ffmpeg aborted with `Stream map '' matches no streams`. Audio is now copied only when a stream exists. The render argv moves into `ffmpeg_command()` and the audio check into `has_audio()`, so both are verifiable without ffmpeg. Pillow is imported lazily: it is only needed to draw, and requiring it at import time made the module unimportable in an environment without it. Verified by rendering a real 12 s 9:16 take end to end — header at 12% height, captions at 78%, source audio untouched — and by `ffprobe` on the output.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Fixes two independent faults in
caption_burn.py(theugc-talking-head-videoskill's caption step),each of which aborted a render outright on a current machine. Both are now covered by tests.
FFmpeg 9 removed
-filter_complex_script. Every burn died withUnrecognized option 'filter_complex_script'before a frame was encoded. Worth recording why this is not a one-line flagbump: the replacement the release points at,
-/filter_complex, does not appear inffmpeg -h full, so no capability probe finds it by inspection — and a naive substring probematches
-filter_complexinside-/filter_complexand silently returns the wrong flag (I hitexactly this while fixing it). Passing the graph inline sidesteps the version question entirely:
every version accepts it, the argv list reaches
execdirectly so there is no escaping step, and acaption graph is far under
ARG_MAX.A silent take has no audio stream, but the render mapped
0:aunconditionally. ffmpeg abortedwith
Stream map '' matches no streams. The sting is that the skill's own silent mode emits exactlythat video-only file, so captions could not be burned onto the output that mode produces. Audio is
now copied only when a stream is actually present.
How it was tested
tests/test_ugc_caption_burn.py— 5 passed:To make the command checkable without ffmpeg, the render argv moves into
ffmpeg_command()and theaudio probe into
has_audio(); the assertions read the argv directly. Pillow is imported lazily —it is only needed to draw, and the module-level import made the script unimportable anywhere
without it.
Also rendered a real 12 s 9:16 take end to end and inspected it:
ffprobeconfirms a silent input still yields a captioned output (0 audio streams in, 0 out)dark outline, source video otherwise untouched
Not run: the full suite. PyPI's CDN (
files.pythonhosted.org) is unreachable from this machine,so
uv synccannot resolve the dev dependencies and the repo'sconftest.py(which imports FastAPI)does not load. The 5 tests above were run under real pytest 9.0.3 against an isolated copy of the
test file. Treat CI as the authority on the whole suite; if the run is blocked pending approval,
that is the sandbox, not a failure.
Checklist
uv run --with pytest-xdist pytest -n auto -qpasses locally — could not run in full, see abovedocs/context/fragment — not applicable; no subsystem changed, thescript is a standalone skill asset and no fragment documents it