Транскодирование видео: ffmpeg, NVENC и AV1

TL;DR

  • Сценарии: массовый VOD‑транскод (архив/UGC), создание ABR‑лесенок (HLS/DASH), подготовка прокси‑копий/тизеров/тумбов.
  • Режимы: — Оффлайн/массово → Interruptible, чанк ≤ 120 с, ретраи, локальный NVMe‑кэш. См. https://cloudcompute.ru/solutions/interruptible-patterns/ — Интерактив/превью/монтаж → On‑Demand, SLA по p95 latency. См. https://cloudcompute.ru/solutions/throughput-vs-latency/
  • GPU‑профили: 24 ГБ (Compact) — прокси/SD‑HD; 48 ГБ (Balanced) — основная «рабочая лошадь» для 1080p/1440p; 80 ГБ (HQ) — 4K/8K, множественные параллели/фильтры.
  • Кодеки: h264_nvenc, hevc_nvenc, av1_nvenc; декод на cuda/NVDEC; GPU‑фильтры scale_npp/scale_cuda.
  • Хранилище: входные файлы в «тёплом», сегменты/артефакты — на NVMe, итог в «холодное». См. https://cloudcompute.ru/solutions/storage-data/
  • Наблюдаемость: transcode_rtf, fps_in/fps_out, nvenc_utilization, gpu_utilization, drop_total, p50/p95 latency. См. https://cloudcompute.ru/solutions/monitoring-logging/
  • Экономика: Cost_per_1K_min = (c_gpu * t_proc_1Kmin / 60) / U * r; при ABR‑лесенке учитывайте суммарный битрейт и число рендишенов. См. https://cloudcompute.ru/solutions/cost-planner/
  • Оптимизация: zero‑copy, pinned memory, конвейер decode→filter→encode на GPU, -rc-lookahead, AQ, размер GOP, длина сегмента. См. https://cloudcompute.ru/solutions/performance-tuning/

Сценарии: когда это нужно

  • VOD‑архив/UGC — массовая перекодировка в стандартизированный набор профилей (ABR‑лесенка).
  • Редакционный/промо — быстрые прокси/тизеры из mezzanine.
  • Каталоги/репозитории — нормализация кодеков/контейнеров, проверка соответствия, пост‑обработка (денойз/стаб). См. https://cloudcompute.ru/solutions/rendering/de-noising/
  • Переупаковка — дробление на HLS/DASH‑сегменты, мастер‑плейлист, постингест в VOD‑origin.

Архитектуры/пайплайны A. Ферма VOD‑транскода (batch)

[Ingest (Warm Storage)] -> [Validator/Probe] -> [Job Queue] -> [Prefetch -> NVMe Cache]
 |
 +------------------+------------------+
 | |
 [GPU Worker #1] [GPU Worker #N]
 (NVDEC -> scale_npp -> NVENC) (NVDEC -> scale_npp -> NVENC)
 | |
 [HLS/DASH Renditions] [Thumbnails/Proxies]
 /
 +------> [Packager/QA] -> [Cold Storage / Origin]

Ключи: префетч входа на NVMe, decode/фильтры/encode на GPU, сегментация ≤ 120 с для устойчивости Interruptible, idempotent‑вывод по сегментам.

B. Live→VOD (just‑in‑time постобработка)

[Live Ingest] -> [GPU Transcode Ladder] -> [HLS/DASH Live] -> [Archive Segments] -> [Batch VOD Normalizer]

Разделяем live‑SLA и оффлайн‑нормализацию; VOD‑нормализатор может работать как Interruptible.

C. Превью/монтаж (интерактив)

[Editor/Operator] -> [Remote GPU Workstation] -> [NVENC Stream] -> [Viewer]
 метрики: p95 input->pixel, fps_actual, nvenc_utilization

См. удалённые станции: https://cloudcompute.ru/solutions/rendering/studio-remote/

Профили GPU/VRAM/скорости (ориентиры)

**Профиль** **VRAM** **Типовые задачи** **Режим** **Отн. throughput (≈)** **Примечания**
**24 ГБ (Compact)** 24 ГБ Прокси, SD/HD, 1–2 параллельных рендишена Interruptible / On‑Demand 1.0 Следить за NVENC‑сессиями и I/O
**48 ГБ (Balanced)** 48 ГБ 1080p/1440p, 2–4 рендишена, базовые фильтры Interruptible / On‑Demand 1.5–1.8 Базовый профиль фермы
**80 ГБ (HQ)** 80 ГБ 4K/8K, много рендишенов/фильтров, пакетное HQ On‑Demand / Interruptible 2.2–2.6 Комфортный запас VRAM и NVENC‑конкуренция

Индексы относительны; фактическая скорость зависит от входного кодека/битрейта/фильтров.

Конфиги и скелеты

1) Быстрый H.264 (3‑поточная ABR‑лесенка HLS) — NVDEC→NVENC

