如何在 ffmpeg 中使用硬件加速
Posted
技术标签:
【中文标题】如何在 ffmpeg 中使用硬件加速【英文标题】:How to use hardware acceleration with ffmpeg 【发布时间】:2014-06-10 22:25:09 【问题描述】:我需要 ffmpeg 使用硬件加速来解码我的视频(例如 h264)。我正在使用通常的解码帧方式:读取数据包->解码帧。而且我想让 ffmpeg 加快解码速度。所以我用--enable-vaapi
和--enable-hwaccel=h264
构建了它。但我真的不知道接下来我该怎么做。我尝试使用avcodec_find_decoder_by_name("h264_vaapi")
,但它返回nullptr。
无论如何,我可能想使用其他 API 而不仅仅是 VA API。应该如何加快 ffmpeg 解码?
附:我在 Internet 上没有找到任何使用 ffmpeg 和 hwaccel 的示例。
【问题讨论】:
using ffmpeg hwaccel from C++的可能重复 @gbjbaanb,回答上述问题并不能解决任何问题。仅设置编解码器上下文的 hwaccel 对我不起作用。 您使用的是什么平台(即 Mac、Windows 或 Linux;物理硬件或虚拟化)?你认为你有什么样的硬件加速硬件(你认为)可用? @Multimedia Mike,我在 macbook pro(2011) 上安装了 ubuntu,它有英特尔 GPU 首先,AVHwaccel 只是一个骨架,所以不要指望用它轻松实现。您应该查看mpv 的源代码,它是一个基于 MPlayer 的播放器,但有很多东西被修复或清理。它具有成熟的 VA-API 解码功能,并为此使用 ffmpeg。也可以看看 VLC 的源码。 【参考方案1】:经过一番调查,我能够在 OS X (VDA) 和 Linux (VDPAU) 上实现必要的硬件加速解码。当我掌握 Windows 实现时,我也会更新答案。 所以让我们从最简单的开始:
Mac OS X
要让硬件加速在 Mac OS 上运行,您只需使用以下命令:
avcodec_find_decoder_by_name("h264_vda");
但是请注意,您只能在 Mac OS 上使用 FFmpeg 加速 h264 视频。
Linux VDPAU
在 Linux 上,事情要复杂得多(谁感到惊讶?)。 FFmpeg 在 Linux 上有 2 个硬件加速器:VDPAU(Nvidia) 和 VAAPI(Intel),只有一个硬件解码器:用于 VDPAU。在上面的 Mac OS 示例中使用 vdpau 解码器似乎是完全合理的:
avcodec_find_decoder_by_name("h264_vdpau");
您可能会惊讶地发现它并没有改变任何东西,而且您根本没有加速度。那是因为这只是开始,您必须编写更多代码才能使加速工作。幸运的是,您不必自己想出解决方案:至少有 2 个很好的例子来说明如何实现这一点:libavg 和 FFmpeg 本身。 libavg 有 VDPAUDecoder 类,它非常清楚,我的实现基于它。您也可以咨询ffmpeg_vdpau.c 以获得另一个实现进行比较。不过,在我看来,libavg 的实现更容易掌握。
上述两个示例唯一缺少的是将解码帧正确复制到主存储器。这两个示例都使用了VdpVideoSurfaceGetBitsYCbCr
,它扼杀了我在机器上获得的所有性能。这就是为什么您可能希望使用以下过程从 GPU 中提取数据:
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;
虽然它内部使用了一些“外部”对象,但一旦您实现了“获取缓冲区”部分(上述示例对此有很大帮助),您应该能够理解它。另外我使用了BGRA
格式,更适合我的需要,也许你会选择另一个。
所有这些的问题在于,您不能仅通过 FFmpeg 使其工作,您至少需要了解 VDPAU API 的基础知识。我希望我的回答能帮助某人在 Linux 上实现硬件加速。在我意识到在 Linux 上实现硬件加速解码没有简单的单行方式之前,我自己花了很多时间。
Linux VA-API
由于我最初的问题是关于 VA-API,我不能不回答它。
首先,FFmpeg 中没有 VA-API 的解码器,所以avcodec_find_decoder_by_name("h264_vaapi")
没有任何意义:它是nullptr
。
我不知道通过 VA-API 实现解码有多难(或者可能更简单?),因为我看到的所有示例都非常令人生畏。所以我选择完全不使用 VA-API,我必须为 Intel 卡实现加速。对我来说幸运的是,有一个 VDPAU 库(驱动程序?)可以在 VA-API 上运行。因此,您可以在 Intel 卡上使用 VDPAU!
我已使用以下 link 在我的 Ubuntu 上设置它。
此外,您可能想查看原始问题的 cmets,其中 @Timothy_G 还提到了一些有关 VA-API 的链接。
【讨论】:
非常感谢 Linux 和 vdpau 的示例源代码,在理想情况下,您列出的 osx 解决方案在 linux 上也能顺利运行(只需识别硬件加速的意图将是一个很棒的界面)。跨度> @MarkEssel,您需要使用sws_scale
将您在 VDA 之后获得的帧转换为您需要的格式。
@MarkEssel,不幸的是,我无法运行已实现硬件解码的软件,因此无法验证问题所在。但是我查看了代码,在解码后我没有做任何特别的处理来处理帧:这是我的 sws 上下文创建:sws_getCachedContext(nullptr, frame->width, frame->height, static_cast<AVPixelFormat>(frame->format), frame->width, frame->height, AV_PIX_FMT_RGB24, SWS_BILINEAR | SWS_ACCURATE_RND, nullptr, nullptr, nullptr);
@MarkEssel,如果我没记错的话,我遇到了同样的问题。这是因为我在初始化时创建了一次 sws 上下文。在该步骤中,上下文具有 VDA 像素格式,这对 sws 缩放器没有意义。因此,要获得正确的像素格式,您需要使用实际的帧像素格式来创建上下文,并且您将在解码后立即获得它。我希望我没记错。
当然是。 avcodec_decode_video2(m_pCodecCtx, m_pFrame, &frameFinished,&packet); if(frameFinished) 做事 以上是关于如何在 ffmpeg 中使用硬件加速的主要内容,如果未能解决你的问题,请参考以下文章
ffmpeg使用硬件加速hwaccelcuvidh264_cuvidh264_nvenc
ffmpeg使用硬件加速hwaccelcuvidh264_cuvidh264_nvenc
ffmpeg使用硬件加速hwaccelcuvidh264_cuvidh264_nvenc