一帧画面是怎么来的

UNIT 12后期约 21 分钟 · 完整线

从一帧帧画面到一部片

暂停一段跑步的视频,定格的那一帧里,挥动的手常常是糊的:一帧不是一个瞬间,是快门开着的一小段时间。长卷宣传片第二版交给你以后,你问:「移动的时候,画面会闪烁。这是什么问题?是渲染过程中的问题,还是编码过程中的问题?」C14 这一课回答它:帧和帧之间发生了什么,帧又是怎么变成文件的。

长卷里的一条街,镜头正在快速横移:楼、窗户和街上的人都被横着拖出一道道影子。
平移中的一帧。长卷的一条街,镜头每帧横移 48 像素:定格下来,竖线都被横着拖开了。

12 · 1一帧是一段时间

电影每秒 24 帧,快门通常开半帧(电影摄影机的快门是一片转盘,转一圈是一帧,开口 180° 就是开半帧):每帧曝光 1/48 秒,动的东西拉出一道拖影,叫运动模糊(motion blur)。渲染器没有真快门,只会算某一个时刻;想要拖影,就在快门开着的那段时间里取几个时刻各算一遍,再平均,这几个时刻叫子帧(sub-frame)。渲染器能取「第 585.25 帧」这种两帧之间的时刻,是因为画面只由时间决定:给它任何一个时刻,它都能直接算出那一刻,同一个时刻算两遍一模一样。

不要拖影、每帧清清楚楚行不行?快速平移时画面每帧跳几十像素,放起来一顿一顿。那取几个子帧才够?

长卷宣传片第二版,运动模糊固定用 6 个子帧。镜头快速平移(每帧移动 48 像素)时,楼的竖线会是什么样?

  1. 一道平滑的拖影
  2. 一格一格的重影,像梳子齿
  3. 完全清楚:6 个子帧已经够了

一格一格的。快门开半帧,这半帧里画面移动 24 像素(这就是拖影的长度);6 个子帧头尾各落在快门的两端,中间隔成 5 段,相邻两个隔 4.8 像素,每一份都印得清清楚楚,就成了一排梳子齿。第三版改成按速度定子帧数(director.js):子帧数 = 拖影长度 ÷ 2 向上取整再加 1,最少 2 个、最多 24 个,让相邻两个隔 2 像素以内,看上去连成一道。这个速度下是 13 个,间隔正好 2 像素 C14。

快门台子帧、快门位置与剪切点
来自材料
子帧的取法、累加方式和自适应规则照抄长卷成片引擎 director.js;平移画面是长卷公开站的截图。剪切点:红魔 19.5 秒(每秒 30 帧)手机上那个「一下翻个面」的关键帧(set_phone.py;那里从第 1 帧起算,是第 586 帧,本实验按 19.5 × 30 记作第 585 帧),快门用 Blender 默认的半帧(180°)。
本实验的设定
平移速度、手机的样子和它在两帧间转多少,是为演示定的。红魔手机那段用的 Cycles(Blender 的离线渲染器)在快门里取时刻的方式和这里的等间隔子帧不同,但快门跨过翻面那一刻时两个样子都会被取到,这一点一样。
它能证明
子帧间隔和拖影长度的关系;快门窗口跨过跳变键就会出重影。
它不能证明
长卷 v2 闪烁的全部原因(还有瓦片换档和人物的帧率,见 12 · 4)。

它停在长卷第二版的设定:6 个子帧、每帧 48 像素。把子帧数拖到 13,梳子齿连成拖影;拖到 1,再点「播放」,看它一跳一跳。

12 · 2剪切点上的那一帧

「第 585 帧」在时间轴上是 585.00 那一刻,快门窗口就是从哪一刻开到哪一刻。放在哪,Blender 有三个选项:从这一帧开始往后开、以这一帧为中心、开到这一帧为止。平时看不出差别,直到遇上跳变。动画只在几个关键帧(keyframe)上记下位置和角度,中间由软件补(插值);「常量」插值就是不补,到那一刻直接跳。红魔的手机在 19.5 秒的剪切点上就有这么一个键:之前是背面,从 585.00 起一下翻成正面。

快门以帧为中心、开半帧。剪切点那一帧(第 585 帧)会是什么样?

  1. 干净:只有翻转后的正面
  2. 背面和正面叠在一起,各一半
  3. 糊成一片,像快速平移
