Данная статья была написана по мотивам статьи Эффективное кодирование видео в Linux c Nvidia NVENC: часть 1, общая, однако имеет свои особенности и, в отличие от оригинальной статьи, где почему-то упустили этот момент, я применил переработанный патч Nvidia Acceleration к FFmpeg 3.0.2, получив помимо энкодера nvenc еще и быстрый фильтр ресайза — nvresize.
В итого я получил возможность аппаратно кодировать видео в H.264 и HEVC при помощи видеокарты Nvidia GTX 960 на достаточно слабом компьютере (Xeon L5420) со скоростью (для H.264), превышающей возможности данного процессора до 10 раз (и в 3 раза относительно Core i7)! Причем на моем любимом Debian 8 Jessie.
Итак, начнем!
Технология
Nvidia NVENC это технология, обеспечивающая кодирование видео в H.264 и HEVC на вычислительных мощностях GPU. Важное замечание: сколь-нибудь качественное и быстрое кодирование на момент написания статьи (май 2016) могут обеспечить только карты второго поколения Maxwell, и для десктопных это: GTX 960, GTX 970 и GTX 980 (для справки: есть еще дорогая проф.линейка Nvidia Quadro). Причем NVENC модуль работает с одинаковой скоростью на всех трех картах (непроверенная информация, пожалуйста, поправьте меня если это не так!), поэтому брать старшие версии имеет смысл только если платформа используется (помимо кодирования) для игр.
Реализация (FFmpeg)
Все многообразие реализаций Nvidia CUDA можно посмотреть по ссылке. От себя хочу сказать что для видео наиболее распространенным является популярный инструмент — FFmpeg. Его мы и будем использовать.
Аппаратное обеспечение
Хоть это и банально, но перечислю минимально необходимый набор аппаратных требований (основан на реальном опыте):
- Материнская плата: с поддержкой PCI-E. Рекомендую платформу Intel из-за тесной связи Intel-Nvidia и личной приязни. Да простят меня поклонники AMD!
- Процессор: двух-ядерный, уровня не ниже Core2 Duo. Рекомендую Core i3 и некоторые дешевые Xeon (да-да!).
- Память: DDR2/3/4, минимум 2 Гб. Интересный факт, при двух потоках кодирования суммарное потребление памяти у меня ~0.7 Гб.
- Видеокарта: любая видеокарта Nvidia GTX 960, GTX 970 или GTX 980. 2 Гб или 4 Гб, геймерская или нет — не важно! Главное, следите за габаритами и учтите что у всех моделей GTX 960 что я видел, дополнительное питание подключается сверху.
- БП ATX с доп.коннектором питания (6 пин для нашей задачи хватит). Рекомендую мощность не менее 400 Вт.
Программное обеспечение
Дальнейшее повествование опирается на определенный базис из систем, программ и их конкретных версий. Особо отмечу что я специально использовал Debian, а не Ubuntu, для которой есть даже офф. пакеты SDK, т.к. хотел попробовать настроить все в любимом дистрибутиве.
- Операционная система: Debian 8 Jessie с дополнительным репозиторием Deb Multimedia
- Nvidia CUDA 7.5.18
- Nvidia SDK 6.0.1
- FFmpeg 3.0.2
- Патч Nvidia Acceleration, изменен мной для совместимости с FFmpeg 3.0.2
Сборка
Самый важный из файлов — это первый, с драйвером. Только он и нужен если вы сразу хотите установить пакет после его сборки.
cd /usr/src
wget 'http://developer.download.nvidia.com/compute/cuda/7.5/Prod/local_installers/cuda_7.5.18_linux.run'
wget 'https://developer.nvidia.com/video-sdk-601' -O 'video-sdk-601.zip'
wget 'http://developer.download.nvidia.com/compute/redist/ffmpeg/1511-patch/cudautils.zip'
wget 'http://ffmpeg.org/releases/ffmpeg-3.0.2.tar.bz2'
wget 'http://kuzko.com/dl/ffmpeg_NVIDIA_gpu_acceleration.3.0.2.patch'
4b3bcecf0dfc35928a0898793cf3e4c6 cuda_7.5.18_linux.run
24af45272ed2881f88ed534d3211b584 video-sdk-601.zip
f3f890bd314a568c47191810453cad2c cudautils.zip
7db5efb1070872823143e1365fdfcd53 ffmpeg-3.0.2.tar.bz2
a4f59f92675e02a0fa5c6cd124eda64e ffmpeg_NVIDIA_gpu_acceleration.3.0.2.patch
0f366a88968b9eee01044de197e27764bc1567d6 cuda_7.5.18_linux.run
e57c7b4cfb298d4c725a0bb4477928e228dabb1c video-sdk-601.zip
edc818bef432d708466c5454974b9851523a86ba cudautils.zip
c40731a221fbfaa50671d69fe894bedd664f91e2 ffmpeg-3.0.2.tar.bz2
f305832ed42beeff7d7c26a00f79668b63b322ec ffmpeg_NVIDIA_gpu_acceleration.3.0.2.patch
Добавляем репозиторий Deb Multimedia (он требуется если вы хотите получить/использовать FFmpeg, который максимально приближен к тому, который выкладывает Deb Multimedia). Этот репозиторий обязателен для моей сборки!
echo 'deb http://www.deb-multimedia.org jessie main non-free' > /etc/apt/sources.list.d/deb-multimedia.list
Далее выполняем
apt-get update
И устанавливаем keyring:
apt-get install deb-multimedia-keyring
Теперь обновляем систему и ставим требуемые для сборки драйвера пакеты. Этот шаг также необходим!
apt-get update
apt-get -y dist-upgrade
apt-get -y install build-essential dkms ccache pkg-config libglu1-mesa-dev libx11-dev libxi-dev libxmu-dev
Устанавливаем Nvidia Driver, принимаем соглашение (accept), все остальные ответы по-умолчанию. Если предупредят что система не является подходящей, не переживайте, это нормально! Можно передать ключ -silent для быстрой установки, но лучше пройдитесь сами.
cd /usr/src
chmod +x cuda_7.5.18_linux.run
./cuda_7.5.18_linux.run
Выбор дальнейшего действия зависит от вас. Вы можете либо довериться мне и скачать готовый deb файл (создан через checkinstall) и пропустить последующие шаги, либо осуществить сборку вручную, установив необходимые библиотеки и собрав пакет самостоятельно через checkinstall.
cd /usr/src
wget 'http://kuzko.com/dl/ffmpeg_3.0.2-nvenc-7.5.18-nvresize-cudautils-20160523-1_amd64.deb'
dpkg -i ffmpeg_3.0.2-nvenc-7.5.18-nvresize-cudautils-20160523-1_amd64.deb
apt-get -f install
Если вы выбрали светлую сторону силы, то давайте продолжим, установим библиотеки, требуемые для сборки (для этого помимо всего прочего и был нужен Deb Multimedia), подготовим заголовочные файлы, cudautils и применим патч:
apt-get install -y --force-yes libfdk-aac-dev libopencv-dev libiec61883-dev libavc1394-dev libass-dev libbluray-dev libbs2b-dev libkvazaar-dev libilbc2 libilbc-dev libopenh264-dev libsnappy-dev libsoxr-dev libxv1 libxcb-shape0
cd /usr/src
unzip video-sdk-601.zip;
/bin/cp -prf nvidia_video_sdk_6.0.1/Samples/common/inc/nvCPUOPSys.h /usr/include
/bin/cp -prf nvidia_video_sdk_6.0.1/Samples/common/inc/nvEncodeAPI.h /usr/include
/bin/cp -prf nvidia_video_sdk_6.0.1/Samples/common/inc/nvFileIO.h /usr/include
/bin/cp -prf nvidia_video_sdk_6.0.1/Samples/common/inc/NvHWEncoder.h /usr/include
/bin/cp -prf nvidia_video_sdk_6.0.1/Samples/common/inc/nvUtils.h /usr/include
unzip cudautils.zip
cd cudautils
make
tar zxf ffmpeg-3.0.2.tar.bz2
cd ffmpeg-3.0.2
patch -Np1 -i ../ffmpeg_NVIDIA_gpu_acceleration.3.0.2.patch
Теперь мы готовы выполнить три основных команды по сборке пакета (configure / make / checkinstall).
Отмечу несколько моментов, которые вы можете изменить под себя:
- Были добавлены --enable-nvenc и --enable-nvresize (куда же без них!)
- Модифицированы --extra-cflags и --extra-ldflags, чтобы включить в себя cudautils
- Убраны --enable-opencl (не смог найти библиотеку для него) и --enable-libtesseract (лишний модуль на мой взгляд)
- FFmpeg собирается без --enable-shared, хотя ничто не мешает вам его вернуть назад
- make -j10 можете менять на специфичное для вашей системы (я использовал build-машину, где threads+2=10)
- Зависимости в checkinstall я вставил для того, чтобы при установке с нуля, было достаточно выполнить apt-get -f install и установить требуемые пакеты, а не выискивать через ldd что-же еще нужно установить
- Также из-за несовершенства checkinstall пришлось выполнить несколько необязательных действий (удаление конфликтующих dev пакетов и создании папки /usr/share/ffmpeg)
cd /usr/src
cd ffmpeg-3.0.2
./configure --prefix=/usr --extra-cflags='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -I../cudautils ' --extra-ldflags='-Wl,-z,relro -L../cudautils ' --cc='ccache cc' --enable-libmp3lame --enable-gpl --enable-nonfree --enable-libvorbis --enable-pthreads --enable-libfaac --enable-libxvid --enable-postproc --enable-x11grab --enable-libgsm --enable-libtheora --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libx264 --enable-libspeex --enable-nonfree --enable-libvpx --enable-libschroedinger --disable-encoder=libschroedinger --enable-version3 --enable-libopenjpeg --enable-librtmp --enable-avfilter --enable-libfreetype --disable-decoder=amrnb --enable-libvo-amrwbenc --libdir=/usr/lib/x86_64-linux-gnu --disable-vda --enable-libbluray --enable-libcdio --enable-gnutls --enable-frei0r --enable-openssl --enable-libass --enable-libopus --enable-fontconfig --enable-libpulse --disable-mipsdsp --disable-mips32r2 --disable-msa --disable-mipsfpu --disable-mipsdspr2 --enable-libvidstab --enable-libzvbi --enable-avresample --enable-libutvideo --enable-libfdk-aac --enable-libx265 --enable-libbs2b --enable-libilbc --enable-libopenh264 --enable-libkvazaar --enable-libsnappy --enable-libsoxr --enable-libiec61883 --enable-vaapi --enable-libdc1394 --disable-altivec --shlibdir=/usr/lib/x86_64-linux-gnu --enable-nvenc --enable-nvresize
make -j10
apt-get -y remove libswscale-dev libavcodec-dev libswresample-dev libavutil-dev
mkdir -p /usr/share/ffmpeg
checkinstall --pkgname=ffmpeg --pkgversion "10:3.0.2-nvenc-7.5.18-nvresize-cudautils-`date +%Y%m%d`" --backup=no --requires='libcdio-paranoia1,libjack0,libasound2,libsdl1.2debian,libdc1394-22,libavc1394-0,libiec61883-0,libvidstab1.0,libbs2b0,libva1,libzvbi0,libx265-79,libx264-148,libvpx1,libvo-amrwbenc0,libutvideo15,libtheora0,libspeex1,libsoxr0,libsnappy1,libschroedinger-1.0-0,libopus0,libopenjpeg5,libopenh264-1,libopencore-amrwb0,libopencore-amrnb0,libmp3lame0,libkvazaar3,libilbc2,libgsm1,libfdk-aac1,libfaac0,libbluray1,libass5,libxcb-xfixes0,libcrystalhd3,libxvidcore4,libxv1,libxcb-shape0' --default
Если в результате вы получили deb файл, то принимайте мои поздравления!
Кстати, checkinstall может и ругнуться при установке пакета. Не страшно. Установите (если не установился) пакет вручную через dpkg -i ffmpeg_3.0.2-nvenc-7.5.18-nvresize-cudautils-20160523-1_amd64.deb и потом apt-get -f install для установки зависимостей.
Параметры nvenc и nvresize
Отчего-то, не все знают какие параметры принимает nvenc и nvresize, а для этого нужно всего лишь запустить ffmpeg с ключом -h:
Encoder nvenc_h264 [NVIDIA NVENC h264 encoder]:
General capabilities: delay
Threading capabilities: none
Supported pixel formats: yuv420p nv12
nvenc_h264 AVOptions:
-preset <string> E..V.... Set the encoding preset (one of slow = hq 2pass, medium = hq, fast = hp, hq, hp, bd, ll, llhq, llhp, default) (default "hq")
-profile <string> E..V.... Set the encoding profile (high, main, baseline)
-level <string> E..V.... Set the encoding level restriction (auto, 1.0, 1.0b, 1.1, 1.2, ..., 4.2, 5.0, 5.1)
-tier <string> E..V.... Set the encoding tier (main or high)
-cbr <boolean> E..V.... Use cbr encoding mode (default false)
-2pass <boolean> E..V.... Use 2pass encoding mode (default auto)
-gpu <int> E..V.... Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on. (from 0 to INT_MAX) (default 0)
-delay <int> E..V.... Delays frame output by the given amount of frames. (from 0 to INT_MAX) (default INT_MAX)
-enableaq <boolean> E..V.... set to 1 to enable AQ (default false)
Encoder nvenc_hevc [NVIDIA NVENC hevc encoder]:
General capabilities: delay
Threading capabilities: none
Supported pixel formats: yuv420p nv12
nvenc_hevc AVOptions:
-preset <string> E..V.... Set the encoding preset (one of slow = hq 2pass, medium = hq, fast = hp, hq, hp, bd, ll, llhq, llhp, default) (default "hq")
-profile <string> E..V.... Set the encoding profile (high, main, baseline)
-level <string> E..V.... Set the encoding level restriction (auto, 1.0, 1.0b, 1.1, 1.2, ..., 4.2, 5.0, 5.1)
-tier <string> E..V.... Set the encoding tier (main or high)
-cbr <boolean> E..V.... Use cbr encoding mode (default false)
-2pass <boolean> E..V.... Use 2pass encoding mode (default auto)
-gpu <int> E..V.... Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on. (from 0 to INT_MAX) (default 0)
-delay <int> E..V.... Delays frame output by the given amount of frames. (from 0 to INT_MAX) (default INT_MAX)
-enableaq <boolean> E..V.... set to 1 to enable AQ (default false)
Filter nvresize
GPU accelerated video resizer.
Inputs:
#0: default (video)
Outputs:
dynamic (depending on the options)
nvresize AVOptions:
outputs <int> ..FV.... set number of outputs (from 1 to 16) (default 1)
readback <int> ..FV.... read result back to FB (from 0 to 1) (default 0)
gpu <int> ..FV.... Selects which NVENC capable GPU to use. First GPU is 0, second is 1, and so on. (from 0 to INT_MAX) (default 0)
force_original_aspect_ratio <int> ..FV.... decrease or increase w/h if necessary to keep the original AR (from 0 to 2) (default 0)
Целесообразность. Ради чего же все это?
Я не буду здесь приводить подробные бенчмарки (если только сообщество не попросит меня провести определенные тесты), их хватает в интернете, да и скорость кодирования непосредственно картой примерно одинакова и больше зависит от исходного видео, разрешения/битрейта кодируемого и дополнительной обработки (кодирование звука, наложение фильтров).
frame= 7500 fps= 58 q=-1.0 Lsize= 107951kB time=00:05:00.00 bitrate=2947.8kbits/s speed=2.32x
576p исходник, nvenc_h264, битрейт выставлен в 3000k:
frame= 7500 fps=804 q=-0.0 Lsize= 116997kB time=00:05:00.00 bitrate=3194.8kbits/s speed=32.2x
На 1080p исходнике (37 мегабит исходных в 10-15 мегабит) скорость 0.42x и 4.2x — Nvidia опять быстрее примерно в 10 раз.
При кодировании 1080p в HEVC на процессор больно смотреть, там цифры 0.08x и ниже, карта же около 3x выдает.
Для системы на Core i7 разница не такая большая, но все равно карта в 3-4 раза быстрее, чем x265 на HEVC 1080p (15000k) и в 13 раз на HEVC 576p (3000k). И это при том, что сам процессор i7 обычно стоит как GTX 960 и дороже.
Что касается качества. Я перфекционист, но считаю что есть множество применений для аппаратного кодирования, т.к. снижение качества на самом деле заметно слабо (смотрел как на проф.мониторе Dell 24", так и на телевизоре 60" — все с близкого расстояния) и только при т.н. pixel хантинге. Зато скорость делает возможным решение задач, которые обычно не способны выполняться в реальном времени на процессоре.
Я сознательно опустил подробности по скорости nvresize, кроме его параметров, т.к. хоть это и очень интересный и быстрый фильтр, но его использование выходит за рамки данной статьи.
Надеюсь, что мой труд не пропадет даром и поможет еще большему количеству людей приобщиться к технологии аппаратного кодирования, обойдя некоторые подводные камни, на решение которых я потратил достаточно много времени. Но это стоило того!
Автор: alexkuzko
Всем известно что аппаратное кодирование существенно уступает по качество x264 когда bitrate is limited – скажем 0.13 bpp (bits per pixel).
Но HW encoding очень полезно для live streaming/ video chat.