Files
live-photo-concat/CLAUDE.md
T
ergosteur e1cd699b79 Add CLAUDE.md with context not covered by README or code comments
Documents things a future session would otherwise have to rediscover:
no test suite/fixtures exist (verification requires real sample clips
and ffprobe checks), the libvmaf stderr spam is a dev-machine quirk
not a bug, detection thresholds were empirically tuned on one real
dataset, the -r 30 normalization is load-bearing for bitrate targeting
and shouldn't be removed casually, and a cross-platform GUI was
considered and deliberately deferred.
2026-07-26 13:07:33 -04:00

3.8 KiB
Raw Blame History

CLAUDE.md

Guidance for working in this repo that isn't already covered by README.md or the scripts' own docstrings/comments.

There is no test suite, and no fixture files in the repo

.gitignore excludes *.mov/*.MOV, so there are no sample clips checked in. The overlap-detection logic depends on real iPhone HEVC/PCM quirks (variable frame rate, the exact multi-track Live Photo container structure, genuinely-correlated real-world audio at clip boundaries) that aren't practical to fake convincingly with synthetic ffmpeg test inputs. To verify a change to concat_live_clips.py, ask the user for a real set of sequential Live Photo .MOV files (or reuse ones from earlier in the conversation if still on disk) and check results with ffprobe:

  • ffprobe -show_entries format=duration — output duration should equal the sum of (each clip's duration its detected overlap).
  • ffprobe -select_streams v -show_entries frame=pts_time — verify strictly increasing timestamps (no reordering artifacts at the joins).
  • ffprobe -show_entries format_tags — confirm GPS/device/Live-Photo tags made it through from the source clip.
  • Cross-check detected overlap/gap values against the clips' com.apple.quicktime.creationdate tags by hand for a sanity read before trusting a change to the correlation math.

The libvmaf stderr spam is an environment quirk, not a bug

Every libx265 encode on this dev machine prints repeated libvmaf ERROR could not read model from path: ... / problem loading model file lines. This reproduces with a trivial synthetic -c:v libx265 encode with zero flags, and -x265-params log-level=none does not suppress it — it comes from libvmaf itself, not from anything this script requests, and doesn't affect output correctness (exit code 0, correct output every time this was checked). Don't spend time chasing it as if it were caused by this codebase; the user has explicitly said they're fine with it showing.

Detection thresholds are empirically tuned on one real dataset, not derived analytically

--confidence-threshold (0.9), --min-signal-rms (25), --bitrate-multiplier (1.2), and --bitrate-floor (10M) were chosen by testing against two real clip sets from one iPhone (see conversation history / commit messages for the actual numbers observed: correlation scores landed either ~1.000 or well below ~0.6, RMS values were in the hundreds for real audio content). They aren't validated across other devices, iOS versions, or recording environments. If a user reports a false abort or a false pass, prefer surfacing the actual score/RMS numbers (already printed) over silently loosening a default.

Rate-control depends on the -r 30 normalization — don't remove it

concat_live_clips.py forces constant 30fps output (see the comment above video_args += ["-r", "30", ...]). This was added after the bitrate-target mode was found to silently undershoot by >10x (target ~13Mbps, actual ~1Mbps, x265 hitting max QP) because the source clips' irregular VFR timestamps confused x265's ABR rate control once concatenated. If touching the encoding args, keep this normalization or re-verify bitrate targeting actually hits its target (check ffprobe -show_entries stream=bit_rate on the output, not just that the encode succeeds).

A cross-platform GUI was considered and explicitly deferred

The user asked about a GUI, wanted it to look good on Mac/Windows/Linux and possibly iOS, then decided against it once the iOS scope implication became clear (iOS would require either a full native rewrite or a client-server model, not just a new frontend on the same script). Don't reintroduce that scope unprompted; if asked again, the open question is specifically desktop-only vs. desktop+mobile, since that decision determines the whole architecture (e.g. Tkinter/PySide6 vs. a local web app).