Files
gui-video-clipper/chat-summaries/2026-09-21_21-36-fix-caption-export-bugs-summary.md

42 lines
3.2 KiB
Markdown
Raw Normal View History

# 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:
1. Added `trim_and_sanitize_vtt()` function that extracts cues within the clip's time range and shifts all timestamps to start from 0.
2. Switched `build_ffmpeg_args_mux_subs` to use **input seeking** (`-ss`/`-t` before `-i`) for speed. The pre-trimmed VTT timestamps already start from 0, matching the video output.
3. Burn-in mode (`build_ffmpeg_args_burnin_subs`) retains **output seeking** since the `subtitles` filter 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 end` to `-t duration` in 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_subs` to input seeking with pre-trimmed VTT
- Updated `export_single_clip_with_subs` to 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 using `Command::args()`.
- ffmpeg's `-to` is ambiguous with output seeking — it may refer to post-PTS-reset time rather than input time. `-t duration` is always safe.
- When using input seeking on video (`-ss` before `-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.