这是我对最新版本FFMpeg 4.1硬件解码的理解。以下是我在研究源代码后得出的结论。
首先,我建议从hw_decode示例中获取灵感:
https://github.com/FFmpeg/FFmpeg/blob/release/4.1/doc/examples/hw_decode.c
使用新的API时,当您使用
avcodec_send_packet()将数据包发送到编码器时,可以使用
avcodec_receive_frame()来检索解码帧。
有两种不同类型的
AVFrame
:一种是
软件类型,存储在“CPU”内存(也称为RAM)中,另一种是
硬件类型,存储在显卡内存中。
从硬件获取AVFrame
要检索硬件帧并将其转换为可读取、可转换(使用 swscaler)的
AVFrame
,需要使用
av_hwframe_transfer_data() 从显卡中检索数据。然后查看检索到的帧的像素格式,当使用 nVidia 解码时,通常为 NV12 格式。
m_swFrame->format = AV_PIX_FMT_NV12;
err = av_hwframe_transfer_data(
m_swFrame,
m_decodedFrame,
0);
const char* gpu_pixfmt = av_get_pix_fmt_name((AVPixelFormat)m_decodedFrame->format);
const char* cpu_pixfmt = av_get_pix_fmt_name((AVPixelFormat)m_swFrame->format);
列出支持的“软件”像素格式
这里需要注意,如果您想选择像素格式,不是所有的AVPixelFormat都受支持。AVHWFramesConstraints在这里是您的好帮手:
AVHWDeviceType type = AV_HWDEVICE_TYPE_CUDA;
int err = av_hwdevice_ctx_create(&hwDeviceCtx, type, nullptr, nullptr, 0);
if (err < 0) {
}
AVHWFramesConstraints* hw_frames_const = av_hwdevice_get_hwframe_constraints(hwDeviceCtx, nullptr);
if (hw_frames_const == nullptr) {
}
AVPixelFormat found = AV_PIX_FMT_NONE;
for (AVPixelFormat* p = hw_frames_const->valid_sw_formats;
*p != AV_PIX_FMT_NONE; p++)
{
if (sws_isSupportedInput(*p))
{
found = *p;
break;
}
}
av_hwframe_constraints_free(&hw_frames_const);
最后,可能更快的方法是使用av_hwframe_transfer_get_formats()函数,但您需要解码至少一个帧。
希望这可以帮到您!
qsvdec.c
和hw_decode.c
官方示例可能是一个很好的参考。在这里,解码器应该将nv12格式返回到主机内存。 - halfelf