You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何借助Intel QuickSync实现FFmpeg中NV12转YUV420的硬件加速?

可以通过Intel QuickSync实现硬件加速的色彩转换

你当前使用的sws_scale是纯CPU处理,完全没有用到QuickSync加速。通过全程保留硬件帧、利用QSV的硬件转换能力,能避免将帧数据从GPU传到CPU的开销,实现格式转换的硬件加速。

核心思路

不要提前调用av_hwframe_transfer_data将QSV帧传到CPU,直接在硬件域内完成格式转换,最后按需将转换后的帧传到CPU内存(如果需要)。

实现方案一:基于硬件帧直接转换

// 解码得到QSV硬件帧 _tmpFrame (格式为AV_PIX_FMT_QSV)

// 提前初始化硬件帧上下文(仅需执行一次)
static AVBufferRef *hw_frames_ref = NULL;
if (!hw_frames_ref) {
    hw_frames_ref = av_hwframe_ctx_alloc(_tmpFrame->hw_frames_ctx->device_ref);
    AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)hw_frames_ref->data;
    hw_frames_ctx->format = AV_PIX_FMT_QSV;
    hw_frames_ctx->sw_format = AV_PIX_FMT_YUV420P; // 目标输出格式
    hw_frames_ctx->width = _context->width;
    hw_frames_ctx->height = _context->height;
    av_hwframe_ctx_init(hw_frames_ref);
}

// 1. 创建硬件目标帧
AVFrame *hw_dst_frame = av_frame_alloc();
hw_dst_frame->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
av_hwframe_get_buffer(hw_dst_frame->hw_frames_ctx, hw_dst_frame, 0);

// 2. 硬件内格式转换(QuickSync加速)
int32_t ret = av_hwframe_transfer_data(hw_dst_frame, _tmpFrame, 0);
if (ret < 0) {
    // 错误处理逻辑
}

// 3. (可选)将转换后的硬件帧传到CPU内存,得到YUV420P格式的帧
AVFrame *dst_frame = av_frame_alloc();
dst_frame->format = AV_PIX_FMT_YUV420P;
dst_frame->width = _context->width;
dst_frame->height = _context->height;
av_frame_get_buffer(dst_frame, 32);

ret = av_hwframe_transfer_data(dst_frame, hw_dst_frame, 0);
if (ret < 0) {
    // 错误处理逻辑
}

// 此时dst_frame即为硬件加速转换后的YUV420P帧,可直接使用

// 资源释放
av_frame_free(&hw_dst_frame);
av_frame_free(&dst_frame);

实现方案二:使用QSV滤镜链

如果需要更灵活的处理(比如同时做缩放、格式转换),可以用FFmpeg的QSV滤镜实现全硬件加速的处理链:

// 提前初始化滤镜图(仅需执行一次)
static AVFilterGraph *filter_graph = NULL;
static AVFilterContext *buffer_src_ctx = NULL;
static AVFilterContext *buffer_sink_ctx = NULL;

if (!filter_graph) {
    filter_graph = avfilter_graph_alloc();
    // 输入为QSV硬件帧,输出为YUV420P
    const char *filter_desc = "format_qsv=format=yuv420p";
    
    // 初始化输入滤镜
    AVFilter *buffer_src = avfilter_get_by_name("buffer");
    AVDictionary *src_args = NULL;
    av_dict_set(&src_args, "video_size", av_asprintf("%dx%d", _context->width, _context->height), 0);
    av_dict_set(&src_args, "pix_fmt", av_get_pix_fmt_name(AV_PIX_FMT_QSV), 0);
    av_dict_set(&src_args, "hw_frames_ctx", av_buffer_ref(_tmpFrame->hw_frames_ctx), 0);
    avfilter_graph_create_filter(&buffer_src_ctx, buffer_src, "src", NULL, &src_args, filter_graph);
    
    // 初始化输出滤镜
    AVFilter *buffer_sink = avfilter_get_by_name("buffersink");
    AVDictionary *sink_args = NULL;
    av_dict_set(&sink_args, "pix_fmts", av_get_pix_fmt_name(AV_PIX_FMT_YUV420P), 0);
    avfilter_graph_create_filter(&buffer_sink_ctx, buffer_sink, "sink", NULL, &sink_args, filter_graph);
    
    // 链接滤镜并配置
    avfilter_link(buffer_src_ctx, 0, buffer_sink_ctx, 0);
    avfilter_graph_config(filter_graph, NULL);
}

// 处理单帧
av_buffersrc_add_frame(buffer_src_ctx, _tmpFrame);
AVFrame *dst_frame = av_frame_alloc();
av_buffersink_get_frame(buffer_sink_ctx, dst_frame);
// 此时dst_frame就是硬件加速转换后的YUV420P帧

// 资源释放
av_frame_free(&dst_frame);

关键注意事项

  • 确保FFmpeg编译时开启了QSV支持:编译参数需添加--enable-libmfx --enable-qsv。
  • 硬件上下文hw_frames_ctx需提前初始化,避免重复创建带来的性能开销。
  • 全程保留硬件帧处理,避免不必要的GPU-CPU数据拷贝,这是提升性能的核心。

内容的提问来源于stack exchange,提问作者zerpico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:30:59