Эта статья содержит практические сведения, полезные для организации эффективного кодирования видео на Linux с использованием последних видеопроцессоров Nvidia.
Чем не является эта статья:
  • Не является пособием по выбору технологии аппаратного кодирования или агитацией в пользу описываемой. Кроме Nvidia NVENC есть Intel QuickSync, есть AMD VCE, наверняка есть и ещё что-то. Все эти технологии имеют разные характеристики, которые трудно даже уложить на одну шкалу для сравнения. Тем не менее, я сделал свой выбор.
  • Не является претензией на самый быстрый/качественный способ кодирования. По причинам, указанным выше.

Об NVENC


Nvidia NVENC это технология, позволяющая кодировать видео в H.264 (и H.265 для последних процессоров Maxwell) силами GPU со скоростями несколько сот кадров в секунду (в зависимости от профиля и разрешения). Вендор предоставляет возможность использования этой технологии в виде набора разработчика NVENC SDK.

Реализация


Имеется множество утилит для различных платформ, которые в каком-то виде дают доступ к функционалу SDK. В марте 2015 года вышел релиз ffmpeg, который включил в себя поддержку NVENC. ffmpeg занимает центральное положение среди всего множества свободного и не очень ПО для работы с видео, поэтому с практической точки зрения он наиболее интересен. Этим инструментом можно и обрабатывать видеофайлы (1, 2), и вести потоковое вещание (1, 2). С момента мартовского релиза вышел ещё один, который включил в себя ещё больше опций для кодека nvenc и поддержку H.265 (HEVC).

Сборкой FFmpeg с поддержкой NVENC мы и займёмся.

Развёртывание

Для создания рабочей конфигурации нам потребуется:
  • Одна видеокарта Nvidia на ядре Kepler или Maxwell. На мой взгляд самый интересный выбор это GTX 970 — процессор Maxwell второго поколения (GM204) за 300$.
  • Один линукс типовой (ubuntu 14.04) на компьютере с видеокартой.


Драйверы и рантайм CUDA

Драйверы и библиотеки установить за раз одним пакетом. Из репозитория лучше ничего не использовать.
sudo apt-get update
sudo apt-get -y install axel build-essential dkms
axel 'http://developer.download.nvidia.com/compute/cuda/7_0/Prod/local_installers/cuda_7.0.28_linux.run'
chmod +x cuda_7.0.28_linux.run
sudo ./cuda_7.0.28_linux.run

На все вопросы уважаемого компьютера следует ответить утвердительно. После установки — перезагрузить.

Заголовочные файлы nvenc

Для сборки приложений с nvenc sdk неободимы некоторые заголовочные файлы. Раньше их необходимо было стягивать из виндовой версии SDK. Но прогресс идёт семимильными шагами и теперь этот файл можно стянуть из примеров в линуксовом SDK. Найдите в примерах (были установлены вместе с рантаймом и драйверами на предыдущем шаге) файлы
nvCPUOPSys.h nvEncodeAPI.h nvFileIO.h NvHWEncoder.h nvUtils.h
и положите их в /usr/include. Они потребуются только один раз, при сборке ffmpeg. На всех машинах они не нужны.

FFMPEG

Начать его сборку лучше с установки всех сборочных зависимостей.
sudo apt-get build-dep libav
sudo apt-get install -y libfdk-aac-dev libopencv-dev

Я мог что-то забыть, что-то может измениться. Чтобы найти недостающий для сборки файл, не стесняйтесь пользоваться apt-file:
$ sudo apt-get install apt-file -y
$ sudo apt-file update
$ apt-file search libxcb-shm.so.0
libxcb-shm0: /usr/lib/x86_64-linux-gnu/libxcb-shm.so.0
libxcb-shm0: /usr/lib/x86_64-linux-gnu/libxcb-shm.so.0.0.0


Скачиваем с сайта последнюю версию ffmpeg, распаковываем, конфигурируем, собираем и устанавливаем:
axel 'http://ffmpeg.org/releases/ffmpeg-2.7.1.tar.bz2'
tar xf ffmpeg-2.7.1.tar.bz2
cd ffmpeg-2.7.1
./configure --cpu=native --enable-pthreads --extra-version=habrahabr.ru --enable-bzlib --enable-libdc1394 --enable-libfreetype --enable-frei0r --enable-gnutls --enable-libgsm --enable-libmp3lame --enable-librtmp --enable-libopencv --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-vaapi --enable-vdpau --enable-libvorbis --enable-libvpx --enable-zlib --enable-libfdk-aac --enable-nonfree --enable-gpl --enable-swscale --enable-libcdio --enable-x11grab --enable-libx264 --enable-libxvid --enable-libopencore-amrnb --enable-version3 --enable-libopencore-amrwb --enable-version3 --enable-libvo-aacenc --enable-version3 --enable-libvo-amrwbenc --enable-version3 --enable-nvenc
make -j5
sudo make install

Собираем с libfdk-aac, он точно предпочтительнее имеющегося кодека aac. Кроме прочего, можно заметить опцию --enable-nvenc. В остальном параметры выбраны по мотивам билдспеки пакета libav в самом дистрибутиве ubuntu. После всех манипуляций должен появиться рабочий ffmpeg в /usr/local/bin/ffmpeg.

