Пользователи загружают видео в чём попало — 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.
Используйте эти рекомендации — и пайплайн будет работать стабильно даже под высокой нагрузкой.







