🎬 第二章 FFmpeg命令行初体验
📄 一句话概括

525 行变成 480 行,和 PAL 是同一套算法。差别在于它的帧率不是整数。 29.97 的精确值是 30000/1001,千分之一的偏差会累积成麻烦。

📝 本节和前面几节的关系

2.8.2 把 PAL 算到底,这一节用同一套方法算 NTSC,正好对比着看。 本章到此结束,第三章开始逐个细讲三个工具的全部选项。

一、525 行变成 480 行

算法和 PAL 完全一样:总行数扣掉消隐,剩下的就是有效行。

项 PAL NTSC 差别


扫描行 625 525 少 100 行 有效行 576 480 少 96 行 宽度 720 720 一样 帧率 25 29.97 快约 20%

第三行的「宽度一样」很有意思:720 是数字取样标准定的,跟模拟行数无关。 所以两套完全不同的扫描体系,最后都用了 720 这个宽度。

这也意味着「720×576」和「720×480」看着只差高度,实际背后是两套体系。 把 PAL 素材当 NTSC 处理,画面会被拉长;反过来会被压扁。

二、29.97 到底是多少

这个数字有三种写法,用哪个场合不一样:

写法 值 该用在哪


分数 30000/1001 精确值,ffmpeg 内部就用它 小数 29.9699… 四舍五入成 29.97 是给人看的 与 30 的比 0.999001 差了约千分之一

第一行是关键:ffmpeg 的参数里写 29.97 会被自动转成接近的分数, 但要精确匹配必须写 30000/1001。两个写法在某些场合结果不一样。

什么时候会踩这个坑?做帧精确的剪切、做长时间的时间码统计、 或者要把两段素材无缝拼接时——差一帧都会露出来。

三、千分之一累积成什么样

单帧差 0.03 毫秒,感觉可以忽略。但播出是连续几小时的:

时长 按 30 算 按 29.97 算 差多少帧


1 小时 108000 107892 108 1 天 2592000 2589410 2590 30 天 77760000 77682317 77683

一小时差 108 帧就是 3.6 秒。一天差 86 秒,够让字幕和画面彻底错开。 所以广播行业必须有「丢帧时间码」这种东西。

名字容易误会:它丢的是时间码的编号,不是画面。 画面一帧都没少,只是每过几分钟就跳过几个编号,让时间码追上真实时间。

这也能解释一个日常现象:为什么剪 29.97 的片子, 时间线上显示的时间和实际钟表时间总是差一点——它在补偿这个千分之一。

四、动手 Demo:29.97 这个怪数字的来历

先把 525 行到 480 行的换算走一遍,再算清 30000/1001 这个分数, 最后量一下千分之一的偏差在一天、一个月里会累积成多少帧。

# NTSC 与 PAL 的换算对比
for name, lines, active in ((u"PAL", 625, 576), (u"NTSC", 525, 480)):
    print(u"%s  扫描 %d  有效 %d  折损 %d 行"
          % (name, lines, active, lines - active))

# 29.97 的精确形式
num, den = 30000, 1001
fps = float(num) / den
print(u"30000/1001 = %.6f" % fps)
print(u"和 30 的比 = %.6f" % (fps / 30))

# 偏差累积
for label, hours in ((u"1 小时", 1), (u"1 天", 24), (u"30 天", 720)):
    a = 30 * 3600 * hours
    b = fps * 3600 * hours
    print(u"%s  按30算 %.0f 帧  按29.97算 %.0f 帧  差 %.0f 帧 / %.1f 秒"
          % (label, a, b, a - b, (a - b) / 30.0))

# 同族帧率
for label, n, d in ((u"23.976", 24000, 1001), (u"29.97", 30000, 1001),
                    (u"59.94", 60000, 1001)):
    print(u"%s 就是 %d/%d = %.4f" % (label, n, d, float(n) / d))

实跑输出:

--------------------------------------------------------------------
NTSC 制式——29.97 这个怪数字的来历
--------------------------------------------------------------------

