ffmpeg — быстрей, еще быстрее

В давние времена возможностью кодирования видео на уровне железа обладали немногие устройства (в основном цифровые фото/видеокамеры и гаджеты типа Canopus). Но с 2012 года такие гиганты, как Intel и NVIDIA сказали, что теперь и мы сможем заниматься кодированием/раскодированием видеопотока, выделив под это дело отдельный набор микросхем (чип). Intel ввела технологию Quick Sync Video в своих процесорах, а NVIDIA реализовала это, как NVDEC/NVENC чип на своих видеокартах . Этот чип ничем кроме, как сжатием/расжатием видеопотока заниматься не может (на самом деле может еще кое-что). А раз чип берет на себя всю работу по сжатию видео, например, в h.264, то центральный CPU полностью разгружается, открывая перед пользователем очередные горизонты в multimedia. Особенно «горизонты» открылись в стриме, когда нужно было «играть» и «показывать». За «играть» отвечает CPU + основные ресурсы GPU, а за «показывать» отвечал тот самый чип. Еще «горизонты» открылись для пользователей слабых ноутбуков, теперь они могут заниматься обработкой FullHD и 4K видео без томительного ожидания окончания процесса кодирования.

FFMpeg

Преимущества кодирования/декодирования видео мы будем рассматривать на примере FFmpeg. Это популярная бесплатная программа, с открытым исходным кодом, доступная на Linux и Windows. Разработка FFmpeg ведется довольно активно, что указывает на расширение функционала и повышения стабильности программы от релиза к релизу.

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

Попробуем, как говориться, «разогнать» FFmpeg и сделать его еще быстрее.

Что будем кодировать

В качестве теста возьмем известный ролик Buck Bunny. Это 3D компьютерный мультик в 4K разрешении. Детализация просто зашкаливает. Травинки, ворсинки на шкурке, панорамы камерой — все это дает сильную нагрузку на кодек.

Знакомство с кодированием на GPU начнем с NVIDIA и ее технологии NVDEC/NVENC.

NVIDIA NVENC

В 2012 году NVidia в своих видеокартах линейки Kepler установила пару чипов, в которых на аппаратном уровне происходит раскодирование и кодирование видеопотока. На следующей схеме — это блоки NVDEC и NVENC.

NVDEC (video decoder) — тот, кто расжимает сжатое видео. Согласитесь, прежде чем показать видео на экране его полагается для начала разжать. Задача эта не легкая и нагрузку на центральный процессор дает ощутимую. А если видео 4K да еще 60fps, то не всякий процессор с этим справится. NVDEC работает с самыми популярными форматами видео.

NVENC (video encoder) — тот, кто сжимает видео. Жмет в h.264 и HEVC (h.265). Тут все понятно.

Обратите внимание, блоки NVDEC, NVENC располагаются отдельно от CUDA Cores, тем самым не создавая нагрузку на графический процессор, который в данный момент занимается важными делами (например, обрабатывает PhysX и Bullet для любимой компьютерной игры).

Установка

FFmpeg с поддержкой аппаратного кодека NVENC можно легко собрать из исходников, а можно воспользоваться и готовой сборкой для Windows.

Сборка из исходников

