结论:用FFmpeg C++读取本地MP4并解码第一帧,需先调用avformat_open_input打开文件,再用avformat_find_stream_info获取流信息,接着用av_find_best_stream定位视频流索引,然后查找解码器、分配并初始化AVCodecContext,打开解码器后循环调用av_read_frame和avcodec_send_packet/avcodec_receive_frame,直到成功接收第一帧AVFrame。

怎么用 FFmpeg C++ 读取本地 MP4 并解码第一帧
直接说结论:FFmpeg C++ 本身没有“C++ API”,所谓“C++ 调用”实际是用 C 接口(avformat_open_input、avcodec_send_packet 等)在 C++ 环境里写。关键不是语言,而是流程是否绕过常见坑——比如没找对视频流、没处理 B 帧依赖、或忽略 AVPacket 的 pts/dts 顺序。
必须先找到正确的视频流(AVStream*)
MP4 容器里可能含多个流(视频、音频、字幕),avformat_find_stream_info 后不能硬写 0 当视频流索引。要遍历 ic->streams 找 AVMEDIA_TYPE_VIDEO 且 codecpar->codec_type == AVMEDIA_TYPE_VIDEO 的流。
- 错误做法:
video_stream_index = 0—— 音频流在前时会 crash 或解码出错 - 正确做法:用
av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0),它自动跳过无效流并返回真实索引 - 别忘了检查返回值是否
,否则后续所有调用都未定义行为
解码第一帧得手动送包直到拿到一帧(avcodec_receive_frame 成功)
FFmpeg 解码器内部有缓冲,尤其 H.264/H.265 的 B 帧会导致前几个 AVPacket 调用 avcodec_receive_frame 返回 AVERROR(EAGAIN)。不能只 decode 一次就放弃。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 循环逻辑:读包 → 判断是否属目标视频流 →
avcodec_send_packet→ 循环调用avcodec_receive_frame直到成功 - 关键点:
avcodec_receive_frame成功后立刻 break,不要继续读后续包——否则你拿到的可能是第二帧 - 注意:MP4 的第一个
AVPacket不一定是 I 帧(尤其是 fragmented MP4),所以必须靠receive_frame的返回值判断,而非 packet 的flags & AV_PKT_FLAG_KEY
YUV 数据转 RGB(如果需要显示/保存)别漏掉 sws_getContext 初始化
解码出来的 AVFrame 默认是 YUV 格式(如 AV_PIX_FMT_YUV420P),直接 memcpy 到 OpenGL 或 OpenCV Mat 会花屏。转换必须用 sws_scale,但前提是 sws_getContext 已创建且参数匹配。
立即学习“C++免费学习笔记(深入)”;
- 常见错误:传入的源宽高和
frame->width/frame->height不一致(例如没考虑对齐,frame->width可能是 1280,但实际有效像素是 1272) - 安全做法:用
frame->width和frame->height初始化sws_getContext,目标格式按需选AV_PIX_FMT_BGR24(OpenCV)或AV_PIX_FMT_RGBA(OpenGL) - 性能提示:上下文可复用,不必每帧重建;但首次调用
sws_scale会有开销,别在循环里重复初始化
最易被忽略的是时间基(time_base)和帧率推导——虽然第一帧不涉及 PTS 计算,但如果你之后要定位关键帧或做 seek,stream->r_frame_rate 和 stream->time_base 的组合必须手动算准,FFmpeg 不保证它们始终自洽。

















