Как повысить скорость декодирования видеопотока в FFmpeg

от автора


С приходом тяжеловесных видеоформатов, таких как 4K (Ultra HD), проблема эффективности декодирования видеопотока стала достаточно актуальной. На среднем компьютере приходится принимать специальные меры для того, чтобы можно было обработать такой видеопоток в реальном масштабе времени. В статье рассказывается о возможных способах увеличения скорости декодирования видеопотоков в решениях, основанных на FFmpeg, и приводятся результаты экспериментов по измерению скорости декодирования для 4K видеопотоков, закодированных в H264 и HEVC(H265).


Оглавление

  1. Три способа повышения скорости декодирования видеопотока
    1.1. Подключение дополнительных рабочих потоков в стандартных декодерах
    1.2. Подключение аппаратного ускорения в стандартных декодерахх
    1.3. Использование специальных декодеров, реализующих декодирование на графических процессорах
  2. Измерение скорости декодирования
  3. Замечания о QSV декодерах
  Ресурсы

1. Три способа повышения скорости декодирования видеопотока

Мы будем рассматривать три способа повышения скорости декодирования видеопотока.

  1. Подключение дополнительных рабочих потоков (threads) в стандартных декодерах.
  2. Подключение аппаратного ускорения (HW Acceleration) в стандартных декодерах.
  3. Использование специальных декодеров, реализующих декодирование на графических процессорах.

Первый из них использует исключительно возможности CPU, а два других задействуют возможности графических процессоров.

Доступные способы повышения скорости декодирования видеопотока достаточно сильно зависят от используемой операционной системы, аппаратной конфигурации компьютера и конфигурации FFmpeg. Все приведенные в статье результаты проверялись на следующей программно-аппаратной конфигурации: операционная система — Windows 10, ЦП — Intel i5 8400 2.80 ГГц (6 ядер без hyper-threading), встроенный графический процессор — Intel UHD Graphics 630, память — 16 ГБ, сборка FFmpeg 4.2.1, с zeranoe.

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

1.1. Подключение дополнительных рабочих потоков в стандартных декодерах

Многие декодеры (но, конечно, не все) позволяют установить количество рабочих потоков, используемых для декодирования. Для этого перед вызовом avcodec_open2() член thread_count структуры AVCodecContext надо установить в требуемое значение. Другой способ — добавить опцию threads в словарь опций, передаваемый в качестве третьего аргумента в avcodec_open2().

Наиболее популярные декодеры, используемые для тяжелых форматов, (h264, hevc, vp9) поддерживают эту возможность, а вот theora нет.

Для подключения дополнительных потоков в командной строке надо использовать ключ -threads.

1.2. Подключение аппаратного ускорения в стандартных декодерах

FFmpeg позволяет для некоторых декодеров подключить аппаратное ускорение. При программировании с использованием FFmpeg API все необходимое для подключения к декодерам аппаратного ускорения находится в заголовочном файле libavutil/hwcontext.h. В этом файле определено перечисление enum AVHWDeviceType, каждый элемент которого и соответствует некоторому типу аппаратного ускорения. Какие типы аппаратного ускорения доступны в текущей сборке FFmpeg можно узнать с помощью следующего кода:

void print_hwtypes_all() {     AVHWDeviceType hwtype = AV_HWDEVICE_TYPE_NONE;     while ((hwtype = av_hwdevice_iterate_types(hwtype)) !=                             AV_HWDEVICE_TYPE_NONE)     {         printf("%s\n", av_hwdevice_get_type_name(hwtype));     } }

Для описанной выше программно-аппаратной конфигурации мы получим:

     cuda     dxva2     qsv     d3d11va 

Понятно, что cuda требует установки платы Nvidia и соответствущего ПО, qsv использует технологию Intel Quick Sync Video (QSV), реализованную на встроенных графических процессорах Intel (см. [1]), dxva2 и d3d11va используют технологию DirectX Video Acceleration (см. [1]), доступную только в Windows.

Конкретные декодеры не обязаны поддерживать все эти типы аппаратного ускорения (или хотя бы один из них). Для определения типов, поддерживаемых конкретным декодером, можно воспользоваться следующим кодом:

void print_hwtypes(const AVCodec *decoder) {     for (int i = 0; ; ++i) {          const AVCodecHWConfig *config =                avcodec_get_hw_config(decoder, i);         if (config) {             if (config->methods &                     AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) {                 printf("%s\n",                    av_hwdevice_get_type_name(config->device_type));             }         }         else {             break;         }     } }

Для описанной выше программно-аппаратной конфигурации декодеры h264, hevc, vp9, vc1 поддерживают следующие типы аппаратного ускорения:

     dxva2     d3d11va     cuda 

А вот theora вообще не поддерживает аппаратного ускорения.

Теперь совсем кратко рассмотрим процедуру подключения к декодеру аппаратного ускорения, за дополнительными деталями надо обратится к примеру hw_decode.c. Также можно посмотреть статью [3], написанную 2expres.