Если вы «осмелились» 🙂 собрать FFmpeg из исходников с поддержкой NVENC, то вот вам несколько советов.

  1. Для сборки нужно очень много dev версий библиотек, ну что-то типа:
    glew-utils libglew-dbg libglew-dev libglew1.13 \
    libglewmx-dev libglewmx-dbg freeglut3 freeglut3-dev freeglut3-dbg libghc-glut-dev \
    libghc-glut-doc libghc-glut-prof libalut-dev libxmu-dev libxmu-headers libxmu6 \
    libxmu6-dbg libxmuu-dev libxmuu1 libxmuu1-dbg git-core

    и это не все, а только часть. Я когда собирал, сделал список всех установленных пакетов в системе (installed-packages), чтобы потом отфильтровать его по префиксу «dev» и воспользоваться уже готовым списком.

  2. Необходимо установить CUDA Toolkit. Ставьте с настройками по умолчанию, в ту директорию, в которую инсталлятор предложит:
    $ pwd
    /usr/local/cuda
    $ ll
    total 68
    drwxr-xr-x 3 root root 4096 Feb 9 17:32 bin
    drwxr-xr-x 5 root root 4096 Feb 1 10:03 doc
    drwxr-xr-x 5 root root 4096 Feb 1 10:03 extras
    drwxr-xr-x 5 root root 4096 Feb 1 10:03 include
    drwxr-xr-x 5 root root 4096 Feb 1 10:04 jre
    drwxr-xr-x 3 root root 4096 Feb 9 17:43 lib64
    drwxr-xr-x 8 root root 4096 Feb 1 10:03 libnsight
    drwxr-xr-x 7 root root 4096 Feb 1 10:04 libnvvp
    drwxr-xr-x 2 root root 4096 Feb 1 10:04 nsightee_plugins
    drwxr-xr-x 3 root root 4096 Feb 1 10:03 nvml
    drwxr-xr-x 7 root root 4096 Feb 1 10:03 nvvm
    drwxr-xr-x 2 root root 4096 Feb 1 10:04 pkgconfig
    drwxr-xr-x 11 root root 4096 Feb 1 10:04 samples
    drwxr-xr-x 3 root root 4096 Feb 1 10:03 share
    drwxr-xr-x 2 root root 4096 Feb 1 10:03 src
    drwxr-xr-x 2 root root 4096 Feb 1 10:03 tools
    -rw-r--r-- 1 root root 76 Feb 9 17:43 version.txt
  3. Скачиваем и устанавливаем Include файлы (понадобятся при сборке). Раньше, чтобы их найти нужно было приложить не мало сил. Теперь все просто:
    git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git

    Далее, необходимо сделать:

    make
    make install

    После этого они установятся в нужную папку и когда будете собирать FFmpeg, configure скрипт их с легкостью найдет.

  4. Скачиваем исходники FFmpeg. Рекомендую делать это не через «git clone», а скачать архив исходников с http://ffmpeg.org/releases/. Причем выбирать не самую последнюю версию, а ту которая ближе к версии CUDA SDK (примерно сравните время создания архивов). Это нужно, чтобы избежать конфликтов с совместимостью.
    wget http://ffmpeg.org/releases/ffmpeg-3.4.1.tar.gz
  5. Запускаем сборку FFmpeg
    ./configure --enable-cuda --enable-cuvid --enable-nvenc --enable-nonfree --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64 --extra-cflags=-I/home/voran/install/nv-codec-headers/include --disable-x86asm

    Внимание. После окончания сборки не будет проигрывателя ffplay. Не ищите его. FFplay не поддерживает аппаратное ускорения во время проигрывания video. Четыре года назад был создан баг на эту тему, но воз и ныне там. Но, как выход можно воспользоваться MPV, которые позволяет задействовать мощность GPU при проигрывании видео.

Готовые пакеты

FFmpeg содержится в репозитариях всех популярных дистрибутивов Linux. Его можно легко установить через соответствующий менеджер пакет.
Самые свежие версии FFmpeg для Windows можно скачать с https://ffmpeg.zeranoe.com/builds/.
Чтобы проверить поддерживает ли ffmpeg аппаратное кодирование на NVIDIA GPU выполните команду:

ffmpeg -codecs | egrep nvenc

и ищите строчку с префиксом nvenc:

DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_vdpau h264_cuvid ) (encoders: h264_nvenc nvenc nvenc_h264 )
DEV.L. hevc                 H.265 / HEVC (High Efficiency Video Coding) (decoders: hevc hevc_cuvid ) (encoders: nvenc_hevc hevc_nvenc )

Пример

Теперь можно запустить аппаратное кодирование через ffmpeg и насладиться скоростью:

export LD_LIBRARY_PATH=/usr/local/cuda-9.1/lib64:$LD_LIBRARY_PATH
./ffmpeg -hwaccel cuvid -c:v h264_cuvid -i bbb_sunflower_native_60fps_normal.mp4 -vf scale_npp=1280:720 -c:v h264_nvenc sunflower-video.mp4

-c:v h264_cuvid — раскодирование видео будет делаться на NVDEC;

-c:v h264_nvenc — кодировать поток будем на NVENC

То есть в этом примере мы имеем полное аппаратное декодирование, а затем кодирование. Чтобы удостовериться в том, что графическая карта занимается раскодированием и кодированием видео, запустим:

