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>
42 lines
3.2 KiB
Markdown
42 lines
3.2 KiB
Markdown
# 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.
|