# MOV8mm v3

Shot-aware, resumable restoration pipeline for 8mm home-movie reels.
Built for an RTX 4060 Laptop (8GB), Windows 11, Python/PyTorch.

The organizing principle: **per-shot exposure and color consistency** — not
resolution — is what makes old footage read as modern. So the pipeline detects
shots first and processes each one independently for anything photometric.

- **Step list / spec:** [docs/spec.md](docs/spec.md)
- **Rationale & research:** [docs/V3_BUILD_Recomendation.md](docs/V3_BUILD_Recomendation.md)
- **Backlog:** [docs/backlog.md](docs/backlog.md)

## Architecture in one paragraph

One orchestrator ("the boss") never imports a model. It builds a job grid of
`(shot × stage)`, runs cheap classical stages in-process, and dispatches heavy/
conflicting models as **subprocesses into their own isolated venv** (each named
`env`). Stages hand off via **lossless FFV1/MKV** files, and every cell is
tracked in a **resumable JSON manifest** — a crash costs one shot-stage, not the
whole reel.

## Status: MVP reached (Phases 0–2)

The pipeline runs a real, shot-aware restoration end-to-end:

- **B2 shot detection** — PySceneDetect AdaptiveDetector (tuned for 8mm).
- **B3 stabilize** — FFmpeg vid.stab, gate-weave / jitter removal (per shot).
- **B4 photometric** — per-shot deflicker (temporal luminance normalization).
- **B6 scratch** — dust/dirt removal (RemoveDirt) via AviSynth+ (`runners/avisynth/`).
- **B5 denoise** — MDegrain2 motion-compensated denoise via the same AviSynth+ runner.
- **B7 upscale** — Real-ESRGAN x4plus on the GPU (`runners/upscale/`, tiled for 8GB).
- **B8 faces** — KEEP (ECCV 2024) video-native restoration on the GPU
  (`runners/keep/`), with tunable detection for soft 8mm faces.
- **B9 color** — per-shot cast removal + gray-world WB + blue-shadow grain fix.

**Every processing stage is now real — no stubs left.** The orchestrator itself
stays model-free; heavy work lives in isolated `runners/*` (see
[runners/README.md](runners/README.md)). Remaining work is quality upgrades
(temporal SR, BM3DCUDA, film LUT, grain re-inject) and a full dual-mode run.

## Setup

```powershell
python -m venv env
.\env\Scripts\Activate.ps1
pip install -r requirements.txt
```

Requires **FFmpeg** on PATH (gyan.dev build with libsvtav1, libx264, libvidstab)
and, for GPU stages later, **NVIDIA driver ≥570**. Check your environment:

```powershell
python -m orchestrator.pipeline --doctor
```

## Run the null pipeline

```powershell
# drop a clip into input_videos/, then:
python -m orchestrator.pipeline input_videos\test.mp4 --mode faithful

python -m orchestrator.pipeline input_videos\test.mp4 --reset   # start clean
```

Outputs land in `output_videos/` as three tiers:
`*.archival.mkv` (FFV1), `*.viewing.mp4` (SVT-AV1 10-bit), `*.sharing.mp4` (x264).

## Cut & stitch first (B0 — work on only the frames you care about)

Trim a long reel to the moments you want and stitch them into a shorter clip
*before* any processing, so every stage only touches those frames:

```powershell
# keep seconds 0–10 and 0:43–0:47, then run the whole pipeline on the result:
python -m orchestrator.pipeline Movie0015.MP4 --keep 0-10,0:43-0:47 --mode faithful

# or drive the cut from a JSON edit-list:
python -m orchestrator.pipeline --edl edits\movie0015.json --mode faithful
```

The cut is a tracked, resumable step — change the ranges and the pipeline
re-cuts and re-runs only what's affected. `cut.py` can also be run on its own
(`python -m orchestrator.cut Movie0015.MP4 --keep 0-10,0:43-0:47`) to preview a
cut without processing. List every tool with `python -m orchestrator`.

## Layout

```
orchestrator/   the boss: pipeline, shots, state, ffio, doctor, stages/
runners/        isolated model envs, called via subprocess (see runners/README.md)
work/           lossless intermediates + manifest.json per job (gitignored)
config/         faithful.json / modern.json presets
tests/          metric tools + regression corpus
```
