Pull to refresh

Распределенное кодирование видео

Reading time 4 min
Views 21K
image
Думаю, большинству хабрапользователей хоть раз да приходилось кодировать видео. Возможно, вы хотели посмотреть свежую серию любимого сериала в метро, а ваш смартфон или иное портативное устройство никак не хотело играть этот кодек, или SmartTV отказывался декодировать звук в видеофайле, либо же вы застряли в 2004 и транскодировали H.264 в MPEG-4 для вашего старого DVD-проигрывателя. Или же, например, сжимали невероятного размера видео, снятое фотоаппаратом, во что-то более-менее приличное по размеру. Наверняка вы замечали, что это не самый быстрый процесс.

Для кодирования видео сделано огромное количество софта, начиная от программ типа «жми крестик чтобы кодировать» и заканчивая софтом, который принимает AviSynth-скрипты на вход. Однако программы, поддерживающие хоть какое-то распределение кодирования, можно пересчитать по пальцам одной руки.

Что вообще следует понимать под распределенным кодированием видео? В моем представлении, есть 2 разных задачи:
  1. Кодирование большого количества видеофайлов на множестве компьютеров одновременно
  2. Кодирование одного видеофайла по частям на множестве компьютеров одновременно

Первая задача подразумевает наличие большого количества видеофайлов, сильно больше, чем компьютеров, на которых их можно кодировать, и довольно легко автоматизируется с использованием CLI-кодировщиков, например, HandBrake или FFmpeg и любых средств автоматизации, которые поддерживают распределение, вроде GNU Parallel или PPSS (к слову, о нем мало кто знает, рекомендую!).

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

Обычно, мне нужно кодировать 1-2 10-битных видеофайла, закодированных кодеком H.264, в 8-битные, с пресетом medium, slow или slower. Как правило, на одну минуту видео требуется 6-8 минут кодирования. Хотелось бы быстрее.

Глоссарий

GOP (Group of Pictures) — буквально, группа изображений. Часть кадров от одного I-frame (ключевого кадра) до другого, не включая последний.
image
Worker — программа, которая выполняет какую-то работу (как правило, самую затратную) в распределенной системе. В нашем случае — кодирование видео.

Готовые решения


Я несколько дней искал живые проекты по распределенному кодированию обоих задач, и вот что я нашел:
1. MediaCoder
MediaCoder — достаточно продвинутый и удобный комбайн, неплохо балансирующий между количеством настроек и легкостью использования. Однако, распределенное кодирование в нем реализовано хуже некуда: декодируется видео локально, а worker отправляется несжатый декодированный фрейм. Рекомендуют гигабитную сеть, так что через интернет это будет работать невероятно медленно. Сервер работает только под Windows (и еще в Wine), worker работает под Windows и Linux. Поддерживается только H.264 и VP8.

2. dvd::rip
Методы распределения в этом проекте, к сожалению, ничем не лучше, чем с использованием обычных средств распределения. Вам нужно будет поднять SSH-сервер на каждой машине и NFS-сервер на машине с файлами. Не умеет кодировать один файл на нескольких компьютерах.

3. Ripbot264
Лучшее, что я видел. Правильно режет файлы (по GOP), удобно настраивается, но, к сожалению, использует средства общего доступа к файлам Windows, что практически исключает работу вне одной сети (программа требует, чтобы все компьютеры были в одной рабочей группе). И работает только в Windows.

Создание своего велосипеда


К сожалению, под Linux ничего сносного не нашел и загорелся идеей сделать свое. Какие требования я выдвигал к распределенной системе кодирования видео?
  • Система должна уметь кодировать один файл на нескольких workers (разрезка файла по GOP и последующая склейка обратно)
  • Должно поддерживаться как можно большее количество декодеров, энкодеров и контейнеров (как минимум, mkv и mp4)
  • По возможности, избегать создание временны́х файлов и минимизировать потребление RAM на workers

Для кодирования видео решил использовать FFmpeg, а для разрезания и склейки файлов mkvmerge, и, соответственно, контейнер matroska (т.к. в процессе испытывания FFmpeg вылезла регрессия в mkv-муксере).
Переписывал я проект 6 раз. Какие идеи были отброшены:
  • Использование Job Server (Gearman, Beanstalkd) и Message Broker (RabbitMQ) для передачи кусков видео для кодирования внутри Job. Это, конечно, очень удобно, но хранить куски исходного и перекодированного файла в памяти я себе позволить не мог. К тому же, сначала нужно было получить видео полностью, затем перекодировать его, и только потом отправлять.
  • Использование RPC по той же причине
  • Использование HTTP-сервера для отдачи и получения файлов

И все вернулось к сокетам. Действительно, лучше сокетов здесь тяжело что-то придумать — сокет можно подать как на stdin FFmpeg, так и на stdout, и никаких временны́х файлов не будет создаваться, и оперативной памяти расходуется по минимуму, и скодированное видео загружается сразу на сервер.

И я это сделал.
github.com/ValdikSS/distvidcDistVIDc (типа distcc, только для видео)
Я использовал Rage Driven Development, и знатно расслабился, когда получил первую рабочую версию и первый коммит.
Как оно работает?

Есть три скрипта — server, client и worker. Server ждет файл и параметрами кодирования от client, режет его на куски, распределяет между worker, отдает части и принимает переконверченные куски, собирает куски в файл. Worker, соответственно, подключается к серверу, ждет команды и кодирует куски.

Проблемы:
  • Видео с переменной кадровой частотой (VFR), скорее всего, будет кодироваться неправильно и рассинхронизироваться
  • Эффективность кодирования получается немного меньше из-за того, что на конце разрезанного куска GOP может быть меньше, чем он мог бы быть без разрезки

Положительные стороны:
  • Можно подавать на вход и получать на выходе все, что поддерживается проектом FFmpeg. Theora в ogg в VP8 в webm? Без проблем. Богом забытый msmpeg2 в avi в HEVC в mkv? Да запросто!
  • Эффективная работа worker. Потребляется всего около 200КБ оперативной памяти!

DistVIDc будет работать как под Linux, так и под Windows (на данный момент, worker работает только под Linux). Буду рад любому, кто заинтересуется проектом.
Tags:
Hubs:
+44
Comments 34
Comments Comments 34

Articles