# Вход -> 240p/480p/720p, HLS со стаб. GOP, «независимые сегменты»
ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 
-filter_complex "
 [0:v]split=3[v240][v480][v720]; 
 [v240]scale_npp=426:240:interp_algo=lanczos,format=yuv420p[v240o]; 
 [v480]scale_npp=854:480:interp_algo=lanczos,format=yuv420p[v480o]; 
 [v720]scale_npp=1280:720:interp_algo=lanczos,format=yuv420p[v720o]" 
-map "[v240o]" -c:v:0 h264_nvenc -preset p5 -tune hq -rc vbr -b:v:0 400k -maxrate:v:0 500k -bufsize:v:0 800k -g 120 -keyint_min 120 -sc_threshold 0 -bf 3 -rc-lookahead 20 -spatial_aq 1 -temporal_aq 1 
-map "[v480o]" -c:v:1 h264_nvenc -preset p5 -tune hq -rc vbr -b:v:1 1200k -maxrate:v:1 1500k -bufsize:v:1 2500k -g 120 -keyint_min 120 -sc_threshold 0 -bf 3 -rc-lookahead 20 -spatial_aq 1 -temporal_aq 1 
-map "[v720o]" -c:v:2 h264_nvenc -preset p5 -tune hq -rc vbr -b:v:2 2800k -maxrate:v:2 3500k -bufsize:v:2 6000k -g 120 -keyint_min 120 -sc_threshold 0 -bf 3 -rc-lookahead 32 -spatial_aq 1 -temporal_aq 1 
-map a:0 -c:a:0 aac -b:a:0 64k -ar 48000 -ac 2 
-map a:0 -c:a:1 aac -b:a:1 96k -ar 48000 -ac 2 
-map a:0 -c:a:2 aac -b:a:2 128k -ar 48000 -ac 2 
-f hls -hls_time 4 -hls_playlist_type vod -hls_flags independent_segments 
-var_stream_map "v:0,a:0 v:1,a:1 v:2,a:2" 
-master_pl_name master.m3u8 -hls_segment_filename "v%v/seg_%06d.ts" "v%v/index.m3u8"

Заметки: единый GOP (-g/-keyint_min) и -sc_threshold 0 для ровного сегментирования; AQ/-rc-lookahead улучшают визуальное качество при VBR.

2) HEVC/AV1 (VOD высокого качества)

# HEVC (H.265) NVENC
ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input_prores.mov 
-c:v hevc_nvenc -preset p6 -tune hq -rc vbr -b:v 8M -maxrate 10M -bufsize 20M 
-spatial_aq 1 -temporal_aq 1 -rc-lookahead 40 -g 120 -bf 3 
-c:a aac -b:a 192k -movflags +faststart out_hevc.mp4
# AV1 NVENC (VOD; проверьте декод‑совместимость вашей витрины)
ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input_prores.mov 
-c:v av1_nvenc -preset p5 -rc vbr -b:v 6M -maxrate 8M -bufsize 16M 
-spatial_aq 1 -temporal_aq 1 -rc-lookahead 40 -g 240 -bf 5 
-c:a aac -b:a 192k out_av1.mp4

3) DASH‑пакетирование из одного прохода

ffmpeg -y -hwaccel cuda -hwaccel_output_format cuda -i input.mp4 
-filter_complex "[0:v]scale_npp=1920:1080:interp_algo=lanczos[v1080];[0:v]scale_npp=1280:720[v720]" 
-map "[v1080]" -c:v:0 h264_nvenc -b:v:0 5M -g 120 -keyint_min 120 -sc_threshold 0 -bf 3 -rc vbr -rc-lookahead 32 
-map "[v720]" -c:v:1 h264_nvenc -b:v:1 3M -g 120 -keyint_min 120 -sc_threshold 0 -bf 3 -rc vbr -rc-lookahead 32 
-map a:0 -c:a:0 aac -b:a:0 160k -map a:0 -c:a:1 aac -b:a:1 128k 
-use_template 1 -use_timeline 1 -seg_duration 4 -init_seg_name 'init_$RepresentationID$.mp4' 
-media_seg_name 'chunk_$RepresentationID$_$Number%06d$.m4s' -adaptation_sets "id=0,streams=v id=1,streams=a" 
-f dash manifest.mpd

4) Чанк‑транскод для Interruptible (идемпотентные сегменты)

