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.
This commit is contained in:
@@ -0,0 +1,70 @@
|
|||||||
|
# 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).
|
||||||
Reference in New Issue
Block a user