Как я могу преобразовать FFmpeg AVFrame с пиксельным форматом AV_PIX_FMT_CUDA в новый AVFrame с пиксельным форматом AV_PIX_FMT_RGB

У меня есть простое приложение C ++, которое использует FFmpeg 3.2 для получения потока RTP H264. Чтобы сохранить процессор, я делаю часть декодирования с помощью кодека h264_cuvid. Мой FFmpeg 3.2 скомпилирован с ускорением hw. На самом деле, если я сделаю команду:

ffmpeg -hwaccels

я получил

cuvid

Это означает, что в моей настройке FFmpeg все в порядке, чтобы «говорить» с моей картой NVIDIA.
Кадры, которые функция avcodec_decode_video2 предоставляет мне формат пикселей AV_PIX_FMT_CUDA, Мне нужно преобразовать эти кадры в новые с AV_PIX_FMT_RGB, К сожалению, я не могу сделать преобразование, используя хорошо знакомые функции sws_getContext а также sws_scale потому что формат пикселей AV_PIX_FMT_CUDA не поддерживается. Если я пытаюсь с swscale, я получаю ошибку:

«cuda не поддерживается как формат входного пикселя»

Знаете ли вы, как конвертировать FFmpeg AVFrame от AV_PIX_FMT_CUDA в AV_PIX_FMT_RGB ?
(кусочки кода будут очень признательны)

4

Решение

Вы должны использовать vf_scale_npp сделать это. Вы можете использовать либо nppscale_deinterleave или же nppscale_resize зависит от ваших потребностей.

Оба имеют одинаковые входные параметры, которые AVFilterContext это должно быть инициализировано с nppscale_init, NPPScaleStageContext который принимает ваш входной / выходной пиксельный формат и два AVFrames, которые, конечно, ваши входные и выходные кадры.

Для получения дополнительной информации вы можете увидеть npplib \ nppscale определение, которое будет выполнять CUDA-ускоренное преобразование и масштабирование формата начиная с ffmpeg 3.1.

Во всяком случае, я рекомендую использовать Видеокодек NVIDIA SDK непосредственно для этого.

1

Другие решения

Я не эксперт ffmpeg, но у меня была похожая проблема, и мне удалось ее решить. Я получал AV_PIX_FMT_NV12 от cuvid (декодер mjpeg_cuvid) и хотел AV_PIX_FMT_CUDA для обработки куда.

Я обнаружил, что установка формата пикселей перед декодированием кадра работает.

    pCodecCtx->pix_fmt = AV_PIX_FMT_CUDA; // change format here
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// do something with pFrame->data[0] (Y) and pFrame->data[1] (UV)

Вы можете проверить, какие форматы пикселей поддерживаются вашим декодером, используя pix_fmts:

    AVCodec *pCodec = avcodec_find_decoder_by_name("mjpeg_cuvid");
for (int i = 0; pCodec->pix_fmts[i] != AV_PIX_FMT_NONE; i++)
std::cout << pCodec->pix_fmts[i] << std::endl;

Я уверен, что есть лучший способ сделать это, но я тогда использовал этот список для сопоставления идентификаторов целочисленных пиксельных форматов с читаемыми человеком форматами пикселей.

Если это не сработает, вы можете сделать cudaMemcpy для переноса ваших пикселей с устройства на хост:

    cudaMemcpy(pLocalBuf pFrame->data[0], size, cudaMemcpyDeviceToHost);

Преобразование из YUV в RGB / RGBA может быть сделано многими способами. Этот пример делает это с помощью libavdevice API.

1

По вопросам рекламы [email protected]