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

PAL、NTSC、SECAM 三种模拟制式,行数、场频、帧率都不一样。 这些数字今天还在影响每一个 ffmpeg 参数的默认值。

📝 本节和前面几节的关系

2.7 讲的是一个「看得懂的格式」,这一节回到历史,讲清那些古怪数字的出处。 2.8.2 和 2.8.3 分别把 PAL 与 NTSC 算到底。

一、三种制式,三套参数

模拟电视时代,各国选的路不一样,留下的参数也不一样:

制式 扫描行 场频 帧率 主要地区


PAL 625 50 25 中国、欧洲、澳洲 NTSC 525 60 29.97 北美、日本 SECAM 625 50 25 法国、俄罗斯、非洲

第一列的行数不是随便定的,它跟当地的交流电频率有关: 50 Hz 的地区用 50 场,60 Hz 的地区用 60 场——早期设备靠电源同步。

所以「用哪种制式」在当年不是技术选择,是地理选择。 这也解释了为什么今天同一个视频在不同国家还要挑不同的版本。

二、场和帧是两倍关系

最容易搞混的一对概念,其实关系很简单:

概念 含义 PAL NTSC


场 一次扫描的半幅画面 50 60 帧 两场拼成一幅完整画面 25 30 关系 帧率 = 场频 ÷ 2 — —

因为当年是隔行扫描:先扫奇数行,再扫偶数行,两次凑成一幅完整画面。 所以「50 场」和「25 帧」说的是同一件事,只是数法不同。

这个换算在看规格时特别有用:看到「1080i50」,就是「1080 隔行、每秒 50 场」, 等价于 25 帧;看到「1080p50」,那是逐行 50 帧,信息量是前者的两倍。

最后一个字母是隔行标志:i 是隔行,p 是逐行。 这两个字母的区别,比分辨率数字更能决定一路流要多少带宽。

三、为什么 NTSC 那个 29.97 这么怪

按上表的规律,NTSC 应该是 60 场、30 帧,整数多干净。 可实际是 29.97,差的那千分之一是后来加的。

原因是彩色电视要兼容黑白电视:彩色信号要在原来的带宽里塞进色度信息, 为了不让色度干扰伴音载波,工程师把行频减慢了千分之一。

这个改动小到肉眼看不出,但它留下了一个永久的麻烦: 帧率不再是整数,时间码和真实时间会慢慢对不上。

差多少、怎么补,2.8.3 会把数算完。这里只要记住一句: 29.97 不是四舍五入的结果,它的精确值是 30000/1001。

四、动手 Demo:PAL 与 NTSC 到底差在哪

把三种制式的参数摆在一起,再把「场」与「帧」的换算算一遍。 最后量一下千分之一的偏差累积一小时会变成多少帧。

# 三种制式的参数表,纯查表,不涉及设备
STD = {
    u"PAL":   dict(lines=625, field=50,  fps=25.0),
    u"NTSC":  dict(lines=525, field=60,  fps=30000.0 / 1001),
    u"SECAM": dict(lines=625, field=50,  fps=25.0),
}

for name, d in STD.items():
    print(u"%-5s 行 %d  场 %d  帧 %.2f"
          % (name, d[u"lines"], d[u"field"], d[u"fps"]))

# 场频与帧率的两倍关系
for name, d in STD.items():
    half = d[u"field"] / 2.0
    print(u"%s 场频÷2 = %.2f,表里写 %.2f,差 %.3f"
          % (name, half, d[u"fps"], abs(half - d[u"fps"])))

# 千分之一偏差累积一小时
n30 = 30 * 3600
n2997 = (30000.0 / 1001) * 3600
print(u"按 30 算 %.0f 帧,按 29.97 算 %.0f 帧,差 %.0f 帧"
      % (n30, n2997, n30 - n2997))
print(u"折合 %.1f 秒" % ((n30 - n2997) / 30.0))

实跑输出:

--------------------------------------------------------------------
制式——PAL 与 NTSC 到底差在哪
--------------------------------------------------------------------

