高级参数主要管三件事:同步、丢帧、缓冲。 默认值之所以是默认值,是因为它符合人的感知特点。
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 秒实验
- 看时钟:
ffplay -stats 片子.mp4,盯住那一行里 audio/video/sys 三个数的差。 - 强制视频为主:
ffplay -sync video 片子.mp4,听声音会不会偶尔断一下。 - 低延迟:
ffplay -fflags nobuffer rtmp://…,体会「起播快但容易卡」。
常见误区
- 同时加
-infbuf和nobuffer。方向相反,同时写行为不确定。选一个。 - 以为音画不同步是解码慢。先看
-stats三个时钟谁在等谁,再判断是哪一侧的问题。 - 在视频分析时用默认同步。默认以音频为准,会为了声音丢掉视频帧——分析场景要改成
-sync video。
自测三问(点开对答案)
1. 为什么 `-sync` 默认是 audio? —— 因为人耳对声音断续比对画面卡顿敏感得多。宁可丢视频帧,也不要声音断——这是播放器设计的共识。 2. `-infbuf` 和 `-fflags nobuffer` 能同时用吗? —— 不能。一个要缓冲、一个不要缓冲,方向相反。同时写结果是覆盖或者行为不确定。 3. `-stats` 打出三个时钟,看它们的差能判断什么? —— 判断是哪一侧在等。音频时钟落后说明音频慢,视频时钟落后说明视频慢,卡顿的原因就在那一侧。- ☐ (本节完,下一节 3.2.3 ffplay 的数据可视化分析应用)