swscale 只做两件事:改尺寸、改格式。 两件事能在一次调用里同时做,不必转两趟。
11.1 讲了色彩的原理,这一节讲干这件事的工具。 11.3 用它处理真实的一帧。
一、这一层有多大
本机认得 267 种像素格式,比编解码器还多。 项 值
像素格式总数 267 常用几个 yuv420p/nv12/rgb24/gray
为什么这么多:每种色度采样比例(4:2:0/4:2:2/4:4:4)、每种位深(8/10/12/16 位)、 每种排布都算一种。 常用的其实只有十来个,其余是专业设备与中间格式。 所以看格式表别慌,认住 yuv420p 与 rgb24 就够起步。
二、只做两件事
别看名字里只有 scale,它也管格式。 做什么 参数 典型用途
改尺寸 width/height 缩略图、降分辨率省码率 改格式 format YUV 转 RGB 给图像算法
这两件事可以在一次调用里同时做。 因为底层走的是同一条流水线:先重采样像素、再算颜色。 所以「缩到 320 宽再转 RGB」应该写成一次 reformat, 不要写成两次——两次意味着多分配一个中间帧、多拷一遍内存。
三、五个枚举
控制「怎么换」的那几个开关。 枚举 有几个值 管什么
Interpolation 18 缩放插值算法 Colorspace 5 用哪套换算系数 ColorRange 4 limited 还是 full ColorPrimaries 12 红绿蓝的基准色 ColorTrc 17 伽马曲线
前两个最常用,后三个多数时候不用管。 但「颜色偏了」「暗部断层」这类问题,查的就是后三个。 Interpolation 有 18 个值,常用的只有五个:FAST_BILINEAR、BILINEAR、BICUBIC、POINT、LANCZOS。 其余是给专业修复与特殊场合用的。
四、reformat 的七个参数
全都不给也能调,返回一个原样的副本。 参数 默认 说明
width/height 不变 要的尺寸 format 不变 要的像素格式 src_colorspace 自动 进来时按什么算 dst_colorspace 自动 出去时按什么算 interpolation 默认 缩放用什么算法 threads 自动 几线程
「自动」的意思是从帧自己的属性里读,读不到就用默认。
所以源那一侧的 colorspace、color_range 有没有标对,直接决定颜色准不准。
这就是「元数据不是装饰」的一个实例:同一堆像素,标 601 与标 709 解出来的颜色不一样。
很多素材这两个字段是空的,那就只能按默认猜。
五、平面与 stride
这是这一层最容易踩的坑,也是最该记住的一条。 宽度 line_size buffer_size
4 [16, 16, 16] [64, 32, 32] 16 [16, 16, 16] [64, 32, 32] 17 [32, 16, 16] [128, 32, 32] 160 [160, 80, 80] [640, 160, 160]
line_size 是一行占多少字节,它被对齐到 16 的倍数。
宽 4 的那一行实际占 16 字节,只有前 4 个是有用的像素。
所以 buffer_size 总比「宽 × 高」大,它算的是对齐后的账。
手动拷内存时踩错这一条,会拷到垃圾甚至越界。
为什么非要对齐:SIMD 指令一次读 16 或 32 字节,地址不对齐要么慢一倍、要么直接崩。
这是用空间换速度的典型做法。
六、动手 Demo:SWScale 这一层有哪些东西
数一遍像素格式与五个枚举,再量一遍 line_size 的对齐规律。
import av
print(len(list(av.video.format.names)))
# 五个枚举各有多少值
for mod, name in ((av.video.reformatter, "Interpolation"),
(av.video.reformatter, "Colorspace"),
(av.video.reformatter, "ColorRange"),
(av.video.reformatter, "ColorPrimaries"),
(av.video.reformatter, "ColorTrc")):
print(name, len(list(getattr(mod, name))))
# stride:宽多少、一行实际占多少
for w in (4, 8, 16, 17, 160):
f = av.VideoFrame(w, 4, "yuv420p")
print(w, [p.line_size for p in f.planes],
[p.buffer_size for p in f.planes])
# 不给参数也能 reformat
g = av.VideoFrame(8, 8, "yuv420p")
print(g.reformat().format.name)
实跑输出:
--------------------------------------------------------------------
SWScale 这一层有哪些东西
--------------------------------------------------------------------
**① 本机认得多少种像素格式**
项 值
-----------------------------------------------
像素格式总数 267
常用几个 yuv420p/nv12/rgb24/gray
**267 种,比编解码器还多。** 因为每种色度采样比例、每种位深都算一种。
**常用的其实只有十来个**,其余是各种专业格式。
**② swscale 其实只做两件事**
做什么 参数 典型用途
--------------------------------------------------------
改尺寸 width/height 生成缩略图、降低码率
改格式 format YUV 转 RGB 送给图像算法
**两件事可以在一次调用里同时做。**
**所以「缩放 + 转色彩空间」只要一次 reformat,不必转两趟。**
**③ 五个枚举,控制「怎么换」**
枚举 有几个值 管什么
-----------------------------------------------------
Interpolation 18 缩放插值算法
Colorspace 5 用哪套换算系数
ColorRange 4 limited 还是 full
ColorPrimaries 12 红绿蓝的基准色
ColorTrc 17 伽马曲线
**前两个最常用,后三个多数时候不用管。**
**但一旦出问题(颜色偏、暗部断层),查的就是后三个。**
**④ reformat 的七个参数**
参数 默认 说明
------------------------------------------------
width/height 不变 要的尺寸
format 不变 要的像素格式
src_colorspace 自动 进来时按什么算
dst_colorspace 自动 出去时按什么算
interpolation 默认 缩放用什么算法
threads 自动 几线程,默认够用
**全都不给也能调**,它返回一个原样的副本——**这一条用一个空调用就能验。**
**⑤ 平面与 stride**
宽度 line_size buffer_size 有效字节
-----------------------------------------------------------
4 [16, 16, 16] [64, 32, 32] 24
8 [16, 16, 16] [64, 32, 32] 48
16 [16, 16, 16] [64, 32, 32] 96
17 [32, 16, 16] [128, 32, 32] 100
160 [160, 80, 80] [640, 160, 160] 960
**`line_size` 是「一行占多少字节」,它会被对齐到 16 的倍数。**
**宽 4 的那一行,实际占 16 字节,只有前 4 个有用。**
**这就是 `buffer_size` 总比「宽 × 高」大的原因**——**它算的是对齐后的账。**
**手动拷内存时踩错这一条,会拷到垃圾甚至越界。**
267 种像素格式,五个枚举分别是 18/5/4/12/17。
line_size 对齐到 16,宽 4 与宽 16 的 buffer_size 一样大。
30 秒实验
- 用
Interpolation.POINT缩一张图,与BICUBIC比锯齿(提示:肉眼看边缘)。 - 打印
av.video.format.names里含420的所有名字。 - 建一个 1920×1080 的 yuv420p 帧,看
line_size是不是正好 1920。
常见误区
- 以为 swscale 只缩放。 它也换像素格式与色彩空间。
- 分两次调 reformat。 一次能同时做完,两次多一次拷贝。
- 把 buffer_size 当成「宽 × 高」。 它含对齐填充。
自测三问(点开对答案)
1. swscale 做哪两件事? —— 改尺寸与改像素格式(含色彩空间)。 2. `line_size` 为什么比宽度大? —— 它被对齐到 16 的倍数,方便 SIMD 与预取。 3. 遇到「颜色偏」先查什么? —— 先查 colorspace 与 color_range,再查编码。- ☐ (本节完,下一节 11.3 SWScale图片色彩空间转换案例实战)