Stitch cleanup and grading!

This commit is contained in:
2026-07-15 20:00:04 +02:00
parent 83715e85e8
commit 38e6c7940c
8 changed files with 81 additions and 37 deletions
+12 -18
View File
@@ -1313,7 +1313,7 @@ def _import_narration_segments(narration_dir: Path, config, verbose: bool) -> No
media/narration/processed/ ← chroma-keyed output (preprocess)
media/narration/narration.json
Scans processed/ for ready-to-stitch files and raw/ for any new raw
Scans processed/ for ready-to-render files and raw/ for any new raw
recordings not yet represented in narration.json.
Priority: processed/ files define the segment catalogue.
@@ -1410,7 +1410,7 @@ def _import_narration_segments(narration_dir: Path, config, verbose: bool) -> No
}
narration_entry["use_audio_channels"] = "auto"
# Loudnorm is applied per-segment during preprocess (not deferred to
# stitch), so the processed files are already normalized and ready to be
# preprocess), so the processed files are already normalized and ready to be
# concatenated directly at render time.
narration_entry["defer_loudnorm"] = False
@@ -1438,7 +1438,7 @@ def _import_narration_segments(narration_dir: Path, config, verbose: bool) -> No
narration_entry["use_audio_channels"] = "auto"
# Loudnorm is applied per-segment during preprocess (not deferred to
# stitch), so the processed files are already normalized and ready to be
# preprocess), so the processed files are already normalized and ready to be
# concatenated directly at render time.
narration_entry["defer_loudnorm"] = False
@@ -2367,7 +2367,7 @@ def cmd_preprocess(
cache_root = _resolve_process_cache(project_path, config)
if cache_root:
# Mirror the project's media/ structure so GnommoCache (resolve_with_cache)
# finds these files transparently during render/stitch.
# finds these files transparently during render.
cache_narration_dir = cache_root / "media" / "narration"
cache_narration_dir.mkdir(parents=True, exist_ok=True)
(cache_narration_dir / "processed").mkdir(parents=True, exist_ok=True)
@@ -2459,9 +2459,8 @@ def cmd_preprocess(
if using_compressed and segment_id.endswith("_compressed"):
segment_id = segment_id[: -len("_compressed")]
# For non-full res, write into the res subdir so stitch --res low finds the
# files at narration/low/processed/ (narration.json still records the plain
# "processed/..." path; stitch shifts the base dir itself).
# For non-full res, write processed outputs into the res subdir.
# (narration.json still records the plain "processed/..." path.)
_res_cfg = RES_CONFIGS.get(res) if res != "full" else None
if _res_cfg:
_, _, _subdir = _res_cfg
@@ -2469,7 +2468,7 @@ def cmd_preprocess(
else:
output_file = f"processed/{segment_id}_processed.mov"
# When process_cache is set, output goes to the cache dir; narration.json
# still records the relative path so stitch (also using cache) can find it.
# still records the relative path so render (also using cache) can find it.
output_base = cache_narration_dir or narration_dir
output_path = output_base / output_file
@@ -2606,7 +2605,7 @@ def cmd_preprocess(
for key in _PRESERVE_KEYS:
if key in existing_entry:
entry[key] = existing_entry[key]
# Always record the plain path; stitch shifts the base dir for low/tiny.
# Always record the plain path; the res subdir shift happens at render for low/tiny.
entry["source_file"] = f"processed/{segment_id}_processed.mov"
entry.setdefault("use_audio_channels", "auto")
entry.setdefault("defer_loudnorm", False)
@@ -3120,7 +3119,7 @@ def _transcode_processed_files(
1. Transcode to a temp file using hevc_videotoolbox with alpha.
2. Move the ProRes original into a prores/ subdirectory (never deleted).
3. Rename the compressed file to the original _processed.mov name
so stitch/render find it unchanged.
so render finds it unchanged.
The prores/ subdirectory is never scanned — only top-level files are candidates.
If prores/<filename> already exists the file has already been compressed —
@@ -3297,7 +3296,7 @@ def cmd_transcode(
Compress _processed.mov files (ProRes 4444 + alpha) to HEVC+alpha.
Archives the ProRes original as _prores.mov (never deleted).
The compressed file takes the original _processed.mov name so the
rest of the pipeline (stitch, render) finds it unchanged.
rest of the pipeline (render) finds it unchanged.
Uses Apple VideoToolbox (hevc_videotoolbox) with --alpha-quality.
"""
if processed:
@@ -3440,11 +3439,6 @@ def cmd_transcode(
return 0
# =============================================================================
# Stitch Command (fast iteration on narration segments)
# =============================================================================
# =============================================================================
# Render Command
# =============================================================================
@@ -4292,7 +4286,7 @@ def cmd_render(
)
# Timestamp guard (make-style): even if the fingerprint matches, re-render
# when a key upstream artifact — the stitched narration or its transcript —
# when a key upstream artifact — the concatenated narration or its transcript —
# is newer than the rendered output. This catches cases the fingerprint
# can't: the state file isn't transferred to the render rig (it's a dotfile),
# and the combined may live on an external cache disk. If the previous stage
@@ -4674,7 +4668,7 @@ def cmd_all(
result = cmd_trim(project_path, verbose, force=cascade_force, threshold_db=-40.0)
if result != 0:
return result
# Trim modifies narration.json skip/take values; any change invalidates stitch
# Trim modifies narration.json skip/take values; any change invalidates the render
if _files_modified_since(project_path, t0, "narration.json"):
cascade_force = True