🎬 第二章 把控FFmpeg骨架:【八大金刚】核心开发库
📄 一句话概括

一个 sws_scale 同时干两件事:改尺寸、改像素格式。 它只管数与数的换算,不管色彩管理——HDR 转 SDR 它做不了。

📝 本节和前面几节的关系

2.8 管声音,这一篇管画面。八个库到此认完。 第三章开始拿真实数据走流程,第一个用的是 AVPacket 与 AVFrame。

一、一个函数,两个用途

sws_scale 既改尺寸也改像素格式,还能一起改。 为什么能一起改?因为它本质是「按目标格式重新采样每个像素」,尺寸只是采样网格的一部分。 项 源 目标


宽高 1920×1080 1280×720 像素格式 yuv420p rgb24 每帧字节 约 3.1 MB 约 2.8 MB

表里第三行值得算一遍:yuv420p 每个像素平均 1.5 字节,rgb24 是 3 字节。 所以缩小一半之后,rgb 反而更大。 所以「转成 rgb 再处理」这句常见做法,代价是内存翻倍。 能只在需要那一步转,就别全程转。

二、267 种像素格式,常用的十来个

格式 典型用途


yuv420p 最通用,兼容性最好 nv12 摄像头、硬件编码 rgb24 bgr24 OpenCV 与绘图 gray 算法中间结果 yuv444p 无损处理

选错格式的代价很实在:yuv420p 转 rgb24 再转回 yuv420p,色彩会有可见损失; 而 yuv420p 直接缩放,损失小得多。 一条原则:能一步做完就别拆两步。 缩放与格式转换在同一个 sws_scale 里做完, 比转两次少一次有损环节。

三、它不管色彩管理

libswscale 只做数与数的换算,不做 gamma、不做色域映射、不做色调映射。 HDR 转 SDR 它做不了。 那要 libavfilter 里的 zscale 一类滤镜, 而 zscale 又要额外的库(zimg)。 本机没有 zscale,所以这一层只能做到「格式对了」,做不到「颜色准了」。 第十三章接 OpenCV 做美颜时会再遇到这个问题。 判断方法很简单:filters_available 里查 zscale,没有就是没编。 别指望 swscale 能替你解决 HDR。

四、缩放质量的三个选项

算法 速度 质量


fast_bilinear 最快 糊 bilinear 快 够用,默认 bicubic 中等 好,缩小首选 lanczos 慢 最好,放大首选

缩小用 bicubic、放大用 lanczos,这是性价比最高的两条默认。 倍率很关键:缩小超过四倍,什么算法都保不住细节;放大超过两倍,边缘一定会软。 这跟算法无关,是信息量的上限。

五、动手 Demo:libswscale——缩放与像素格式,一个函数干两件事

这一段算两种格式的每帧字节数,说明「转 rgb 的代价」。 本机没有 zscale,所以色彩管理那一步做不了。

w, h = 1920, 1080
print("yuv420p", w * h * 3 // 2)
print("rgb24  ", w * h * 3)

实跑输出:

--------------------------------------------------------------------
libswscale——缩放与像素格式,一个函数干两件事
--------------------------------------------------------------------

**① 它的输入输出都是「一帧」**

  项           源            目标
  ----------------------------------------
  宽高         1920×1080     1280×720
  像素格式     yuv420p       rgb24
  每帧字节     约 3.1 MB     约 2.8 MB

**② 一个函数,两个用途**

`sws_scale` 既能改尺寸,也能改像素格式,还能两个一起改。
**因为它本质是「按目标格式重新采样每个像素」**,尺寸只是采样网格的一环。

**③ 本机有 267 种像素格式,常用的十来个**

yuv420p(最通用)、nv12(摄像头与硬件编码)、rgb24/bgr24(OpenCV 与绘图)、gray(算法中间结果)、
yuv444p(无损处理)。

**选错格式的代价很实在**:yuv420p 转 rgb24 再转回 yuv420p,色彩会有可见损失;
而 yuv420p 直接缩放,损失小得多。**能一步做完就别拆两步。**

**④ 它不管色彩管理**

libswscale 只做「数与数之间的换算」,不做 gamma、不做色域映射。
**HDR 转 SDR 那种事它做不了**,得用 libavfilter 里的 zscale 一类滤镜,而那需要额外的库支持。

**本机没有 zscale**(它要 zimg),所以这一层只能做到「格式对了」,做不到「颜色准了」。
第十四章接 OpenCV 做美颜时,这条路会再遇到一次。

同一分辨率,rgb24 是 yuv420p 的两倍。 所以「全程转 rgb 处理」会让内存翻倍,只在必要那一步转。

30 秒实验

  1. python -c "import av; print(len(av.video.format.names))" 数像素格式。
  2. 用两种算法把 1080p 缩到 360p,对比文件大小与肉眼细节。
  3. 查 filters_available 里有没有 zscale,判断本机能不能做 HDR 转换。

常见误区

  1. 以为 swscale 能做 HDR 转 SDR。 它不做色彩管理,那要 zscale。
  2. 全程转成 rgb24 处理。 内存翻倍,还多一次有损转换。
  3. 放大时用 fast_bilinear。 快是快,边缘糊得看不出原样。
自测三问(点开对答案) 1. sws_scale 为什么能同时改尺寸与格式? —— 它本质是按目标格式重新采样每个像素,尺寸只是采样网格的一部分。 2. 为什么说「转 rgb 处理」有代价? —— rgb24 每像素 3 字节,yuv420p 平均 1.5 字节,同一画面内存翻倍,且多一次有损转换。 3. 本机能做 HDR 转 SDR 吗? —— 不能。那要 zscale 滤镜,本机没编,swscale 只管数与数的换算。

相关笔记