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

FFmpeg.AutoGen帧指针持久化及av_hwframe_transfer_data报错求助

问题解决方案

一、av_hwframe_transfer_data 返回-22(无效参数)的排查与修复

  • 源帧并非硬件解码帧
    如果解码流程未启用硬件加速,输出的是系统内存帧,此时调用av_hwframe_transfer_data属于错误操作,直接使用帧数据即可,无需执行转移。
  • 目标帧未正确初始化
    调用前必须保证目标帧的格式、宽高与源硬件帧完全匹配:先通过av_frame_alloc()分配帧结构,手动设置format(系统内存格式如AV_PIX_FMT_RGB24或AV_PIX_FMT_YUV420P)、width、height参数,再调用av_frame_get_buffer()分配内存。
  • 硬件上下文未正确关联
    启用硬件加速时,需先通过av_hwdevice_ctx_create创建硬件设备上下文,再将其关联到解码器的hw_device_ctx字段。如果硬件上下文未配置,解码出的不是硬件帧,会导致转移失败。

修正示例代码片段:

// 创建硬件设备上下文(以CUDA为例)
AVBufferRef* hw_device_ctx = null;
av_hwdevice_ctx_create(&hw_device_ctx, AVHWDeviceType.AV_HWDEVICE_TYPE_CUDA, null, null, 0);

// 将硬件上下文关联到解码器
pCodecContext.hw_device_ctx = av_buffer_ref(hw_device_ctx);

// 接收硬件帧后初始化目标系统内存帧
AVFrame* targetFrame = av_frame_alloc();
targetFrame->format = (int)AVPixelFormat.AV_PIX_FMT_RGB24;
targetFrame->width = pCodecContext.width;
targetFrame->height = pCodecContext.height;
av_frame_get_buffer(targetFrame, 32); // 分配内存对齐的缓冲区

// 执行硬件帧到系统内存的转移
int ret = av_hwframe_transfer_data(targetFrame, sourceFrame, 0);
if (ret < 0)
{
    // 错误处理
    av_frame_free(&targetFrame);
}

二、长期保留帧指针并避免复制的实现

FFmpeg帧内存默认由内部缓冲区管理,要长期持有需遵循以下规则:

  • 避免自动释放:在需要保留帧的期间,不要调用av_frame_unref()或av_frame_free()。但解码器输出的帧会被后续解码操作覆盖,因此必须增加引用计数。
  • 用av_frame_ref()复用内存:通过av_frame_ref(dstFrame, srcFrame)创建新的帧引用,无需复制像素数据,仅增加引用计数。原帧被unref后,dstFrame的内存依然有效。
  • 硬件帧需转系统内存持有:硬件帧内存由设备管控,无法直接长期持有,必须通过av_hwframe_transfer_data转移到系统内存帧后,再持有该帧指针,直到主动释放。

保留n帧的示例代码:

List<AVFrame*> retainedFrames = new List<AVFrame*>();

// 解码循环
while (av_read_frame(pFormatContext, packet) >= 0)
{
    if (packet.stream_index == videoStreamIndex)
    {
        avcodec_send_packet(pCodecContext, packet);
        while (avcodec_receive_frame(pCodecContext, frame) >= 0)
        {
            AVFrame* retainedFrame = av_frame_alloc();
            av_frame_ref(retainedFrame, frame); // 增加引用,不复制数据
            retainedFrames.Add(retainedFrame);

            if (retainedFrames.Count >= n)
                break;
        }
    }
    av_packet_unref(packet);
    if (retainedFrames.Count >= n)
        break;
}

// 主动释放内存(不再需要时)
foreach (var frame in retainedFrames)
{
    av_frame_unref(frame);
    av_frame_free(&frame);
}

三、FFmpeg 7.0 API 过时说明

你当前使用的av_read_frame()、avcodec_send_packet()、avcodec_receive_frame()均为FFmpeg 7.0的推荐API,并未过时。已废弃的旧API包括:

  • avcodec_decode_video2()、avcodec_decode_audio4():已被send/receive模式替代
  • 老旧硬件加速API如av_hwaccel_get_by_name():推荐使用av_hwdevice_ctx_create系列接口

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 10:42:19