В этом посте речь пойдет о вопросах кодирования видео «в промышленных масштабах» с применением видеокодека h264 на GPU, интегрированном в современные процессоры Intel и о том опыте, которая приобрела наша компания Inventos в процессе создания и оптимизации медиа сервера для обработки потокового видео.
Введение
Итак, была поставлена задача разработать медиа сервер, представляющий собой эдакий «комбайн» на все случаи жизни и умеющий следующее:
- Кодирование/рессемплинг аудио/видео почти во все известные форматы, среди которых HLS, HDS, RTMP, mp4, etc;
- Поддержка съема сигнала с SDI, DVB;
- Балансировка и масштабирование серверов раздачи и кодирования;
- Описание конфигурации кодировщика на встроенном языке;
- Различные модули для нормализации звука, усиления, деинтерлейсинга видео и т.д.
Этот продукт под кодовым названием «streambuilder» является бэкендом медиа платформы Webcaster.pro. Решение написано на C++ с использованием библиотек libavcodec, в которые имплементированы многие известные кодеки, такие как h264, mpeg4 и т.д. Такое решение позволяет достаточно быстро разворачивать инфраструктуру доставки контента любой сложности и является гибким в плане конфигурирования.
Наш медиасервер, а, точнее, язык конфигурации, позволяет представить все этапы обработки аудио/видео в виде направленного ациклического графа. В корневой вершине находится источник сигнала, а остальные представляют собой различные блоки, проводящие операции над данными. При помощи конфигурационных файлов мы можем описывать графы, удовлетворяющие почти любым потребностям. В сильно упрощенном виде этот граф будет выглядеть следующим образом:
Несмотря на то, что код библиотек libavcodec хорошо оптимизирован, он рассчитан на работу на CPU, содержащим конечное число исполнительных устройств, таком, как x86 based. Увеличение количества ядер только отчасти решет проблему, так как обходится это недешево, да и ядра всегда есть чем загрузить, помимо кодирования видео. И логичным шагом была попытка использовать возможности графических ускорителей для решения данной задачи.
Теперь немного о самом кодировании видео. Как известно, в основе сжатия видео лежат множество алгоритмов из разных разделов математики. Это фурье — анализ, вейвлеты, операции с матрицами, векторами, вероятностные алгоритмы и т. д. Объединяет их одно — все они так или иначе работают с видео данными, которые представляют собой не что иное, как векторы и матрицы. Мы не будет углубляться в особенности сжатия конкретными видеокодеками, но следует понимать, что такие задачи крайне затратны по ресурсам в плане памяти и особенно процессорного времени. Тем более, если речь идет о промышленных масштабах кодирования. До недавнего времени процесс кодирования осуществлялся на центральных процессорах. CPU характеризуются прежде всего ограниченным числом исполнительных блоков. И даже, несмотря на то, что в современных процессорах появилось много ядер, число исполнительных блоков остается конечным. Конечно, производители процессоров добавляют элементы суперскалярной архитектуры в свои чипы (например, наборы инструкций SSExxx/AVX от Intel). Они позволяют одной инструкцией обработать несколько однотипных чисел, но всегда существуют такие задачи, как сжатие видео, когда ресурсов все равно не бывает много, особенно в свете появления новых стандартов вещания (HD, 4k, и т. д.). GPU, в свою очередь, обладают большим количеством исполнительных блоков, которые, впрочем, умеют исполнять ограниченное число инструкций. Соответственно, GPU идеально подходят для обработки однотипных данных, с использованием параллельных алгоритмов. Кроме этого, многие производители GPU добавляют в свои видео ускорители дополнительные команды для ускорения обработки мультимедиа данных.
Решение от Intel
В качестве эксперимента мы решили попробовать ускорить кодирование видео при помощи графических сопроцессоров Intel HD Graphics, встроенных в современные процессоры Intel. Intel любезно предоставляет свой Media SDK для кодирования, декодирования, ресемплинга и других алгоритмов видео обработки. Данный SDK, к нашей большой радости, теперь доступен и для Linux, что крайне важно для промышленного использования. Именно благодаря появлению поддержки Linux мы заинтересовались этим решением. Коллег из Intel тоже заинтересовали результаты практического использования данного SDK в условиях промышленного использования. При этом, должен отметить, на протяжении всего периода разработки сотрудники Intel нам очень сильно помогали, отвечали на вопросы (которых было много поначалу) и давали действительно ценные советы.
В комплекте вместе с Media SDK идет хорошая документация и примеры почти на все случаи жизни. Процесс интеграции Intel Media SDK сильно упростило наличие примеров, без них он, надо сказать, покажется не самым тривиальным. Суть интеграции заключалась в замены наиболее требовательных к аппаратной части софтверных модулей кодирования/декодирования/ресемплинга на соответствующие модули, использующие аппаратные возможности Intel HD Graphics.
Тесты
Конфигурация нашего тестового стенда: Процессор i7-3770 3.4 GHz, память 3 Гб. Версия Intel Media SDK for Linux Servers — 16.1.0.10043. В качестве источника брались разные медиафайлы и результат усреднялся.
Кодирование RAW видео в h264
ffmpeg | intel media sdk | |
720x608, h264 RAW, 30 сек, 3000 кб/с | 1.2 сек | 0.24 сек |
Пример транскодирования с демуксером/муксером ffmpeg (аудио пакеты писались без транскодирования)
ffmpeg | intel media sdk | |
720x608, aac+h264, 30 сек, 3000 кб/с | 1.6 сек | 0.32 сек |
streambuilder
simple streambuilder | with intel media sdk | |
1920x800 + resize 1280x720, 3000 кб/с h264, aac, 12 минут | 5.4 мин | 2.3 мин |
А теперь посмотрим на результаты. Для начала мы собрали примеры, которые шли в комплекте. В кодировании RAW видео в h264 тестовая программа обогнала ffmpeg h264 encoder при схожих параметрах в 4-5 раз, при этом надо сделать поправку на время, затраченное на операции дисковых записи/чтения (то есть реальный результат немного выше). Fmpeg при этом на 100% нагружал все ядра CPU. Video decoder и аппаратное изменение размеров изображения показали сходные результаты. Мы также собрали пример транскодирования с демуксером/муксером ffmpeg. Этот пример использует особый тип памяти для работы с фреймами и в нем фреймы передаются от декодера на энкодер минуя стадию копирования данных из памяти SDK в YUV формат в системной памяти. Соответственно, здесь Intel Media SDK показал производительность в среднем в 5 раза выше, чем аналогичное транскодирование при помощи ffmpeg.
Наш медиаконвеер совместно с аппаратными модулями кодирования показал увеличение производительности в 2-3 раза. И это ожидаемый результат, так как большая часть производительности терялась на операциях копирования памяти. Gprof показал, что 80% процессорного времени уходило на работу с памятью, что вызывало задержки при подачи фреймов на аппаратный энкодер/декодер. Однако, эту проблемы мы планируем закрыть в ближайшее время, используя напрямую структуры памяти Intel SDK при обмене пакетами между разными модулями. Мы ожидаем здесь значительного увеличения производительности.
Итак, в качестве плюсов решения от Intel можно выделить следующее.
- Аппаратный энкодер (для h264) более адекватно воспринял параметры кодирования, нежели софтварный (libavcodec). Например, более точно выдерживался битрейт при кодировании. Для ffmpeg API его необходимо долго и мучительно подбирать;
- При кодировании почти не используется процессор. В наших тестах CPU использовался для транскодирования аудио потока и операций с памятью внутри конвейера. Общая загрузка была на уровне 25% (загружено было примерно одно ядро из 4-х).
Из минусов этого решения можно отметить разве что чуть больший порог вхождения и привязка SDK к конкретному ядру Linux, но это не показалось нам критичным.
Что дальше
В качестве итога могу отметить, что всю инфраструктуру продукта можно перевести на новый API примерно за 1 человеко-месяц (без учета тестирования). Кроме этого, мы использовали старый API. В новой версии SDK появилось много новых плюшек, таких как аналог двухпроходного кодирования на 100 фреймах, расчет dts кодированного пакета, увеличение качества видео и т. д. Для тестов мы использовали обычный настольный компьютер с достаточно производительным CPU. В ближайшее время мы планируем попробовать новую версию API, а также провести тесты на серверных решениях. Кроме этого, мы планируем провести расширенные тесты на различных наборах параметров для получения более полной картины, результатами которых мы поделимся в самое ближайшее время.
Автор: xaoc80