# Пример: кодируем кусок 0..120 c и пишем независимый HLS-фрагмент
ffmpeg -y -ss 0 -t 120 -i input.mp4 -c:v h264_nvenc -g 120 -keyint_min 120 -sc_threshold 0 
-f hls -hls_time 4 -hls_flags independent_segments+append_list+omit_endlist 
-hls_segment_filename "chunk_0000/seg_%06d.ts" "chunk_0000/index.m3u8"
# Следующий чанк 120..240 c -> chunk_0001/...

Смысл: каждый чанк самодостаточен (ключевые кадры на границах), ретраи не портят общий плейлист. Сборка мастер‑плейлиста — постпроцесс.

5) YAML‑спека задания очереди

job:
 name: "vod_2025q1_abrladder"
 mode: "interruptible" # on-demand | interruptible
 gpu_profile: "48GB-Balanced" # 24GB-Compact | 48GB-Balanced | 80GB-HQ
 chunk_seconds: 120
 retries: 3
 input:
 uri: "s3://warm-bucket/in/video_001.mov"
 probe: true
 ladder:
 renditions:
 - {name: "240p", w: 426, h: 240, v_bitrate: "400k", a_bitrate: "64k"}
 - {name: "480p", w: 854, h: 480, v_bitrate: "1200k", a_bitrate: "96k"}
 - {name: "720p", w: 1280, h: 720, v_bitrate: "2800k", a_bitrate: "128k"}
 packaging:
 type: "hls" # hls | dash
 segment: 4
 independent_segments: true
 cache:
 nvme_size_gb: 200
 prefetch: true
 output:
 uri: "s3://cold-bucket/vod/video_001/"
 hooks:
 on_start: ["python /scripts/prefetch.py"]
 on_chunk: ["python /scripts/register_chunk.py"]
 on_success: ["python /scripts/finalize_master.py"]
 on_failure: ["python /scripts/requeue.py --backoff"]

6) SSE‑стрим прогресса (FastAPI)

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import time
LOG="/out/transcode.log"
app=FastAPI()
def tail(path):
 with open(path,"r") as f:
 f.seek(0,2)
 while True:
 line=f.readline()
 if not line:
 time.sleep(0.5); continue
 yield f"data: {line}nn"
@app.get("/events")
def events():
 return StreamingResponse(tail(LOG), media_type="text/event-stream")

См. стриминг и UI‑обвязки: https://cloudcompute.ru/solutions/gradio-fastapi/ Наблюдаемость/метрики/алерты

База: https://cloudcompute.ru/solutions/monitoring-logging/ https://cloudcompute.ru/solutions/llm-inference/observability/

Ключевые метрики:

  • transcode_rtf — real‑time factor: t_process / t_media (< 1 медленнее realtime, > 1 быстрее). Цель VOD — > 1; цель live — ≥ 1 с запасом.
  • fps_in, fps_out, frames_total, drop_total (по видео/аудио).
  • nvenc_utilization, nvenc_sessions, gpu_utilization, gpu_memory_used_bytes.
  • io_read_mb_s, io_write_mb_s (вход/сегменты), cache_hit_ratio (NVMe).
  • Профиль латентности этапов (decode→filter→encode), p50/p95.

Алерты:

  • p95 transcode_rtf < целевого (напр., < 1.1 для VOD‑SLA) в течение N минут.
  • nvenc_sessions упрётся в лимит → очередь растёт, запуск дополнительных воркеров.
  • gpu_utilization < 60% при очереди → узкое место I/O/CPU (перенастроить префетч/параллелизм).
  • drop_total > 0 → провал по декоду/сети/стриму.
  • Сегменты с разъехавшимся GOP (нарушение -sc_threshold 0 или ключевых точек) — quarantine.

Экономика и формулы

См. https://cloudcompute.ru/solutions/cost-planner/ и https://cloudcompute.ru/solutions/throughput-vs-latency/

Определения:

  • RTF = t_process / t_media (для файла длительностью t_media секунд и времени обработки t_process секунд).
  • Чем RTF выше, тем меньше часов GPU на единицу медиадлительности.

Стоимость 1000 минут видео (VOD):

Cost_per_1K_min = (c_gpu * t_proc_1Kmin / 60) / U * r

где: t_proc_1Kmin = 1000 * 60 / RTF_total

c_gpu — цена/час GPU, U — целевая загрузка, r — retry‑factor (Interruptible), RTF_total — суммарный по лесенке.

ABR‑лесенка (K рендишенов):

RTF_total ≈ 1 / (Σ_i (1/RTF_i)) при параллельном энкоде

Если кодируете последовательно — складывайте t_process_i.

On‑Demand‑сессия (интерактив):

Cost_per_hour = c_gpu / U_session

Когда выгоден Interruptible: если скидка покрывает r-1 и каждый чанк ≤ 120 с (идемпотентная сборка).

