sws_getContext参数顺序为:源宽、源高、源像素格式,目标宽、目标高、目标像素格式,缩放算法,后三参数通常为NULL;易错点是源/目标像素格式颠倒或宽高与实际帧数据不一致。

sws_getContext参数顺序和像素格式容易写反
创建 sws_getContext 时,源格式、目标格式、缩放算法三者顺序固定:源宽高+源格式、目标宽高+目标格式、算法。常见错误是把 AV_PIX_FMT_YUV420P 和 AV_PIX_FMT_RGB24 位置颠倒,或误用 AV_PIX_FMT_BGR24(OpenCV默认用BGR,但纯FFmpeg转RGB24就是RGB)。宽高必须和实际帧数据一致,不能传0或任意值——否则 sws_scale 会返回0且不报错。
示例关键行:
SwsContext* sws_ctx = sws_getContext(
width, height, AV_PIX_FMT_YUV420P,
width, height, AV_PIX_FMT_RGB24,
SWS_BILINEAR, nullptr, nullptr, nullptr
);注意:width 和 height 必须是原始YUV帧的实际尺寸;若YUV数据带对齐填充(如stride不是width),需用 av_image_fill_arrays 正确设置源 data 和 linesize,否则颜色错乱。
YUV420P的linesize要按plane分别处理
YUV420P是planar格式,共3个plane:Y占一行宽,U/V各占半宽半高,且U/V的linesize通常是Y的一半(因水平采样为2:1)。但FFmpeg的 AVFrame 中 linesize[0]、linesize[1]、linesize[2] 可能不等于 width 或 width/2——尤其当内存对齐(如16字节对齐)时,linesize[0] 可能是 ≥ width 的最小对齐值。
立即学习“C++免费学习笔记(深入)”;
正确做法:
- 用
av_frame_get_buffer分配frame后,直接读取其linesize数组,别硬编码 - 调用
sws_scale时,源srcSlice的srcSliceY从0开始,srcSliceH传真实高度(非linesize) - 目标RGB24是packed格式,只有一块连续内存,
dst的data[0]是起点,linesize[0]应为width * 3
sws_scale返回值为0不代表失败
sws_scale 返回处理的行数(int),正常应等于输入的 srcSliceH。但它可能返回0——这通常不是出错,而是:输入的 srcSliceY + srcSliceH 超出了源frame的有效高度,或 srcSliceH 为0。FFmpeg不会报错,只会静默返回0,导致目标内存没被写入,后续读取全为脏数据。
调试建议:
- 打印
srcSliceY、srcSliceH、源frame的height,确认srcSliceY + srcSliceH ≤ height - 确保源
data指针非空,且每个plane的data[i]都有效(YUV420P要求data[0]、data[1]、data[2]均非空) - 不要忽略返回值,加断言:
assert(sws_scale(...) == srcSliceH)
内存布局和字节序问题常被忽略
RGB24是每像素3字节:R、G、B顺序,无alpha。但某些显示库(如SDL2)默认期望BGRA,或OpenGL纹理要求特定排列。如果转完数据直接送显却颜色发紫/发绿,大概率是字节序误解——不是FFmpeg转错了,而是下游消费方理解错了。
验证方法:
- 用
ffplay -f rawvideo -pix_fmt rgb24 -s WxH out.rgb播放生成的二进制文件,确认是否正常 - 手动检查前几个像素:读取
dst_data[0]开头3字节,应为R值(偏亮区域R≈200),而非B值 - 若需BGR24,改用
AV_PIX_FMT_BGR24并同步调整下游逻辑,别在转完后逐字节交换
YUV420P到RGB24本身没有平台字节序依赖,但整个流程中任何一环(如memcpy、文件写入、GPU上传)若假设错误的内存布局,就会出问题。最稳妥的方式是全程用FFmpeg API管理内存,避免裸指针操作。


