**① 三种模拟制式,参数完全不一样**

  制式      行数     场频     帧率      主要地区
  --------------------------------------------------------------
  PAL       625      50       25        中国、欧洲、澳洲
  NTSC      525      60       29.97     北美、日本、台湾地区
  SECAM     625      50       25        法国、俄罗斯、非洲

**② 场频和帧率是两倍关系,因为隔行**

  概念     含义                     PAL     NTSC
  --------------------------------------------------
  场       一次扫描的半幅画面       50      60
  帧       两场拼成一幅完整画面     25      30
  关系     帧率 = 场频 ÷ 2          25      30

**所以老录像带上的「50 场」和「25 帧」说的是同一件事,只是数法不同。**
**看到「1080i50」就是「1080 隔行、每秒 50 场」,等价于 25 帧。**

**③ 为什么 NTSC 是 29.97 而不是整数 30**

**因为彩色电视要在原来的黑白信号里塞色度,为了不让色度干扰伴音载波,**
**把行频减慢了千分之一:30 ÷ 1.001 ≈ 29.97。**

  项             按 30 算     按 29.97 算     差
  ------------------------------------------------------
  一小时帧数     108000       107892          108 帧
  折合秒数       3600.0       3603.6          3.6 秒

**每小时差 3.6 秒,一天差 86 秒,一个月差 43 分钟。**
**这就是「丢帧时间码」这种东西存在的原因——不是丢画面,是丢时间码的编号。**

**④ 现在这些还有用吗**

**有,两种场合:一是老素材的帧率就摆在那儿;**
**二是各国摄像机的默认值仍是 25 或 30 的体系。**
**所以 ffmpeg 的参数里到处是 25、30、29.97、59.94,一个都不能少。**

第二段那个「差」值得看:PAL 和 SECAM 的场频÷2 正好等于帧率,差是 0。 NTSC 就不为 0 了——因为它的帧率根本不是 60÷2,而是 60÷2÷1.001。

这就是分辨「这是个整数制式还是 NTSC 制式」最快的办法: 场频÷2 能不能整除。不能整除的,背后一定有个 1001。

最后两行是那个千分之一累积的结果。一小时的偏差看着不大, 但播出是连续的,一天的偏差就够让字幕和画面错开好几秒。

注意这些都是「查表 + 算术」,不涉及任何设备。 沙箱里没有摄像头也没有采集卡,制式这一层只能这么验证——但结论是硬的,因为它是定义。

30 秒实验

  1. 查一次:ffmpeg -h demuxer=rawvideo 或看 -framerate 的说明,找到 PAL/NTSC 的预设值。
  2. 算一次:用 Python 算 30000/1001,确认和你以为的 29.97 差多少。
  3. 看一个真文件:ffprobe -show_streams 看 r_frame_rate,常见值就是 25/1 和 30000/1001。

常见误区

  1. 把场频当帧率。50 场不等于 50 帧,隔行扫描下两场才凑一帧。看到 1080i50 要换成 25 帧来算码率。
  2. 以为 NTSC 是 30 帧。它名义上 30,实际是 30000/1001 ≈ 29.97。差千分之一,累积起来很可观。
  3. 以为制式只是历史名词。摄像机的默认值、ffmpeg 的预设、DVD 的分辨率,全都是从这儿来的。
自测三问(点开对答案) 1. 为什么 PAL 地区的扫描行数是 625,NTSC 是 525? —— 跟当地交流电频率有关。50 Hz 地区用 50 场配 625 行,60 Hz 地区用 60 场配 525 行,早期设备靠电源同步。 2. 「1080i50」换算成帧是多少? —— 25 帧。i 表示隔行,50 是场频,两场凑一帧,所以是 25 帧。 3. 怎么快速判断一个帧率是不是 NTSC 体系? —— 看场频÷2 能不能整除。不能整除(比如 60÷2=30 但帧率是 29.97)就说明背后有个 1001 的因子。

相关笔记