Frame extraction fails on ffmpeg 9.0: -vsync was removed (use -fps_mode)
Frame extraction fails completely on ffmpeg 9.0, which removed the deprecated -vsync option. The result is transcript-only output with no frames — which for a skill whose purpose is giving Claude a visual input is a total failure rather than a degradation.
Notably this hits new Windows users following the plugin's own setup instructions: scripts/setup.py prints winget install Gyan.FFmpeg, and that package now ships 9.0. So a first run on a clean Windows box installs an ffmpeg the extractor cannot drive.
What happens
[watch] extracting scene-aware frames over full 421.4s (target 60, cap 60)…
ffmpeg scene extraction failed: Unrecognized option 'vsync'.
Error splitting the argument list: Option not foundDownload and caption retrieval both succeed; only frame extraction dies.
Cause
scripts/frames.py passes -vsync vfr in two places:
frames.py:256frames.py:615
-vsync was long deprecated in favour of -fps_mode and is removed in ffmpeg 9.0, so the whole command is rejected at argument-parsing time.
Reproduction (self-contained, no video needed)
# a source with real scene cuts
ffmpeg -f lavfi -i "testsrc=duration=2:size=160x90:rate=10" \
-f lavfi -i "smptebars=duration=2:size=160x90:rate=10" \
-f lavfi -i "color=c=navy:duration=2:size=160x90:rate=10" \
-filter_complex "[0:v][1:v][2:v]concat=n=3:v=1[v]" -map "[v]" -y scenes.mp4
# what frames.py sends today
ffmpeg -i scenes.mp4 -vf "select='gt(scene,0.1)',scale=128:-2" -vsync vfr a_%02d.jpg -y
# exit 8 — "Unrecognized option 'vsync'" → 0 frames
# the replacement
ffmpeg -i scenes.mp4 -vf "select='gt(scene,0.1)',scale=128:-2" -fps_mode vfr b_%02d.jpg -y
# exit 0 → 2 framesFix
Swapping -vsync vfr → -fps_mode vfr at both call sites resolves it. I ran the full pipeline on a 7-minute YouTube video that way and got frames as expected.
One caveat I have not verified: the earliest ffmpeg release that accepts -fps_mode. If the plugin intends to support older ffmpeg builds, a probe (e.g. checking ffmpeg -hide_banner -h full output, or the reported version) and choosing the flag accordingly would be safer than an unconditional swap. If the supported floor is recent enough, the straight swap is simpler.
Environment
| plugin | watch 0.2.0 (via bradautomates/claude-video) |
| ffmpeg | 9.0-full_build-www.gyan.dev (winget Gyan.FFmpeg) |
| yt-dlp | 2026.08.19 |
| OS | Windows 11 |
| Python | 3.13 |
Unrelated note that may still be useful
On this machine an antivirus product intercepts TLS, so yt-dlp failed with CERTIFICATE_VERIFY_FAILED — its root is in the Windows cert store, but Python verifies against a bundled CA list. Not a plugin bug, but the failure is opaque and Windows users may hit it. Injecting truststore (truststore.inject_into_ssl()) makes Python consult the OS trust store while leaving verification fully enabled, and fixed it cleanly. Possibly worth a troubleshooting line in the README.
Source: bradautomates/claude-video