C++调FFmpeg需用extern "C"包裹头文件防name mangling,链接顺序为avformat→avcodec→avutil→swscale→swresample,av_read_frame返回EAGAIN非错误需关闭AVFMT_FLAG_NONBLOCK,解码需循环avcodec_receive_frame,H.264需确保SPS/PPS送入,sws_scale注意宽高与linesize匹配。

ffmpeg C++ 项目怎么链接 libavcodec 等库
不链接对的库,avcodec_open2 这类函数连编译都过不去,不是“找不到定义”就是“undefined reference”。C++ 本身不区分 C 符号,但 FFmpeg 是纯 C 实现,头文件里必须用 extern "C" 包裹,否则 C++ 编译器会做 name mangling,导致链接失败。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 所有 FFmpeg 头文件包含前加
extern "C"块,例如:extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> } - 链接顺序不能错:依赖关系是
avformat → avcodec → avutil → swscale → swresample,CMake 中用target_link_libraries(myapp PRIVATE avformat avcodec avutil swscale swresample) - Linux 下确保 pkg-config 可用,用
pkg-config --libs libavformat libavcodec校验实际链接参数;Windows 用 MinGW 或 MSVC 都要手动配好.lib路径,别只丢头文件
av_read_frame 返回 AVERROR(EAGAIN) 怎么处理
这不是错误,是 FFmpeg 在非阻塞模式下“暂时没数据”,但很多人直接当异常退出,结果音视频刚打开就卡死。根本原因是没设对 AVFormatContext 的 flags,或底层 IO 上下文没配好缓冲。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 初始化
AVFormatContext*后,显式关闭非阻塞:fmt_ctx->flags &= ~AVFMT_FLAG_NONBLOCK;
- 如果用了自定义
AVIOContext(比如网络流),确保read_packet回调在无数据时返回 0 而不是AVERROR(EAGAIN),除非你真在做异步拉流 - 真正该检查的是
av_read_frame返回且不等于 <code>AVERROR_EOF和AVERROR(EAGAIN)的情况,比如AVERROR_INVALIDDATA才代表流损坏
解码 H.264 时 avcodec_send_packet 一直返回 -11
-11 是 AVERROR(EAGAIN),但这里和 av_read_frame 不同:它表示解码器内部输入队列满了,必须先调 avcodec_receive_frame 把已解出的帧取走,才能继续喂包。新手常写成“送完所有 packet 再统一收 frame”,结果卡在第一个 send 就失败。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 必须严格按“送包 → 收帧 → 送包 → 收帧”循环,不能攒包;伪代码逻辑是:
while (av_read_frame(fmt_ctx, &pkt) >= 0) { avcodec_send_packet(dec_ctx, &pkt); while (avcodec_receive_frame(dec_ctx, frame) == 0) { // 处理 frame } av_packet_unref(&pkt); } - 注意
avcodec_receive_frame返回 0 表示成功,AVERROR(EAGAIN)表示暂无输出(需再送包),AVERROR_EOF表示解码结束 - H.264 的 SPS/PPS 必须随第一个关键帧一起送入,如果 demux 出的 packet 没带这些(比如某些 MP4 封装),要用
avcodec_parameters_to_context提前初始化解码器
sws_scale 转 RGB 时图像偏绿或花屏
这是像素格式没对齐最典型的症状。比如源是 AV_PIX_FMT_YUV420P,目标设成 AV_PIX_FMT_RGB24,但忘了给 sws_getContext 传正确的宽高——特别是 YUV420P 的 UV 平面宽高是 Y 的一半,而 sws_scale 会按你传的“目标宽高”直接填内存,越界就踩到其他变量。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 调
sws_getContext时,src_w/src_h 必须是原始帧的width/height,dst_w/dst_h 是目标图像尺寸,不要用frame->width(那是对齐后尺寸,可能大于真实宽高) - YUV 数据的 linesize[0/1/2] 必须和像素格式匹配:YUV420P 的
linesize[1] == linesize[2] == linesize[0]/2,RGB24 则只有linesize[0]有效,其余为 0 - 务必检查
sws_scale返回值,它可能小于 dst_h(尤其缩放时),别假设每次都能填满整块内存



















