Мне нужно, чтобы ffmpeg декодировал мое видео (например, h264) с использованием аппаратного ускорения. Я использую обычный способ декодирования кадров: прочитать пакет -> декодировать кадр. И я бы хотел, чтобы ffmpeg ускорил декодирование. Так что я построил это с --enable-vaapi
а также --enable-hwaccel=h264
, Но я не знаю, что мне делать дальше. Я пытался использовать avcodec_find_decoder_by_name("h264_vaapi")
но он возвращает nullptr.
В любом случае, я мог бы хотеть использовать другие API, а не только VA API. Как ускорить декодирование ffmpeg?
Постскриптум Я не нашел ни одного примера в Интернете, который бы использовал ffmpeg с hwaccel.
После некоторых исследований я смог реализовать необходимое ускоренное декодирование HW в OS X (VDA) и Linux (VDPAU). Я обновлю ответ, когда я получу в свои руки также реализацию Windows.
Итак, начнем с самого простого:
Чтобы ускорить работу HW в Mac OS, вы должны просто использовать следующее:
avcodec_find_decoder_by_name("h264_vda");
Обратите внимание, однако, что вы можете ускорить видео h264 только в Mac OS с FFmpeg.
В Linux все намного сложнее (кто удивлен?). FFmpeg имеет 2 ускорителя HW в Linux: VDPAU (Nvidia) и VAAPI (Intel) и только один HW декодер: для VDPAU. И может показаться вполне разумным использовать декодер vdpau, как в примере с Mac OS выше:
avcodec_find_decoder_by_name("h264_vdpau");
Вы можете быть удивлены, узнав, что это ничего не меняет, и у вас совсем нет ускорения. Это потому, что это только начало, вам нужно написать гораздо больше кода, чтобы ускорить работу. К счастью, вам не нужно придумывать решение самостоятельно: есть как минимум 2 хороших примера того, как этого добиться: libavg и сам FFmpeg. libavg имеет класс VDPAUDecoder, который совершенно понятен и на котором я основал свою реализацию. Вы также можете проконсультироваться ffmpeg_vdpau.c чтобы получить другую реализацию для сравнения. На мой взгляд, реализацию libavg легче понять.
Единственное, чего нет в обоих вышеупомянутых примерах, — это правильное копирование декодированного кадра в основную память. Оба примера использует VdpVideoSurfaceGetBitsYCbCr
который убил всю производительность, которую я получил на моей машине. Вот почему вы можете использовать следующую процедуру для извлечения данных из графического процессора:
bool VdpauDecoder::fillFrameWithData(AVCodecContext* context,
AVFrame* frame)
{
VdpauDecoder* vdpauDecoder = static_cast<VdpauDecoder*>(context->opaque);
VdpOutputSurface surface;
vdp_output_surface_create(m_VdpDevice, VDP_RGBA_FORMAT_B8G8R8A8, frame->width, frame->height, &surface);
auto renderState = reinterpret_cast<vdpau_render_state*>(frame->data[0]);
VdpVideoSurface videoSurface = renderState->surface;
auto status = vdp_video_mixer_render(vdpauDecoder->m_VdpMixer,
VDP_INVALID_HANDLE,
nullptr,
VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME,
0, nullptr,
videoSurface,
0, nullptr,
nullptr,
surface,
nullptr, nullptr, 0, nullptr);
if(status == VDP_STATUS_OK)
{
auto tmframe = av_frame_alloc();
tmframe->format = AV_PIX_FMT_BGRA;
tmframe->width = frame->width;
tmframe->height = frame->height;
if(av_frame_get_buffer(tmframe, 32) >= 0)
{
VdpStatus status = vdp_output_surface_get_bits_native(surface, nullptr,
reinterpret_cast<void * const *>(tmframe->data),
reinterpret_cast<const uint32_t *>(tmframe->linesize));
if(status == VDP_STATUS_OK && av_frame_copy_props(tmframe, frame) == 0)
{
av_frame_unref(frame);
av_frame_move_ref(frame, tmframe);
return;
}
}
av_frame_unref(tmframe);
}
vdp_output_surface_destroy(surface);
return 0;
}
Несмотря на то, что в нем есть некоторые «внешние» объекты, вы сможете понять его, как только вы реализуете часть «get buffer» (для которой вышеупомянутые примеры очень помогают). Также я использовал BGRA
формат, который был более подходящим для моих нужд, может быть, вы выберете другой.
Проблема со всем этим состоит в том, что вы не можете просто заставить его работать из FFmpeg, вам нужно понять хотя бы основы API VDPAU. И я надеюсь, что мой ответ поможет кому-то реализовать ускорение HW в Linux. Я потратил много времени на это сам, прежде чем понял, что не существует простого, однострочного способа реализации ускоренного декодирования HW в Linux.
Поскольку мой первоначальный вопрос касался VA-API, я не могу оставить его без ответа.
Во-первых, в FFmpeg нет декодера для VA-API, поэтому avcodec_find_decoder_by_name("h264_vaapi")
не имеет никакого смысла: это nullptr
,
Я не знаю, насколько сложнее (или, может быть, проще?) Реализовать декодирование через VA-API, поскольку все примеры, которые я видел, были довольно пугающими. Поэтому я решил вообще не использовать VA-API, и мне пришлось реализовать ускорение для карты Intel. К счастью для меня, есть библиотека VDPAU (драйвер?), Которая работает через VA-API. Таким образом, вы можете использовать VDPAU на картах Intel!
Я использовал следующее ссылка на сайт настроить его на моем Ubuntu.
Также вы можете проверить комментарии к исходному вопросу, где @Timothy_G также упомянул некоторые ссылки, касающиеся VA-API.