🎬 第三章 FFmpeg三大常用工具及应用选项详解
📄 一句话概括

高级参数主要管三件事:同步、丢帧、缓冲。 默认值之所以是默认值,是因为它符合人的感知特点。

📝 本节和前面几节的关系

3.2.1 讲的是「放什么」,这一节讲「怎么放得稳」。 3.2.3 接着讲怎么把声音画成图。

一、同步:这个工具最核心的一个开关

-sync 决定「以谁的时间为准」,三种取值:

-sync 取值 以谁为准 什么场合用


audio 音频为主,视频追音频 默认,看片最自然 video 视频为主,音频追视频 看画面细节、分析动作 ext 以外部时钟为准 录屏、对齐外部设备

默认选 audio 不是技术偏好,是感知特点:人耳对声音断续比对画面卡顿敏感得多。 宁可画面丢一帧,也不要声音断一下——这是几十年来播放器设计的共识。

所以「视频分析」这类用途要手动改成 -sync video。 因为分析时画面每一帧都要看到,声音断不断无所谓——需求正好反过来。

二、丢帧与缓冲:追不上时的取舍

这三个参数都是在「处理不过来」时做选择,方向各不相同:

参数 做法 代价


-framedrop 追不上就丢视频帧 画面卡但不拖慢音频 -infbuf 不限制缓冲大小 吃内存,但网络抖动不卡 -fflags nobuffer 尽量不缓冲 起播快,但容易卡顿

后两个不能同时开:-infbuf 要缓冲,nobuffer 不要缓冲,方向正好相反。 同时写的结果是「后者覆盖前者」或者「行为不确定」,依版本而定。

选哪个看场景:直播要稳就 -infbuf,要低延迟就 nobuffer。 「又稳又低延迟」是做不到的——缓冲本质上就是拿延迟换稳定。

三、调试类:四个

这四个不改善播放,只帮你看清问题在哪:

参数 打出什么 用来查什么


-stats 帧率、码率、时钟偏差 卡不卡、同步准不准 -debug_ts 每帧的时间戳 时间戳有没有跳变 -ast / -vst 强制指定音视频流 多音轨选错的时候 -vf / -af 挂滤镜链 边放边看效果

第一行最值得学:-stats 那一行里有三个时钟——音频时钟、视频时钟、系统时钟。 音画不同步时就是这三个数在互相追,看它们差多少就知道问题在哪一侧。

判断方法很直接:音频时钟落后于视频时钟,说明音频在等;反过来就是视频在等。 等的那一侧通常就是慢的那一侧,卡顿的原因也就找到了。

四、动手 Demo:同步、丢帧、缓冲这三组

这三组参数改的都是「播放行为」,不产出任何文件。 这一段把它们归成一张表,并说明哪些能在库里验证、哪些只能在真 exe 上验。

import av

# 所有播放参数都不改数据,只改节奏
c = av.open(u"src.mp4")
st = c.streams.video[0]
print(u"源帧率 %s" % st.average_rate)
print(u"时间基 1/%d" % st.time_base.denominator)
print(u"容器时长 %.2f 秒" % (float(c.duration) / 1000000))
c.close()

# 关键帧位置决定「能跳到哪」,也就是 -framedrop 与 seek 的地基
c = av.open(u"src.mp4")
keys = [pk.pts for pk in c.demux(video=0)
        if pk.size and pk.is_keyframe]
c.close()
print(u"关键帧位置 %s" % keys[:6])

实跑输出:

--------------------------------------------------------------------
ffplay 高级参数——同步、丢帧、缓冲这三组
--------------------------------------------------------------------

**① 同步策略是这个工具最核心的一个开关**

  -sync 取值     以谁为准                 什么场合用
  ----------------------------------------------------------------
  audio          音频为主,视频追音频     默认,看片最自然
  video          视频为主,音频追视频     看画面细节、分析动作
  ext            以外部时钟为准           录屏、对齐外部设备

