ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

sws_scale 到底在干嘛?—— FFmpeg libswscale 最细参数说明书

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 全部打包干完。

核心任务只有两件:

  1. 格式转换(Pixel Format)

  2. 几何缩放(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

中文

用在哪里

SWS_FAST_BILINEAR

快双线性

播放器首选

SWS_BILINEAR

双线性

质量稍好

SWS_BICUBIC

立方

放大好看

SWS_POINT

最近邻

截图 / 调试

SWS_LANCZOS

缩图强迫症

SWS_AREA

均值

缩得很小

实时播放器结论:

1080p↓:SWS_FAST_BILINEAR

放大预览:BICUBIC


const uint8_t *const srcSlice[]

是什么

AVFrame->data 原样传

srcSlice = frame->data;
合法值示例

格式

srcSlice 含义

YUV420P

{data[0], data[1], data[2]}

NV12

{data[0], data[1]}

RGB24

{data[0]}

RGBA

{data[0]}

别传 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 别瞎选。

返回列表