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

嵌入式Linux下ffmpeg用h264_v4l2m2m解码视频报错的问题排查

问题分析与修复方案

核心原因

h264_v4l2m2m是基于V4L2的硬件解码器,它输出的视频帧内存是硬件DMA缓冲区,和软件解码器(比如默认的h264)输出的用户态内存帧本质不同:

  • 硬件帧的data指针可能未直接映射到用户态,或者多平面格式下部分指针为空
  • 硬件帧的生命周期由V4L2驱动管理,提前释放会导致swscale访问无效内存
  • 你的代码大概率直接复用了软解的帧处理逻辑,没适配硬件帧的格式与内存规则

修复步骤

1. 匹配swscale的输入格式与硬件帧格式

bad src image pointers报错主要是因为swscale初始化时指定的输入格式和硬件解码输出的帧格式不匹配。先打印解码后帧的格式,再用实际格式初始化swscale:

// 先获取硬件解码输出帧的实际格式
enum AVPixelFormat src_fmt = decoded_frame->format;
// 初始化swscale上下文时用真实的src_fmt,别硬编码成YUV420P这类软解常用格式
struct SwsContext *sws_ctx = sws_getContext(
    decoded_frame->width, decoded_frame->height, src_fmt,
    dst_width, dst_height, AV_PIX_FMT_YUV420P, // 目标格式按需调整
    SWS_BILINEAR, NULL, NULL, NULL
);

2. 确保硬件帧内存可被用户态访问

硬件解码器输出的帧可能处于硬件地址空间,swscale无法直接访问,必须调用av_frame_make_writable将数据拷贝到用户态内存:

if (av_frame_make_writable(decoded_frame) < 0) {
    av_frame_unref(decoded_frame);
    continue; // 跳过无效帧,避免程序崩溃
}

如果想避免拷贝(追求性能),可以直接用V4L2的内存映射接口操作硬件缓冲区,但嵌入式场景下先优先用上面的方法快速解决问题。

3. 修正帧的释放顺序

硬件帧不能在swscale处理前调用av_frame_unref,否则V4L2驱动会立刻回收硬件缓冲区,导致swscale访问已失效的指针。正确流程是:

// 1. 解码得到decoded_frame
// 2. 执行格式转换
sws_scale(sws_ctx, decoded_frame->data, decoded_frame->linesize, 0, decoded_frame->height, dst_frame->data, dst_frame->linesize);
// 3. 处理转换后的dst_frame(比如显示、保存)
// 4. 最后再释放decoded_frame
av_frame_unref(decoded_frame);

4. 检查ffmpeg编译与驱动兼容性

  • 确认编译ffmpeg 4.4.4时开启了--enable-v4l2m2m和--enable-swscale选项,这两个是硬件解码和格式转换的必要开关
  • 检查kernel 5.10.24的V4L2驱动是否存在DMA缓冲区相关BUG,可尝试给解码器设置thread_count=1,避免多线程导致的帧竞争:
    av_opt_set_int(codec_ctx->priv_data, "thread_count", 1, 0);
    

验证标准

修复后运行程序,满足以下三点说明问题解决:

  • 不再输出bad src image pointers错误日志
  • 程序运行时长和原视频一致(约13秒)
  • 输出的视频帧无花屏、黑屏等异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:40:15