**默认之所以选 audio,是因为人耳对声音断续比对画面卡顿敏感得多。**
**宁可画面丢一帧,也不要声音断一下——这是人类感知的特点,不是技术偏好。**

**② 丢帧与缓冲,都是在「追不上」时的取舍**

  参数                 做法                 代价
  --------------------------------------------------------------------
  -framedrop           追不上就丢视频帧     画面变卡但不拖慢音频
  -infbuf              不限制缓冲大小       吃内存,但网络抖动不卡
  -fflags nobuffer     尽量不缓冲           起播快,但容易卡顿

**这三项不能同时开:`-infbuf` 要缓冲,`nobuffer` 不要缓冲,方向相反。**
**直播看稳定就加 `-infbuf`,看低延迟就加 `nobuffer`,二选一。**

**③ 调试类的四个**

  参数            打出什么                 用来查什么
  ---------------------------------------------------------------
  -stats          帧率、码率、时钟偏差     卡不卡、同步准不准
  -debug_ts       每帧的时间戳             时间戳有没有跳变
  -ast / -vst     强制指定音视频流         多音轨选错的时候
  -vf / -af       挂滤镜链                 边放边看效果

**`-stats` 打出那一行里有三个时钟:音频时钟、视频时钟、系统时钟。**
**音画不同步的时候,就是这三个数在互相追——看它们差多少,就知道问题在哪一侧。**

**④ 这些参数的共同点:它们改的是「播放行为」,不是「数据内容」**

  类别             改什么               会不会影响输出文件
  --------------------------------------------------------------
  同步与缓冲       播放节奏             不会,根本不产出文件
  滤镜 -vf/-af     显示的画面与声音     不会,只在内存里改
  丢帧             显示哪几帧           不会,源文件不动

**最后一行值得强调:ffplay 从头到尾是只读的。**
**所以它特别适合拿来做「这个文件到底能不能正常播」的判定——不改任何东西。**

帧率、时间基、时长这三个数,就是同步逻辑的输入。 播放器要拿它们算「这一帧该在第几毫秒显示」,算错了就卡或者跳。

关键帧位置那一行解释了「为什么跳转不准」:只能跳到关键帧, 两个关键帧之间的位置只能靠解码补——-framedrop 丢的帧也是从这些位置挑的。

注意这一段完全没有「播放」这个动作。 因为这三组参数的效果(顺不顺、卡不卡、同步准不准)只能在真窗口里看, 库这一层能做的只是把它们依赖的那几个数摆出来。

30 秒实验

  1. 看时钟:ffplay -stats 片子.mp4,盯住那一行里 audio/video/sys 三个数的差。
  2. 强制视频为主:ffplay -sync video 片子.mp4,听声音会不会偶尔断一下。
  3. 低延迟:ffplay -fflags nobuffer rtmp://…,体会「起播快但容易卡」。

常见误区

  1. 同时加 -infbuf 和 nobuffer。方向相反,同时写行为不确定。选一个。
  2. 以为音画不同步是解码慢。先看 -stats 三个时钟谁在等谁,再判断是哪一侧的问题。
  3. 在视频分析时用默认同步。默认以音频为准,会为了声音丢掉视频帧——分析场景要改成 -sync video。
自测三问(点开对答案) 1. 为什么 `-sync` 默认是 audio? —— 因为人耳对声音断续比对画面卡顿敏感得多。宁可丢视频帧,也不要声音断——这是播放器设计的共识。 2. `-infbuf` 和 `-fflags nobuffer` 能同时用吗? —— 不能。一个要缓冲、一个不要缓冲,方向相反。同时写结果是覆盖或者行为不确定。 3. `-stats` 打出三个时钟,看它们的差能判断什么? —— 判断是哪一侧在等。音频时钟落后说明音频慢,视频时钟落后说明视频慢,卡顿的原因就在那一侧。

相关笔记