Применение

Запуск

Опции запуска все точно такие же, как при софтверном кодировании, но только вместо libx264 видеокодек будет называться nvenc (он же nvenc_h264) для h.264 и nvenc_hevc для h.265.
/usr/local/bin/ffmpeg -i input.mov -vcodec nvenc -b:v 5000k -r 30 ... output.mp4


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

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

Ограничения

Увы и ах, Nvidia ввела ограничение: на обычных десктопных видеокартах нельзя кодировать больше двух потоков видео одновременно. Снятию этого ограничения будет посвящена моя следующая статья, которая, вероятно, будет интересна немного другому кругу читателей.

Комментарии (10)


  1. ayambit
    14.07.2015 12:57
    +3

    Автор, давай вторую часть уже. Это у тебя рассчитана на немного другой круг читателей.


    1. YourChief Автор
      14.07.2015 13:02
      +2

      Пишу как раз, там скриншотов GDB много.


  1. berez
    14.07.2015 13:44

    Но прогресс идёт семимильными шагами

    Кстати о прогрессе.
    Плач Ярославны
    У НВидии на линуксе есть один застарелый и неприятный баг: когда система загружена (например, компиляция идет), экран частично или полностью перестает перерисовываться. Ну то есть вплоть до того, что вводишь в консоли ls, а результата не видишь. Но если сдвинуть окно — все моментально отрисовывается. Необновленное окно может висеть часами, т.е. это не задержка.
    Багу уже много лет, его фиксили все — и нвидия, и разработчики гнома. Есть множество рецептов по его обходу, разной степени эзотеричности (от отключения power saving на видеокарте до каких-то непонятных ключиков в иксовых конфигах). Ни один не работает гарантированно. Обновление дров с сайта нвидии проблему не решает. Видеокарты, на которых баг вылазит — самые разные (от древней quadro до более-менее современных бюджетных). Линуксы, на которых баг вылазит, тоже разные: дебиан, ред хат энтерпрайзный, етц.


    1. YourChief Автор
      14.07.2015 14:01
      +1

      Я примерно такой эффект видел на старом макбуке, на который установлен линукс, и по-моему там встроенная видеокарта intel. При работе в gnome-terminal не после каждого нажатия перерисовывается окно и иногда введённого текста не видно. Может это другая проблема, а может проблема в какой-нибудь прослойке: в иксах, в DRI. Насчёт nvidia не знаю ничего — на этих машинах иксы никогда не запускались.


      1. berez
        14.07.2015 15:00

        Может это другая проблема, а может проблема в какой-нибудь прослойке: в иксах, в DRI.

        Грузишь линукс с драйвером nvidia — грабли. Причем грабли возникают даже в текстовом режиме(!) при использовании frame buffer.
        Грузишь тот же линукс с драйвером… эээ… как его бишь? nouveaux? — все прекрасно работает, но ни CUDA, ни OpenCL не доступны (что естественно).

        Насчёт nvidia не знаю ничего — на этих машинах иксы никогда не запускались.

        Погодите-ка. Как это не запускались? Разве для того, чтобы заработала CUDA, не нужны запущенные иксы?
        Для работы OpenCL, например, иксы должны быть запущены обязательно.


        1. YourChief Автор
          14.07.2015 15:02
          +3

          Для CUDA не нужны иксы совсем, это точно. У Радеонов для OpenCL, вроде, нужны.


  1. AterCattus
    14.07.2015 15:50

    Весной пробовал nvenc (ffmpeg тогда его еще не умел) на Tesla K40 в сравнении с текущим на тот момент ffmpeg на 8 ядрах (-threads 8) Xeon E5-2600V2.
    Если в один ролик за раз все было еще неплохо, то на двух оба варианта выдавали схожие числа. А на 3+ в параллель вариант на gpu сливал подчистую.
    Так что или один-два потока на не самой дешевой gpu (~200к), или минимум 3-4-5 потоков на сильно более дешевых cpu (около 10к, если не ошибаюсь). При той же скорости каждого отдельного качества.

    nvenc конвертился с пресетами NV_ENC_PRESET_LOW_LATENCY_DEFAULT, NV_ENC_PRESET_HQ и NV_ENC_PRESET_HP.
    ffmpeg выдавал уже готовый готовый mp4 файл, в то время как nvenc выдавал только x264 поток, который еще нужно сохранить в mp4 контейнер.

    Новый ffmpeg обязательно попробую, как руки дойдут.


    1. YourChief Автор
      14.07.2015 16:11

      Tesla K40 это Kepler. Для NVENC нецелесообразно пользоваться чем-то кроме новых Maxwell (GM20*). Я тестировал на Quadro K2000 с Kepler — скорость в разы меньше по сравнению даже с GTX 970.


      1. AterCattus
        14.07.2015 16:40

        А какая скорость выходит на Maxwell?
        K40 выдавала около 600-700 кадров в секунду на целевом 240/360, но сваливалась до несерьезных 50-60 кадров для 720.


        1. AterCattus
          14.07.2015 16:49
          +1

          Нашел вот. Стоит попробовать :)
          image