从帧开始:只看到手机亮着红色屏幕的正面。从帧开始585.00 → 585.50:干净
以帧为中心:手机银色的背面和红色的屏幕半透明地叠在一起,相机孔和圆环像鬼影一样浮在屏幕上。以帧为中心584.75 → 585.25:重影
到帧结束:几乎全是银色背面,淡淡透出一点红色屏幕。到帧结束584.50 → 585.00:最后一个子帧正好落在 585.00,淡淡的重影
快门台里第 585 帧的三种快门位置(16 个子帧)。

以帧为中心时,这一帧的快门从 584.75 开到 585.25,一半的子帧在翻转之前、一半在之后,两个样子各占一半。v4 交片前的自查抓到了它:19.5 秒和 21 秒两个剪切点上各有一帧重影 C26。修法是改成从帧开始(motion_blur_position = 'START'):剪切点那一帧只往后取,全在翻转之后;它前一帧只取到 584.5,全在之前。

在快门台里换成「剪切点上的翻转」,拖「看第几帧」和「快门位置」试试。

12 · 3帧变成文件:平移最吃码率

渲出来的是一张张图,交出去的是一个 mp4。mp4 只是个盒子(容器),里面是按某种编码器(codec)压过的画面,最常见的是 H.264(x264 是压它的程序):隔一段存一张完整的 I 帧,其余的帧只存「和前后帧比哪里变了、往哪挪了」。码率(bitrate)是每秒多少比特,Mbps 即每秒百万比特;一字节 8 比特,码率 = 文件大小 × 8 ÷ 时长。广州片的母版是 ProRes(每帧独立存),100.5 秒 1.9 GB,约 150 Mbps;分享版 H.264,88 MB,约 7 Mbps。先猜一个:

投篮课的成片有个 bug:铁丝网渲成了一堵实心灰墙。修好以后,用完全相同的编码参数(x264,CRF 16,slow——慢一点、压得更好的那一档)重新编码。文件会怎样?

  1. 变小:修掉一个 bug,数据更干净
  2. 差不多:参数没变
  3. 变大,差不多翻倍

220.6 MB 变成 415.6 MB C43。CRF(x264 的画质档,越小越好,默认 23)固定的是画质,不是大小:一堵没有细节的灰墙几乎不用花比特,一张镂空的网每帧都有大量细线,还跟着镜头动,要存的一下多了。

CRF 让码率跟着内容走。分享版要管住文件大小,常常反过来:码率固定,画质跟着内容走;长卷的分享版还压两遍,第一遍看哪里难压,第二遍按这个分比特。下面这段 4 秒的长卷(每秒 30 帧:1 秒不动、2 秒快速平移、1 秒不动)按四种设置压好,在你的浏览器里解码。图里的 PSNR 是和没压过的原片比有多像(dB,越高越像)。

压一压同一段平移,四种压法
来自材料
画面是长卷公开站的截图;三档码率里 2.2 Mbps 是长卷分享版原来的码率、6 Mbps 是改后的 C14;码率固定的三档照长卷 pipeline.sh 的写法两遍编码(x264,slow)。
本实验的设定
这 4 秒是在 Mac 上用 ffmpeg 8.1 从截图生成再压的,不是当年的分享版;拖影按长卷引擎的规则做。每帧字节数由 ffprobe 读出,PSNR 由 ffmpeg 拿无损原片逐帧算。
它能证明
同样的画质,平移的帧比静止的帧贵几十倍;码率固定时,平移那几秒最先吃亏。
它不能证明
别的编码器(硬件编码、H.264 的下一代 HEVC)的数字;也不代表所有平移都一样贵,要看画面里有多少细节。

选 CRF 23 看上面那排柱子:第一帧是 I 帧,约 313 KB;静止时每帧只要两百多字节(几乎只写「和上一帧一样」);一动起来,平均每帧约 16 KB,贵六十多倍。再换成 2.2 Mbps:每秒 2.2 百万比特,除以 8 再除以 30 帧,平均每帧只有约 9 KB。两遍编码已经把静止省下的都挪给了平移,平移时每帧也才约 9.5 KB,只有 CRF 23 时的六成,下面那条 PSNR 从静止时的 42.9 dB 一下掉到 37 dB 左右;停下以后的画面是从压糊了的帧推出来的,也回不到原来。1 Mbps 掉得更多。放大看窗户和墙面,再点「播放」:糊和块都挤在平移那两秒。长卷分享版原来 2.2 Mbps,平移时纹理糊、会闪,提到约 6 Mbps 才好 C14。

