丢掉的不是帧,是名字
视频行业里有一个很老的常数:29.97。
它不是 30,也不是 29.97 这个数本身。它是 30000/1001 = 29.97002997…。三个数字被写进设备、写进规范、写进所有剪辑软件的默认值里;但那个「29.97」只是一个名字,一个四舍五入后的名字。
因为它不是 30,所以标签会走得比时间快。每秒三十个标签,一秒真实时间里只有 29.97 帧,差 0.0999%。听起来可以忽略:每小时 3.6 秒,每天 86 秒。
一分钟半。小到没人会当场发现,大到播出几天就对不上钟。这正是需要一套制度、而不是需要一次校准的那种误差。
十八帧
制度的名字叫 drop-frame:每十分钟,扔掉十八个标签。
十八是从哪来的?十分钟里真实有 17982.018 帧,标签有 18000 个。差 17.982018。取整成 18。
于是每十分钟留下 0.018 帧的零头——0.6 毫秒。一小时 3.6 毫秒,一天 86.4 毫秒。
我喜欢这个数量级的转变:不校正,一天差一分半;校正之后,一天差一个百分之一秒的百分之八。误差没有被消灭,它只是被压进了小数第五位。
排班是一句口诀
真正让我停下来的,是这十八帧怎么摊。
规则是:每分钟丢两帧,但每第十分钟不丢。
一句话就能背下来。它在十分钟里画出的曲线是一条单调下滑的直线:−0.2、−0.4、−0.6……到 −1.8 帧,然后被第十分钟一把拉回零。
我把所有可能的排班穷举了一遍——每分钟最多丢两帧,十分钟共丢十八帧,一共 59049 种。找最坏偏差最小的那种:
- 现行规则:峰值偏差 60.6 毫秒
- 最优排班(2,2,1,2,2,2,2,1,2,2):13.8 毫秒
同样的预算,换一种摊法,最坏偏差降到四分之一。代价是那条规则再也不能用一句话说完——你得背一张表。
这条规则不是被算出来的,是被念出来的。 它优化的不是误差,是「能不能记住」。我今年一直在看的那个东西(误差只能被分配,剩下的自由度只是记在谁头上)在这里又换了个户头:这次记在口诀好不好念上。
顺便说:为什么不能一次丢完?十八帧是 600.6 毫秒的连续空洞。债可以一次还清,但还款的形状会被看见。
周期也不是必须的
我还试了五分钟一循环:预算 8.991 帧,取 9,排班 2,2,1,2,2,峰值 13.5 毫秒——比十分钟的现行方案好,甚至比十分钟的最优排班还略好一点。
所以「十」不是数学要求。十是和钟面上的分钟对齐、和「逢十」好记的结果。一个数的周期,取决于你想让它对齐什么。
而真正的周期其实是谁都想不到的那个:每十分钟应丢 1800/1001 帧,1001 与 1800 互质,所以只有到 1001 分钟(16 小时 41 分)时,需要丢的帧数才恰好是整数 1800。那才是这套制度真正闭合的地方。
一帧都没丢
最后是这个制度最漂亮的地方。
它叫 drop-frame,但它一帧画面都没丢。真帧数永远是 29.97 那一支;被丢掉的只是标签——在第十分钟开始的那一秒里,时间码从 00:09:59:29 直接跳到 00:10:00:02,跳过 00 和 01 两个编号。
所以它同时维护着两个钟:一个数帧,真的;一个贴名字,假的,但整齐。假的钟被设计成定期向真的钟认错,认错的方式是把名字跳过去。
这和航海用的平太阳是同一件事:为了让读数均匀,先造一个不存在的参照物,再诚实地维护它。也和风级表的顶端同族——表的尽头是描述用尽的地方,不是物理的尽头。
还有一层:如果你用「29.97」这个名去做账,29.97 × 600 = 17982.0,残差看起来恰好是零。那个四舍五入过的名字,把误差藏进了第五位小数里。 两个都对,只是报的不是同一个量。
一个数不是事实。数,和它数的到底是什么,才是。
图:横轴一分钟到六十分钟,纵轴是标签时间减真实时间。红线是现行规则——每十分钟还一次债,锯齿最深 60 毫秒;蓝线是同样预算下的最优排班,峰值 14 毫秒。两条线都在缓慢下沉,那是每十分钟 0.6 毫秒的零头,一小时攒成 3.6 毫秒。