# Ядро рендера: выбор кодера, GPU и длинные таймлайны

## Наличие кодера в ffmpeg ничего не значит

`ffmpeg -encoders` перечисляет `av1_nvenc` на картах Pascal, которые физически не
умеют кодировать AV1, и продолжает показывать `h264_nvenc`, когда драйвер слишком стар
для API, под который собран ffmpeg. И то и другое падает уже после того, как рендер
поставлен в очередь.

Поэтому каждый кандидат прогоняется настоящим кодированием нескольких кадров в
реальном разрешении (пробник 16×16 проходит на драйверах, которые затем валятся на
1080p). Результат кэшируется вместе с версией драйвера — обновление драйвера
инвалидирует кэш.

```bash
python scripts/render_core.py --refresh --benchmark
```

## Отказ переводится в действие

Не «ошибка -22», а разбор причины. Пример с реальной машины:

```
h264_nvenc: эта сборка FFmpeg собрана под NVENC API 13.1, а драйвер 582.66 даёт 13.0.
Нужен драйвер NVIDIA 610.00 или новее — либо сборка FFmpeg под старый NVENC SDK.
Рендер идёт на CPU, это не ошибка скрипта.
```

Распознаются также «нет подходящего устройства для этого кодека» и «превышен лимит
одновременных NVENC-сессий».

## GPU-декод — отдельный вопрос от GPU-кодирования

Две разные вещи, и путать их легко:

* `-hwaccel cuda` декодирует на GPU и отдаёт кадры в системную память, поэтому
  обычные CPU-фильтры работают как есть;
* `-hwaccel cuda -hwaccel_output_format cuda` держит кадры в памяти GPU, и любому
  CPU-фильтру нужен `hwdownload` перед ним.

Вставленный `hwdownload` на первом пути падает — именно из-за этого ранняя версия
пробника объявляла CUDA неработающей на машине, где она работает.

Пробник измеряет **обе** ветки против чистого CPU-декода и включает ускорение только
если оно реально быстрее (`worth_using`, порог 1.25×). На средней карте выигрыш на
декоде часто в пределах погрешности, а сложность графа растёт — включать это по
умолчанию было бы карго-культом.

## Профили качества

| Профиль | Для чего | x264 CRF | NVENC CQ |
|---|---|---|---|
| `master` | Финальный мастер, время не важно | 16 | 17 |
| `delivery` | Готовый ролик для платформы | 18 | 19 |
| `draft` | Черновик для проверки монтажа | 22 | 25 |
| `proxy` | Прокси для монтажа длинного видео | 26 | 30 |

CRF и CQ — разные шкалы: одинаковое воспринимаемое качество требует у NVENC чуть
меньшего числа.

Все рендеры скилла берут кодер отсюда, поэтому решение принимается один раз и
одинаково во всех шагах, а не угадывается каждым скриптом отдельно.

## Длинные видео: чанки вместо одного прохода

Часовой таймлайн одним запуском ffmpeg — плохая ставка: падение на 52-й минуте
выбрасывает всё, память растёт вместе с графом фильтров, и середину нельзя посмотреть,
не дождавшись конца.

```bash
python scripts/render_chunked.py long.mp4 out.mp4 \
  --chunk-seconds 120 --vf "ass=filename=captions.ass:fontsdir=assets/fonts/all" \
  --chapters chapters.ffmetadata.txt
```

Что делает шов незаметным:

* все чанки кодируются **одинаковыми** настройками и принудительно открываются
  ключевым кадром — это то, что нужно демультиплексору `concat`, чтобы копировать
  потоки;
* границы чанков выровнены по кадровой сетке;
* звук по желанию перекодируется только в проходе склейки. AAC несёт encoder priming
  в начале каждого чанка, и копирование его насквозь может оставить щелчок на каждом
  шве — перекодирование только звука занимает секунды и убирает это, пока видео
  по-прежнему копируется.

Проверено на 113-секундном исходнике, 6 чанков: расхождение длительности 84 мс,
максимальный скачок сэмплов на швах **ниже** локального 99-го процентиля (щелчок дал
бы превышение в десять раз).

### Возобновление по содержимому, а не по имени файла

Каждый чанк записывает точные параметры, с которыми он был отрендерен. Чанк
переиспользуется только если параметры совпадают и файл всё ещё читается. Упавший
рендер продолжается той же командой.

## Прокси-подход для монтажа

Для решений о монтаже часового видео не нужен мастер-битрейт:

```bash
python scripts/render_chunked.py master.mov proxy.mp4 --profile proxy \
  --vf "scale=-2:720" --chunk-seconds 300
```

Все планы (`recut_plan.json`, `transition_plan.json`, `caption_map.json`) работают во
времени, а не в пикселях, поэтому один и тот же план применяется и к прокси, и к
мастеру.
