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

71 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).