Пользователи загружают видео в чём попало — MOV с iPhone, MKV с торрента, AVI из 2008 года. Задача бэкенда — принять это, отдать в браузер нормальный MP4/H.264 или WebM/VP9, не блокируя веб-процесс на минуты транскодирования. Мы спроектировали отказоустойчивый пайплайн, который используется в продакшене не один год — реализовали его для более чем 30 проектов. Результат: адаптивные профили качества, прогресс в реальном времени, уведомления о готовности. Типичная экономия на серверных ресурсах достигает 40%, а стоимость CDN-трафика снижается существенно.
Почему синхронное транскодирование — плохая идея?
Транскодирование видео — CPU-интенсивная операция, которая длится от секунд до десятков минут в зависимости от длины ролика и профиля кодирования. Синхронная обработка в HTTP-запросе исключена: она заблокирует веб-воркер, приведёт к тайм-аутам и падению отзывчивости. Правильный подход — асинхронная очередь задач. Аппаратное кодирование NVENC обрабатывает видео в 3 раза быстрее программного, но даже оно не должно блокировать запрос.
Как построить пайплайн транскодирования?
Архитектура включает несколько компонентов. Ниже — пошаговый процесс:
- Загрузка: файл сохраняется в объектное хранилище или на локальный диск, возвращается ID задачи.
- Очередь: ставим Job в очередь (RabbitMQ, Redis, SQS), чтобы не блокировать HTTP-запрос.
- Воркер: забирает Job, запускает FFmpeg с нужными параметрами, пишет прогресс в Redis.
- Уведомление: после завершения обновляем БД и оповещаем клиента через WebSocket или polling.
Типичный набор профилей для адаптивной трансляции:
| Профиль | Разрешение | Битрейт видео | Битрейт аудио | CRF | Preset |
|---|---|---|---|---|---|
| 360p | 640×360 | 600 kbps | 96 kbps | 28 | fast |
| 720p | 1280×720 | 2500 kbps | 128 kbps | 23 | fast |
| 1080p | 1920×1080 | 5000 kbps | 192 kbps | 22 | medium |
CRF (Constant Rate Factor) — основной параметр качества для H.264: 18 = почти без потерь, 28 = приемлемое качество при малом размере. preset влияет на скорость кодирования vs размер файла.
Как отслеживать прогресс транскодирования?
FFmpeg умеет выводить прогресс через pipe. Воркер парсит строки формата out_time_usec=... и сохраняет проценты в Redis. Клиент получает обновления через WebSocket (например, Laravel Echo) или polling. Это позволяет показывать точный прогресс без задержек. Механизм progress описан в документации FFmpeg.
Выбор контейнера зависит от задач: MP4 универсален для стриминга, WebM с VP9 даёт лучшее сжатие, MKV подходит для архивного хранения с субтитрами. Для веба мы рекомендуем MP4 с H.264 — браузеры не требуют плагинов.
Как реализовать сервис запуска FFmpeg?
Ключевой элемент — сервис, который управляет процессом FFmpeg с обработкой прогресса:
namespace App\Services;
class FfmpegService
{
public function transcode(
string $inputPath,
string $outputPath,
array $profile,
?callable $onProgress = null
): void {
$width = $profile['width'];
$height = $profile['height'];
$videoBr = $profile['video_br'];
$audioBr = $profile['audio_br'];
$preset = $profile['preset'];
$crf = $profile['crf'];
// scale с сохранением соотношения сторон, padding до нужного размера
$scaleFilter = "scale={$width}:{$height}:force_original_aspect_ratio=decrease," .
"pad={$width}:{$height}:(ow-iw)/2:(oh-ih)/2:black";
$cmd = implode(' ', [
'ffmpeg -y',
"-i " . escapeshellarg($inputPath),
"-vf " . escapeshellarg($scaleFilter),
"-c:v libx264",
"-preset {$preset}",
"-crf {$crf}",
"-maxrate {$videoBr}",
"-bufsize " . (intval($videoBr) * 2) . "k",
"-c:a aac",
"-b:a {$audioBr}",
"-movflags +faststart",
"-progress pipe:1",
"-loglevel error",
escapeshellarg($outputPath),
]);
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$proc = proc_open($cmd, $descriptors, $pipes);
// ... чтение прогресса и проверка кода выхода
}
}-movflags +faststart — обязательный флаг: он перемещает атом moov в начало MP4, позволяя браузеру начать воспроизведение до полной загрузки. Без него видео не начнётся, пока не скачается весь файл.
Как выбрать между программным и аппаратным кодированием?
Программное кодирование (libx264) даёт лучшее качество на низких битрейтах, но медленнее. Аппаратное (NVENC) быстрее, но может ухудшить качество при сильном сжатии. Сравнение:
| Параметр | Software (libx264) | Hardware (NVENC) |
|---|---|---|
| Скорость | 1x | 3-5x |
| Качество | Лучше на low bitrate | Чуть хуже |
| Нагрузка CPU | Высокая | Низкая |
| Доступность | Всегда | Требуется GPU |
Для продакшена часто комбинируют: NVENC для предпросмотра, libx264 для финального архива. Оптимальный выбор зависит от ваших приоритетов: скорость или качество.
Что входит в работу
В рамках разработки конвейера транскодирования мы предоставляем:
- Настройка очередей (RabbitMQ/Redis) и supervisor для воркеров.
- Реализация сервиса FFmpeg с парсингом прогресса.
- Создание Job-классов с обработчиками успеха/ошибок.
- Конфигурация профилей транскодирования под ваши задачи.
- Эндпоинты для получения прогресса и результата.
- Интеграция WebSocket-уведомлений (опционально).
- Документация по развёртыванию и мониторингу.
Сроки и как заказать
Разработка базового пайплайна занимает от 2 до 4 дней в зависимости от сложности профилей и необходимости WebSocket. Оценим ваш проект — свяжитесь с нами, чтобы обсудить детали. Мы гарантируем качество кода и поддержку после сдачи. Свяжитесь для консультации!
Типичные ошибки и как их избежать
- Игнорирование moov atom: без
-movflags +faststartвидео не стримится. Проверяйтеffprobe -v quiet -print_format json -show_format output.mp4 | grep moov. - Слишком много параллельных воркеров: перегрузка CPU. Используйте
numprocs=1на воркер в supervisor. - Забывает про тайм-аут Job: ставьте
timeoutадекватно (час для длинных видео). - Не обрабатывать ошибки FFmpeg: проверяйте код возврата и логируйте stderr.
Используйте эти рекомендации — и пайплайн будет работать стабильно даже под высокой нагрузкой.







