sws_scale 到底在干嘛?—— FFmpeg libswscale 最细参数说明书
目录
一、先给一句话定性
二、sws_scale 函数原型
三、参数逐个拆解
① struct SwsContext *c
是什么
flags 常见值(必须知道)
② const uint8_t *const srcSlice[]
是什么
合法值示例
③ const int srcStride[]
是什么
为什么不等于 width * bpp?
④ int srcSliceY
官方语义
现实情况
⑤ int srcSliceH
是什么
⑥ uint8_t *const dst[]
是什么
玩法 A:AVFrame 接住
玩法 B:自己 malloc
⑦ const int dstStride[]
最常见翻车点
正确示例(RGB32)
YUV420P 输出
四、使用示例
五、90% 花屏 / 灰边 / 崩溃的真实原因
六、colorspace / range 怎么塞进去?
七、一句话总结
觉得有用,就请您帮忙点赞转发收藏吧,您的鼓励是我创作的动力,多谢看官。
由于能力水平有限,文中的错误或不严谨的地方在所难免,还请批评指正。
sws_scale是 FFmpeg 多媒体框架中libswscale库的核心函数,主要用于高效地执行图像像素格式转换、分辨率缩放以及图像滤波处理。它通常在视频解码后、渲染或编码前被调用,将解码得到的原始帧数据(如 YUV 格式)转换为目标格式(如 RGB 格式)或调整尺寸。
做播放器的人,早晚都会遇到这一句:
sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, dst->data, dst->linesize);抄能用,但一问:为什么传 linesize?为什么 srcSliceY 永远是 0?dstStride 能不能乱填?
今天就把它拆干净。
一、先给一句话定性
sws_scale 不是“画图函数”,是像素搬运工:
负责 YUV↔RGB / resize / colorspace / range 全部打包干完。
核心任务只有两件:
格式转换(Pixel Format)
几何缩放(Scale)
二、sws_scale 函数原型
int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[]);看着吓人,其实分组很好记:
上下文 src 数据 / 步长 裁剪区域 dst 数据 / 步长三、参数逐个拆解
①struct SwsContext *c
是什么
一次初始化,终身干活(直到分辨率/格式变)
由这个函数产出的:
struct SwsContext *sws_ctx = sws_getContext( src_w, src_h, src_fmt, dst_w, dst_h, dst_fmt, SWS_BILINEAR, NULL, NULL, NULL );flags 常见值(必须知道)
flag | 中文 | 用在哪里 |
|---|---|---|
| 快双线性 | 播放器首选 |
| 双线性 | 质量稍好 |
| 立方 | 放大好看 |
| 最近邻 | 截图 / 调试 |
| 锐 | 缩图强迫症 |
| 均值 | 缩得很小 |
实时播放器结论:
1080p↓:
SWS_FAST_BILINEAR放大预览:
BICUBIC
②const uint8_t *const srcSlice[]
是什么
AVFrame->data 原样传
srcSlice = frame->data;合法值示例
格式 | srcSlice 含义 |
|---|---|
YUV420P |
|
NV12 |
|
RGB24 |
|
RGBA |
|
别传 AVFrame,传它的 data*
③const int srcStride[]
是什么
每一平面的“行跨度(bytes per line)”
srcStride = frame->linesize;为什么不等于 width * bpp?
CPU 对齐(32 / 64)
GPU / SIMD 友好
例:1280×720 yuv420p
linesize[0] = 1280 (Y) linesize[1] = 640 (U) linesize[2] = 640 (V)但 1278 宽可能变成:
linesize[0] = 1280 ← padding!sws_scale 靠 stride 找下一行
❌ 自己算 stride = 花屏之源
④int srcSliceY
官方语义
从第几行开始处理(切片)
现实情况
srcSliceY = 0; // 99% 情况什么时候不是 0?
多线程切条处理 slice(古老优化)
超大图分段 scale(现在没人这么干)
📌 记住:
播放器永远传 0
⑤int srcSliceH
是什么
要处理的行数
正确写法:
srcSliceH = frame->height;别写 dst_h / coded_height
⑥uint8_t *const dst[]
是什么
输出缓冲区
两种玩法:
玩法 A:AVFrame 接住
av_frame_get_buffer(dst_frame, 32); dst = dst_frame->data;玩法 B:自己 malloc
uint8_t* rgb = new uint8_t[w*h*4]; uint8_t* out[1] = { rgb };注意对齐,推荐av_malloc()
⑦const int dstStride[]
最常见翻车点
正确示例(RGB32)
int dst_stride = dst_w * 4; uint8_t* out[1] = { buf }; int stride[1] = { dst_stride };YUV420P 输出
int dst_linesize[3] = { dst_w, dst_w / 2, dst_w / 2 };sws_scale 不帮你 alloc,也不帮你猜 stride
四、使用示例
SwsContext* sws = sws_getContext( dec_frame->width, dec_frame->height, (AVPixelFormat)dec_frame->format, dst_w, dst_h, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr ); uint8_t* rgb = (uint8_t*)av_malloc(dst_w * dst_h * 3); uint8_t* out[] = { rgb }; int dst_stride[] = { dst_w * 3 }; sws_scale(sws, dec_frame->data, dec_frame->linesize, 0, dec_frame->height, out, dst_stride);五、90% 花屏 / 灰边 / 崩溃的真实原因
症状 | 真凶 |
|---|---|
右边彩色条纹 | dstStride ≠ width*bpp |
上下错位 | srcSliceH 传错 |
颜色发绿 | pixfmt 传 AV_PIX_FMT_YUV420 → YUVJ420P |
缩放糊 | flag 用 POINT |
内存越界 | dst buffer 没算 padding |
六、colorspace / range 怎么塞进去?
sws_scale只看像素布局,不认 color_range / primaries。
高级玩家这样玩:
sws_setColorspaceDetails( sws, sws_getCoefficients(AVCOL_SPC_BT709), 1, // src_range (0=full) sws_getCoefficients(AVCOL_SPC_BT709), 1, // dst_range 0, 1<<16, 1<<16 );不然 YUV→RGB 永远“差点味”
七、一句话总结
sws_scale = src/data/linesize + dst/data/linesize + 裁剪从 0 到 height
永远用 AVFrame 的 linesize,别自己算,flags 别瞎选。