**① 525 行怎么变成 480,和 PAL 是同一套算法**

  项         PAL     NTSC      差别
  ------------------------------------------
  扫描行     625     525       少 100 行
  有效行     576     480       少 96 行
  宽度       720     720       一样
  帧率       25      29.97     快 20%

**有意思的是宽度都是 720——那是数字取样标准定的,和模拟行数无关。**
**所以「720×576」和「720×480」看着只差高度,其实背后是两套完全不同的扫描体系。**

**② 29.97 到底是多少**

  写法               值             说明
  ------------------------------------------------------
  分数形式           30000/1001     这是精确值
  小数形式           29.9699…       四舍五入到 29.97
  和整数 30 的比     0.999001       差了约千分之一

**所以看到 29.97 就要想到它不是一个「随便定的数」,而是 30000/1001。**
**ffmpeg 里写 29.97 会被自动转成这个分数,但精确匹配要用 30000/1001。**

**③ 千分之一的偏差,累积起来有多少**

  时长       按 30 算的帧数     按 29.97 算的帧数     差多少帧
  ----------------------------------------------------------------
  1 小时     108000             107892                108
  1 天       2592000            2589410               2590
  30 天      77760000           77682317              77683

**一小时差 108 帧,也就是 3.6 秒。一天差 86 秒。**
**所以广播行业必须用「丢帧时间码」:跳过一些编号,让时间码追上真实时间。**
**注意它丢的是编号,不是画面——画面一帧都没少。**

**④ 59.94 也是同一个道理**

**59.94 = 2 × 29.97,23.976 = 24 ÷ 1.001。**
**凡是和 NTSC 沾边的帧率,都带着这个 1001 的尾巴。**
**所以 ffmpeg 里 24000/1001、30000/1001、60000/1001 这三个分数会经常见到。**

第一段那个「折损」一列,PAL 是 49 行、NTSC 是 45 行,比例差不多。 两套体系的消隐比例接近,说明这个折扣是扫描原理带来的,不是各自的特殊设计。

第二段的 30000/1001 是核心:它既是定义也是实现。 写 29.97 只是这个分数的近似,很多场合够用,做帧精确就得用分数。

最后一段那三个分数是 NTSC 家族的全部成员。 23.976 是电影转电视用的(24 除以 1.001),59.94 是高帧率的双倍。 凡是和 NTSC 沾边的帧率,都带着这个 1001 的尾巴。

所以 ffmpeg 里最常打交道的三个帧率分数就是 24000/1001、30000/1001、60000/1001。 记住这三个,以后看到一堆奇怪的小数就不会发懵。

30 秒实验

  1. 算一次:用 Python 算 30000/1001 和 29.97 的差,看差在哪个小数位。
  2. 验一次:ffprobe -show_streams 找 r_frame_rate,很多真素材写的就是 30000/1001。
  3. 比一次:ffmpeg -i in.mp4 -r 30 out.mp4,把 29.97 转成 30,看它怎么处理那一帧的差。

常见误区

  1. 以为 NTSC 是 30 帧。名义 30,实际 30000/1001。做帧精确操作时必须用分数写法。
  2. 以为「丢帧时间码」丢的是画面。它只跳编号不跳画面,画面一帧都没少。
  3. 把 720×480 当 720×576 处理。两套体系高度不同,混用会让画面被拉伸或压扁。
自测三问(点开对答案) 1. 29.97 的精确值是什么?为什么不是整数 30? —— 精确值是 30000/1001。当年为了在黑白信号带宽里塞进彩色信息,把行频减慢了千分之一。 2. 千分之一的偏差,一天能累积多少? —— 约 2590 帧,也就是 86 秒多。所以广播行业必须用丢帧时间码来补偿。 3. 23.976、29.97、59.94 这三个数有什么共同点? —— 都是「整数除以 1.001」:24000/1001、30000/1001、60000/1001。凡是 NTSC 家族的帧率都带这个尾巴。

相关笔记