nvidia-smi -dmon

enc — загрузка чипа NVENC,

dec — загрузка чипа NVDEC

Центральный процессор при этом загружен минимально.

Кодек NVENC в ffmpeg предоставляет большое количество опций для выбора оптимального метода сжатия: несколько предустановленных профилей, постоянный/переменный битрейт, многопроходное кодирование и еще много других опций полный список, которых можно посмотреть выполнив:

ffmpeg -hide_banner -h encoder=h264_nvenc

Тест

Условия теста простейшие. Сначала сконвертируем фрагмент видео обычным способом (на CPU), затем сконвертируем на аппаратном кодеке NVENC и сравним времена.

Программное сжатие видео — 163 сек. Проводилось на всех доступных ядрах и потоках в параллельном режиме на Intel i-7.

./ffmpeg -y -i bbb_sunflower_native_60fps_normal.mp4 -vcodec h264 -acodec copy -threads 8 -vframes 1500 video-soft.mp4

Аппаратное сжатие с использованием технологии NVENC — 73 сек.

./ffmpeg -y -hwaccel cuvid -c:v h264_cuvid -i bbb_sunflower_native_60fps_normal.mp4 -c:v h264_nvenc -vframes 1500 -threads 1 video-nvenc.mp4

По факту имеем ускорение в 2 раза.

Intel Quick Sync Video

Intel в своих процессорах, а точнее  в графическом ядре, реализовала технологию «Quick Sync Video», позволяющую аппаратно кодировать/раскодировать видеопоток. Эта технология была представлена в 2011 году и с каждым поколением процессоров производительность QSV возрастала.

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

QSV поддерживает следующие форматы видео; mpeg2, h.264, hevc. Есть несколько пресетов для аппаратного кодека: veryfast, faster, fast, medium, slow, slower, veryslow. Реализовано многопроходное кодирование. Есть возможность задания точного значения битрейта.

Установка

FFMpeg с поддержкой Intel QSV можно собрать из исходников, как под Linux, так и под Windows. Процесс этот довольно простой, поэтому его описание я приводить не буду. Для тех, кто не хочет заморачиваться со сборкой из исходников, в сети есть прекрасный ресурс, где выкладываются самые свежие версии FFMpeg с поддержкой QSV. Рекомендую скачивать статическую версию FFMpeg.

Чтобы проверить содержит ли скачанная версия FFMpeg поддержку qsv для декодирования/кодирования, выполните:

ffmpeg.exe -codecs

Если там будет вот такая строчка с h264_qsv:

DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_qsv h264_cuvid ) (encoders: libx264 libx264rgb h264_nvenc h264_qsv nvenc nvenc_h264 )

Значит все в порядке и можно приступать к кодированию.

Пример

Простейший пример кодирования видео с помощью аппаратного ускорения в Intel GPU:
ffmpeg -i in.mp4 -vcodec h264 _ qsv out .mp4

Тест

Тест проводился на стареньком ноутбуке ASUS с процессором Intel Core i3.

Программное сжатие видео — 385 сек

ffmpeg.exe -hide_banner -y -i bbb_sunflower_native_60fps_normal.mp4 -vcodec h264 -acodec copy -vframes 1500 video-software.mp4

Аппаратное сжатие с использованием технологии QSV — 91 сек

ffmpeg.exe -hide_banner -y -i bbb_sunflower_native_60fps_normal.mp4 -init_hw_device qsv:hw -vcodec h264_qsv -acodec copy -vframes 1500 video-gpu.mp4

Согласитесь, неплохая прибавка (x4) к скорости кодирования на ноутбуке.

Выводы

Когда я впервые собрал ffmpeg с поддержкой GPU и попробовал сравнить скорость кодирования с обычным вариантом на CPU, честно говоря испытал какой-то взрыв эмоций. Вот ноутбук, видео кодируется обычно час, но оказывается на этом же ноуте можно сконвертировать за 15-20 минут. Ощущается, как халява. Двух-трехкратное ускорение, просто из ничего! При этом процессор свободен и можно заниматься своими делами и ничего не тормозит.
Конечно же никакой Америки я не открыл и эта технология давно используется. Тем не менее приятно задействовать все ресурсы ноутбука из которого казалось бы выжато уже все, что можно:-)

Почитать еще