У меня есть простое приложение 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
?
(кусочки кода будут очень признательны)
Вы должны использовать vf_scale_npp
сделать это. Вы можете использовать либо nppscale_deinterleave
или же nppscale_resize
зависит от ваших потребностей.
Оба имеют одинаковые входные параметры, которые AVFilterContext это должно быть инициализировано с nppscale_init
, NPPScaleStageContext который принимает ваш входной / выходной пиксельный формат и два AVFrames, которые, конечно, ваши входные и выходные кадры.
Для получения дополнительной информации вы можете увидеть npplib \ nppscale определение, которое будет выполнять CUDA-ускоренное преобразование и масштабирование формата начиная с ffmpeg 3.1.
Во всяком случае, я рекомендую использовать Видеокодек NVIDIA SDK непосредственно для этого.
Я не эксперт 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.