Includes: - Extended caption styling (font, shadow, dimmed color, bg toggle) - Media server, subtitle downloader, VTT parser, processing modal - Waveform tiers, thumbnail/timeline improvements, transport controls - Hybrid download model, dependency management, clip export enhancements - 21 chat summaries, 2 implementation plans, 2 design specs Co-authored-by: Cursor <cursoragent@cursor.com>
3.2 KiB
Fix Caption Export Bugs (Round 2)
Task
Three bugs in the caption export implementation needed fixing after the initial burn-in/mux feature was added.
Bug 1: Burn-in filter syntax error
Symptom: ffmpeg error No option name near '/var/.../sanitized.vtt'
Root cause: format!("subtitles='{}'", path) passed literal single quotes to ffmpeg via Command::args(). Since there's no shell to strip them, ffmpeg tried to open 'sanitized.vtt' (with quotes in the filename).
Fix: Changed to format!("subtitles={}", path) — no quotes needed when passing args directly.
Bug 2: Wrong output duration (1:43 instead of 32s)
Symptom: Exported clip was 103 seconds instead of 32 seconds.
Root cause: Both subtitle functions used -to end_time with output seeking (-ss/-to after -i). After -ss discards initial frames and the muxer resets PTS to 0, -to 103 means "output 103 seconds" rather than "stop at input timestamp 103".
Fix: Replaced -to end_time with -t duration (clip.end_time - clip.start_time) in both build_ffmpeg_args_mux_subs and build_ffmpeg_args_burnin_subs. -t is unambiguous.
Bug 3: Muxed subtitles invisible in VLC
Symptom: Subtitle track exists in the file but selecting it in VLC shows nothing. Root cause: With output seeking, video PTS was reset to 0 by the muxer, but subtitle cues retained their original absolute timestamps (e.g., 71s-103s). The player sees subtitle cues at 71s but the video is only 32s long. Fix: Two-part strategy change:
- Added
trim_and_sanitize_vtt()function that extracts cues within the clip's time range and shifts all timestamps to start from 0. - Switched
build_ffmpeg_args_mux_substo use input seeking (-ss/-tbefore-i) for speed. The pre-trimmed VTT timestamps already start from 0, matching the video output. - Burn-in mode (
build_ffmpeg_args_burnin_subs) retains output seeking since thesubtitlesfilter needs to see the original absolute timestamps from the VTT.
Changes Made
src-tauri/src/services/clip_exporter.rs
- Removed single quotes from
subtitles=filter value - Changed
-to endto-t durationin both subtitle builder functions - Added
trim_and_sanitize_vtt()with VTT timestamp parsing/shifting - Added helper functions:
parse_vtt_timestamp_line(),parse_vtt_ts(),format_vtt_timestamp() - Switched
build_ffmpeg_args_mux_substo input seeking with pre-trimmed VTT - Updated
export_single_clip_with_substo use trimmed VTT for mux, sanitized VTT for burn-in - Updated all related tests (43 tests pass)
Lessons Learned
Command::args()in Rust bypasses the shell entirely — shell-style quoting (single quotes) becomes literal characters in the argument. Never quote paths for ffmpeg filters when usingCommand::args().- ffmpeg's
-tois ambiguous with output seeking — it may refer to post-PTS-reset time rather than input time.-t durationis always safe. - When using input seeking on video (
-ssbefore-i), subtitle PTS from a separate input must match the reset PTS (~0). Pre-trimming the VTT with shifted timestamps is the reliable approach.
Follow-up
None — all three user-reported bugs are addressed.