You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用libavcodec+VAAPI实现H.264硬件编码报错求助

解决libavcodec VAAPI编码器初始化AVERROR(EINVAL)的问题

我看了你遇到的VAAPI硬件编码初始化失败的问题——命令行FFmpeg能正常跑VAAPI编码,但自己的代码调用avcodec_open2()返回-22(EINVAL),还报Mismatching AVCodecContext.pix_fmt and AVHWFramesContext.format错误,问题确实出在setupEncoder()的硬件初始化部分,你对VAAPI上下文的配置逻辑有几个关键错误,我来帮你修正并解释:

核心错误点分析

你的代码里对VAAPI的hw_device_ctxhw_frames_ctx的处理完全搞反了,而且没有正确配置帧上下文的必要参数:

  • av_hwframe_ctx_alloc()是用来创建帧上下文AVHWFramesContext)的,不是设备上下文
  • 你直接把设备上下文的引用赋值给hw_frames_ctx,导致帧上下文没有正确的格式、宽高配置,和AVCodecContext.pix_fmt(VAAPI)不匹配
  • 没有初始化AVHWFramesContext的核心参数,比如格式、宽高、帧池大小

修改后的setupEncoder()硬件部分代码

把你原有的硬件初始化逻辑替换成下面这段:

if(m_hardwareAcceleration) {
    m_encoder->pix_fmt = AV_PIX_FMT_VAAPI;
    m_encoder->get_format = get_vaapi_format;

    // 1. 创建VAAPI设备上下文
    assert(av_hwdevice_ctx_create(&m_device, AV_HWDEVICE_TYPE_VAAPI, "/dev/dri/renderD128", nullptr, 0) == 0);
    AVHWDeviceContext* deviceCtx = (AVHWDeviceContext*) m_device->data;
    assert(deviceCtx->type == AV_HWDEVICE_TYPE_VAAPI);

    // 2. 基于设备上下文创建帧上下文
    m_encoder->hw_frames_ctx = av_hwframe_ctx_alloc(m_device);
    assert(m_encoder->hw_frames_ctx != nullptr);

    // 3. 配置帧上下文参数
    AVHWFramesContext* framesCtx = (AVHWFramesContext*)m_encoder->hw_frames_ctx->data;
    framesCtx->format = AV_PIX_FMT_VAAPI; // 硬件帧格式,和编码器pix_fmt保持一致
    framesCtx->sw_format = AV_PIX_FMT_NV12; // 软件输入格式(和你传入的frame格式匹配)
    framesCtx->width = s_width;
    framesCtx->height = s_height;
    framesCtx->initial_pool_size = 10; // 帧池大小,可按需调整

    // 4. 初始化帧上下文(必须调用,否则参数不生效)
    assert(av_hwframe_ctx_init(m_encoder->hw_frames_ctx) == 0);

    // 5. 基于帧上下文分配硬件帧
    m_hwFrame = av_frame_alloc();
    assert(av_hwframe_get_buffer(m_encoder->hw_frames_ctx, m_hwFrame, 0) == 0);
}

关键修改说明

  1. 上下文角色区分
    • hw_device_ctx是全局的VAAPI设备上下文,你已经正确创建,但不需要直接赋值给编码器,编码器通过hw_frames_ctx关联设备
    • hw_frames_ctx是绑定到编码器的帧上下文,必须基于设备上下文创建,并配置和输入/输出匹配的格式参数
  2. 格式匹配
    • framesCtx->format设为AV_PIX_FMT_VAAPI,和m_encoder->pix_fmt严格一致,解决报错的格式不匹配问题
    • framesCtx->sw_format设为AV_PIX_FMT_NV12,对应你传入的软件帧格式,确保av_hwframe_transfer_data能正确完成软件帧到硬件帧的转换
  3. 帧上下文初始化
    • 必须调用av_hwframe_ctx_init()完成帧上下文的初始化,否则之前配置的参数不会生效
  4. 硬件帧分配
    • 基于hw_frames_ctx分配硬件帧,而不是原来的hw_device_ctx,这样分配的帧才属于编码器对应的帧池,能被正确使用

额外注意事项

  • 你当前的addFrame()里,av_hwframe_transfer_data从软件帧(NV12)转到硬件帧(VAAPI)的方向是对的,但要确保硬件帧的宽高和软件帧完全一致
  • 记得在析构函数里补充资源释放逻辑:av_frame_free(&m_hwFrame)av_buffer_unref(&m_device)av_buffer_unref(&m_encoder->hw_frames_ctx)avcodec_free_context(&m_encoder)等,避免内存泄漏

修改后,avcodec_open2()应该能正常初始化VAAPI编码器,硬件编码流程就能和命令行FFmpeg的表现一致了。

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

火山引擎 最新活动