Files
gui-video-clipper/chat-summaries/2026-09-21_12-56-fix-playback-codec-timeline-pan-summary.md
cottongin 8ad2f1c800 chore: stage all pending work — caption styling, media server, processing modal, docs, summaries
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>
2026-09-22 10:48:16 -04:00

3.2 KiB

Fix: Video Codec Compatibility + Timeline Pan/Scroll + Minimap

Date: 2026-09-21 12:56
Task: Fix video playback (black screen despite play state), add timeline panning when zoomed, add minimap overview.

Root Causes & Fixes

1. Video playback: WKWebView doesn't support VP9/WebM

The downloaded file was VP9+Opus in WebM container (yt-dlp format 399+251). Apple's WKWebView on macOS does NOT support VP9 codec. The <video> element accepted .play() but had no decodable frames.

Fix: Added -f "bv*[vcodec^=avc1]+ba[acodec^=mp4a]/bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]/b" to the yt-dlp download command in download_manager.rs. This selects H.264 (avc1) video + AAC (mp4a) audio, producing an MP4 file playable by WKWebView. Deleted the cached WebM file.

2. Timeline: no scroll/pan when zoomed

Mouse wheel only triggered zoom. No way to scroll horizontally when zoomed in.

Fix in Timeline.svelte:

  • Horizontal scroll → pan: deltaX from trackpad/shift+wheel now calls panBy() to shift the visible window
  • Vertical scroll → zoom (unchanged)

New panBy() in interactions.ts: Computes new visibleStart/visibleEnd from pixel delta, clamped to [0, duration].

3. Minimap overview bar

Added a minimap canvas that appears when zoomed in:

  • Shows the full waveform at a glance
  • Highlights the current viewport with a blue border
  • Dims regions outside the viewport
  • Click to center viewport, drag to pan
  • Playhead indicator

4. Other fixes applied this session (cumulative)

  • stdout/stderr swap: yt-dlp sends status messages to stdout, not stderr
  • [Merger] path parsing: Correctly captures final merged file path
  • "Already downloaded" parsing: Handles has already been downloaded message
  • Cache check: checkCachedDownload(title) checks temp dir before invoking yt-dlp
  • Parallel processing: Waveform/thumbnails/keyframes results applied individually as they complete
  • Asset protocol scope: Added /private/var/** and /var/** for macOS symlink paths

Files Changed

  • src-tauri/src/services/download_manager.rs — H.264 format selection
  • src/lib/components/Timeline.svelte — Minimap + horizontal pan support
  • src/lib/timeline/interactions.ts — Added panBy() function
  • src-tauri/src/commands/video.rs — Cache check, diagnostic logging
  • src-tauri/src/commands/media_analysis.rs — Diagnostic logging
  • src-tauri/src/lib.rs — Registered check_cached_download command
  • src-tauri/tauri.conf.json — Expanded asset protocol scope
  • src/lib/stores/videoSession.svelte.ts — Cache check before download, parallel results
  • src/lib/bindings/video.ts — checkCachedDownload binding
  • src/lib/components/VideoPlayer.svelte — Local file playback with progress UI

Lessons Learned

  1. WKWebView codec support is limited. VP9/AV1/WebM don't work. Must use H.264+AAC in MP4.
  2. macOS /var is a symlink to /private/var. Asset protocol scope must cover both paths.
  3. Promise.allSettled blocks all results until the slowest completes. Use individual .then() chains when you want progressive rendering.
  4. yt-dlp sends status to stdout, warnings to stderr. Not the other way around.