在哪台机器上压也是一笔账。帧在 Windows 工作机上渲,合成、压片这些靠 CPU 的活放在 Mac 上:300 帧 1080p,x264 在 Mac(M4)上 1.24 秒、工作机的 i7 上 4.39 秒。芯片里专门的编码电路(硬件编码)只要 0.18 秒,可同样大小下暗部不如 x264 慢速两遍干净,分享版就故意用 x264。代价是搬帧:局域网约 11 MB/s,13 GB 的帧要搬约 20 分钟。

12 · 4闪烁:渲染还是编码?

回到你那个问题。分开渲染和编码,最直接的办法是看没压过的原帧:原帧上就闪的,是渲染;原帧干净、成片才有的,是编码。那一次查下来,主要在渲染,次要在编码。第二版交付时写着「闪烁:已修复并验证」,验证用的是每帧整幅的平均亮度——整幅变亮变暗它抓得到,一小块细节换了样子它看不见。后来把后一帧按镜头的移动挪回去,再和前一帧逐像素相减:没变的地方减成一片黑,变了的地方发亮。第 1250 帧,陈家祠的陶塑屋脊在这张差图上整片发亮:它换了一套细节 C14。

长卷宣传片 v2 的闪烁,拆开来
出在哪原来改成
瓦片精度档位(第 11 课)每放大一倍只有 2 档,推拉时整屏换一套精度每倍 32 档,同一帧只用一档
人和船每秒只更新 12–15 次(片子每秒 30 帧),隔一两帧才动一下每帧都画
运动模糊固定 6 个子帧按速度定,最多 24 个
编码(次要)分享版 2.2 Mbps约 6 Mbps

改完,同一段推拉里差图最亮的一帧和一般的一帧之比,从 1.33 降到 1.10(1 就是完全平稳)。第一版的闪法又不一样:转场处整屏亮一下,平均亮度一测就是 5 帧突然跳——交叉淡化的首尾帧亮度不一致,动、静镜头走了两条不同的合成流程,子帧数一会儿多一会儿少;改成一镜到底、统一 6 个子帧、同一条流程,3075 帧零跳变 C13。可统一的 6 个子帧到快速平移时又不够(12 · 1),第三版才按速度定。还有一次,逐帧亮度抓到了丢显卡的坏帧,却没查封面,封面恰好截自坏帧 C16。一次测量只证明你测的那件事。

12 · 5声音这一轨,也是数字

片子的响不响,按响度(LUFS)算,是整条混音听起来多响,不是最响的那一下;数都是负的,越接近 0 越响:广播标准 −23 LUFS,Spotify 统一到 −14;你的几部片在 −13 到 −16 之间,站里的导览按 −16 做(五条实测都在 −16.0 到 −16.2 之间,真峰值不超过 −1.5 dBTP)。分贝是对数:+6 dB 约是振幅翻倍;两段一模一样、完全同步的声音叠起来是 +6 dB,两段互不相关的声音(比如两条不同的环境声)叠起来只多 3 dB。配音平不平也能量:起伏按半音算,12 × log₂(最高音高 ÷ 最低音高),音高就是声音的频率,一个八度是 12 个半音;长卷旁白原来两句只有 15.1 和 13.1 个半音,每句单写语气、录两版挑起伏大的,到了 19–23 个 C18。配乐的剪点落在小节线上:120 拍每分钟、四拍一小节,一小节 2 秒。AI 生成的配乐末尾常藏一句「当前内容由AI生成」,广州片那首是语音识别在 3 分 16 秒听出来的 C08。

带走一个问题

一段镜头:先静止 2 秒,再快速横移 2 秒。成片在横移时一格一格地抖,还糊、还有块。按这一课的模型,这可能是哪几个环节的事?每一个你怎么单独验证(只改一个条件、看哪里变)?

不看上面,写下这一课撞上的几堵墙,再展开对照
  1. 每帧越清楚越好 → 快速运动一跳一跳;一帧是快门开着的一段时间,要取子帧平均。
  2. 子帧随便取几个 → 相邻子帧隔得太远就成梳子齿;子帧数要跟着速度走。
  3. 快门窗口以帧为中心 → 跨过剪切点上的跳变键,一帧里两个姿态叠在一起;改成从帧开始。
  4. 画质参数不变文件就不变 → CRF 固定的是画质,码率跟着内容走;码率固定时,平移先吃亏。
  5. 测过了就是没问题 → 平均亮度抓不到局部细节的跳变;测的是什么,就只证明什么。