# Real-ESRGAN video upscaler (local, free)

Upscales 480p AI-generated takes (Seedance etc.) 2x–4x before editing. Runs on the Apple GPU
(Metal) or CPU. No cloud, no account, no per-second cost. Model: Real-ESRGAN (BSD-3 licence,
Xintao Wang et al.), weights from the official GitHub releases.

Tested: macOS 26 on Apple Silicon, Python 3.11, PyTorch 2.14. About 1 s per 480x854 frame on
an M-series GPU (a 6 s clip ≈ 2.5 min). Also works on Linux/Windows with CUDA or CPU (slower).

## 1. Install once

```bash
./setup.sh
```

It creates a Python environment next to this file (uv if present, else `python3 -m venv`), installs the packages, downloads the two weight files from the official Real-ESRGAN GitHub releases into `weights/` and verifies their SHA-256. Re-running only fetches what is missing. The workflow installers (`install.sh`) run this for you.

Expected SHA-256:

```
4fa0d38905f75ac06eb49a7951b426670021be3018265fd191d2125df9d682f1  RealESRGAN_x4plus.pth
8dc7edb9ac80ccdc30c3a5dca6616509367f05fbc184ad95b731f05bece96292  realesr-general-x4v3.pth
```

To keep the weights elsewhere, set `ESRGAN_WEIGHTS=/path/to/weights`.

## 2. Use

```bash
venv/bin/python upscale_esrgan.py <in.mp4> <out.mp4> [model] [scale]
```

- `model`: `x4plus` (default quality pick: natural skin and hair) or `general` (3x faster, slightly smoother/plastic).
- `scale`: output size relative to the input, 2 (default) to 4. The net always runs at 4x and is
  downsampled with area filtering, which is cleaner than a native 2x.
- Output is H.264, CRF 12, same frame rate, no audio (the raw takes carry none; mux audio back with ffmpeg if needed).
- Quick test of one frame to a PNG: `FRAME=60 venv/bin/python upscale_esrgan.py in.mp4 test.png x4plus 2`

Batch a folder:

```bash
mkdir -p raw_up
for f in raw/*.mp4; do venv/bin/python upscale_esrgan.py "$f" "raw_up/$(basename "$f")" x4plus 2; done
```

## 3. Where it fits in the pipeline

Both workflows deliver every export twice by default: a **normal** copy rendered from the
original footage and an **upscaled** copy rendered from the same edit with the footage replaced
by its 2x upscale (`_upscaled` suffix). Upscale the source clips into a sibling folder
(`raw_up/` or `footage_up/`), build the composites or edit once, then render with each footage
set. Keep the original raws as the delivered "raw take" next to the finals.

## Limits

- It sharpens what the generator drew; it cannot add real detail, and very soft areas can turn
  slightly waxy. Compare one frame before committing to a full run.
- No temporal model: very fine textures may shimmer slightly between frames.
- Memory: a 480x854 frame at 4x needs about 2 GB of GPU/unified memory. For 720p sources on
  small machines, run `general` or reduce to CPU (slower, no memory limit).

## Files

- `upscale_esrgan.py` — self-contained (network definitions included; no `basicsr` dependency).
- `requirements.txt` — Python packages.
- `weights/` — not committed; download as above.