Производительность: практики

  • Конвейер на GPU: -hwaccel cuda -hwaccel_output_format cuda, фильтры scale_npp/scale_cuda, энкодеры *_nvenc — минимум копий CPU↔GPU.
  • GOP и ключевые точки: фиксируйте -g/-keyint_min и -sc_threshold 0 для стабильных сегментов.
  • AQ/Lookahead: -spatial_aq 1 -temporal_aq 1 -rc-lookahead N улучшают качество при VBR.
  • Буферы/пики: корректные -maxrate/-bufsize для соответствия профилю сети.
  • I/O: префетч на NVMe, последовательная запись сегментов, лимит конкуренции записей; pinned memory.
  • Параллелизм: часто эффективнее «1 процесс = 1 GPU», несколько рендишенов — через split/filter_complex в одном процессе при достаточном запасе.
  • Постобработка: денойз/деблок и т.п. — выносить в отдельный батч. См. https://cloudcompute.ru/solutions/rendering/de-noising/

Безопасность и политики

См. https://cloudcompute.ru/solutions/security/

  • Права на контент: хранить в приватных бакетах; доступ по временным токенам; аудит читателей/писателей.
  • Секреты: ключи хранилищ, сервисные аккаунты, токены — через секрет‑хранилище; не логировать.
  • Политики сети: ограниченный egress; allow‑list только на нужные origin/каталоги.
  • Ретеншн: сырые входы и промежуточные сегменты → «холодное» хранилище по регламенту; логи — анонимизированы.

Траблшутинг (симптом → причина → решение)

**Симптом** **Причина** **Решение**
RTF < 1 на VOD I/O узкое место, конкуренция NVENC, тяжёлые фильтры Префетч на NVMe, уменьшить конкуренцию, упростить фильтры/параметры, добавить воркеры
Разъехались сегменты (HLS/DASH) sc\_threshold ≠ 0, непостоянный GOP Выравнять GOP/ключи, пересобрать проблемные чанки
«Осипший» звук/рассинхрон VFR/ошибки таймстампов Привести к CFR (-vsync cfr), перепаковать аудио, проверить -itsoffset
Артефакты/лесенка на ресайзе Неподходящий фильтр/цветовое пространство Использовать scale\_npp c подходящим интерполяционным алгоритмом, проверить pix\_fmt
Декод‑ошибки на конкретных источниках Повреждённый/нестандартный поток Предварительный -err\_detect ignore\_err + репарсер/ремультиплексор
Лимит NVENC‑сессий Превышение одновременных encode Снизить параллелизм на узле, добавить ноды, следить за nvenc\_sessions
OOM VRAM при множестве фильтров Агрессивная фильтрация/слишком много рендишенов Разнести на несколько процессов/GPU, уменьшить одновременные ветви
«Первый» прогон медленный Холодный кэш/компиляция Прогрев (probe, короткий прогон), не чистить NVMe‑кэш между заданиями

Как запустить в cloudcompute.ru

  1. Выберите шаблон: https://cloudcompute.ru/solutions/templates/
  1. Профиль GPU: 24/48/80 ГБ по таблице выше.
  2. Режим:
  • Массовый VOD — Interruptible (чанк ≤ 120 с, идемпотентная сборка).
  • Превью/монтаж — On‑Demand.
  1. Хранилище/кэш: вход в «тёплом» бакете, NVMe для сегментов/кэша, выход — в «холодное». См. https://cloudcompute.ru/solutions/storage-data/
  2. Оркестрация: YAML‑спеки, ретраи/backoff, раздельные очереди на encode/packaging.
  3. CI/CD: зафиксировать версии ffmpeg/драйверов/библиотек. См. https://cloudcompute.ru/solutions/containers-ci-cd/
  4. Наблюдаемость/алерты: дашборды RTF/FPS/NVENC/GPU/I‑O + p95. См. https://cloudcompute.ru/solutions/monitoring-logging/

Чек‑лист перед продом

  • Прогон probe/валидатора на выборке источников (VFR, битые таймстампы, цвет).
  • Единый контейнер с закреплёнными версиями ffmpeg/драйверов; smoke‑транскод прошёл.
  • NVMe‑кэш и префетч включены; cache_hit_ratio стабилен.
  • Чанк‑транскод ≤ 120 с, идемпотентные сегменты; ретраи/backoff работают.
  • Метрики transcode_rtf, nvenc_utilization, gpu_utilization, fps_in/out, drop_total заведены; алерты p95 настроены.
  • Экономика рассчитана (Cost_per_1K_min, Cost_per_hour для интерактива).
  • Политики безопасности/ретенции применены; логи не содержат секретов.

Навигация

Готовы запустить?

Запустить GPU-сервер