void init_hwdevice(AVHWDeviceType hwtype, AVCodecContext *codec_ctx) {     AVBufferRef *dev_ctx = NULL;     int ret = av_hwdevice_ctx_create(&dev_ctx, hwtype, NULL, NULL, 0);     if (ret >= 0) {         codec_ctx->get_format = get_hw_format; // см. hw_decode.c         codec_ctx->hw_device_ctx = av_buffer_ref(dev_ctx); // сохранить  dev_ctx, чтобы освободить после декодирования // с помощью av_buffer_unref()     } }

После декодирования данные кадра находится в некотором специальном формате, который определяется типом устройства, поэтому его надо конвертировать в один из обычных пиксельных форматов с помощью функции av_hwframe_transfer_data(). Для dxva2 и d3d11va этот формат будет NV12.

Для подключения аппаратного ускорения в командной строке надо использовать ключ -hwaccel.

1.3. Использование специальных декодеров, реализующих декодирование на графических процессорах

В состав FFmpeg входят два семейства кодеков, реализующих кодирование и декодирование на графических процессорах.

Одно семейство использует технологию Intel Quick Sync Video (QSV), реализованную на видеопроцессорах, интегрированных в процессоры Intel семейств i3, i5, i7, i9. Подробнее см. [1]. Эти кодеки имеют суффикс _qsv. В рассматриваемой сборке FFmpeg есть следующие декодеры: h264_qsv, hevc_qsv, vp8_qsv, mpeg2_qsv, vc1_qsv.

Другое семейство использует технологии NVDEC, NVENC реализованные на платах Nvidia. Декодеры имеют суффикс _cuvid. В рассматриваемой сборке FFmpeg есть следующие декодеры: h264_cuvid, hevc_cuvid, mpeg2_cuvid, vc1_cuvid, vp8_cuvid, vp9_cuvid, mjpeg_cuvid, mpeg4_cuvid.

После открытия входного потока доступ к декодеру обычно реализуется следующим образом:

AVStream *strm; // ... AVCodecID cid = strm->codecpar->codec_id; const AVCodec *decoder = avcodec_find_decoder(cid);

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

const AVCodec *decoder = (cid == AV_CODEC_ID_H264)     ? avcodec_find_decoder_by_name("h264_qsv")     : avcodec_find_decoder(cid);

2. Измерение скорости декодирования

Для экспериментов по измерению скорости декодирования были выбраны два видеоролика, один закодирован в H264, другой в HEVC(H265). Размер кадра — 3840х2160 (Ultra HD), скорость — 30 к/с. Тестировались стандартные декодеры — h264, hevc и соответствующие QSV декодеры — h264_qsv, hevc_qsv. Стандартные декодеры настраивались в 4х вариантах: по умолчанию, два рабочих потока, четыре рабочих потока, аппаратное ускорение dxva2. В наших экспериментах dxva2 показал лучшие результаты, чем d3d11va, поэтому последний не участвовал в измерениях скорости декодирования. Для проведения тестов была написана программа которая извлекала пакеты из файла и декодировала их с максимально возможной скоростью, игнорируя метки времени и не выполняя рендеринг или иную обработку. Было два режима этой программы: в первом выполнялось только декодирование, в втором еще производилось конвертирование декодированного кадра в 32-битный формат BGRA с использованием библиотеки libswscale. (На выходе декодера кадр обычно имеет 12-битный планарный формат YUV420P или NV12.) Проводилось измерение времени, затраченного программой, и фиксировалось относительное время по отношению к номинальной длительности видеопотока (в процентах). Таким образом, если результат меньше 100%, то у нас есть шанс обработать видеопоток в реальном масштабе времени, если больше, то таких шансов нет. Также с помощью Диспетчера задач фиксировалась примерная загрузка ЦП и графического процессора. Использовалась 64-битная сборка FFmpeg.

Таблица. Измерение скорости декодирования
h264 hevc
Config # Время CPU GPU Время CPU GPU
default 1 75 26 0 125 25 0
2 132 28 0 180 27 0
threads=2 1 47 42 0 74 42 0
2 79 48 0 104 46 0
threads=4 1 35 60 0 46 64 0
2 60 54 0 71 70 0
dxva2 1 45 14 72 34 28 70
2 107 28 35 99 30 36
xxxx_qsv 1 25 34 80 25 34 72
2 70 39 54 70 40 50

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

Эксперименты проводились также для 32-битной сборки FFmpeg. Результаты довольно близкие, кроме одного случая: декодер hevc в конфигурациях без аппаратного ускорения показал падение производительности в 2-3 раза. Весьма неожиданный результат.

3. Замечания о QSV декодерах

В рассматриваемой сборке FFmpeg есть следующие QSV декодеры: h264_qsv, hevc_qsv, vp8_qsv, mpeg2_qsv, vc1_qsv. Два последних оказались неработоспособными. Декодер mpeg2_qsv выдавал искаженную картинку, а vc1_qsv выдавал ошибку при передаче пакета на декодирование. Правда, эти декодеры не особо актуальны, но, все-таки, зачем выкладывать неработоспособные компоненты, не вполне понятно.

К оставшимся декодерам тоже есть претензии. В целом они работают, за исключением одного момента — они некорректно отрабатывают вызов avcodec_flush_buffers(). Ошибки нет, но после этого вызова позиционирование работает некорректно.

Ресурсы

[1] Intel Quick Sync Video.
[2] DirectX Video Acceleration.
[3] FFmpeg практика аппаратного декодирования DXVA2.

ссылка на оригинал статьи https://habr.com/ru/post/486736/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *